Skip to content

Commit c3493c3

Browse files
committed
refactor: Simplify link_user_ids
1 parent f1b7ca6 commit c3493c3

File tree

1 file changed

+74
-78
lines changed

1 file changed

+74
-78
lines changed

src/lib.rs

Lines changed: 74 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{
44
sync::atomic::{AtomicUsize, Ordering},
55
};
66

7-
use anyhow_ext::{Context, Result};
7+
use anyhow_ext::{Context, Result, bail};
88
use futures::{StreamExt, TryStreamExt};
99
use user::User;
1010
use zitadel::{SkipableZitadelResult, Zitadel};
@@ -278,88 +278,84 @@ pub async fn link_user_ids(config: Config, skipped_errors: &SkippedErrors) -> Re
278278
let mut seen_emails: HashSet<String> = HashSet::new();
279279

280280
while let Some(user) = zitadel_users.next().await.transpose().context("failed to query user")? {
281-
let Some(zitadel_id) = user.user_id() else {
282-
tracing::error!(
283-
"Skipping user without a Zitadel ID. Users like this should never appear, this Zitadel instance is very broken."
284-
);
285-
continue;
286-
};
287-
288-
let Some(human_user) = user.human() else {
289-
tracing::error!("Skipping ID linking for non-human user `{zitadel_id}`");
290-
continue;
291-
};
292-
293-
let Some(email) = human_user.email().and_then(|e| e.email()) else {
294-
tracing::error!("Skipping ID linking for user `{zitadel_id}` without an email address");
295-
continue;
296-
};
297-
298-
if !seen_emails.insert(email.to_owned()) {
299-
// Zitadel doesn't actually allow this case, but it's here
300-
// just in case
301-
tracing::error!("Multiple users with the same email address exist");
302-
tracing::error!("Refusing to duplicate ID of user `{zitadel_id}`");
303-
tracing::error!("Manual conversion of some users will be required");
304-
continue;
305-
};
306-
307-
let Some(given_name) = human_user.profile().and_then(|p| p.given_name()) else {
308-
tracing::error!(
281+
let _ = link_user_id(&zitadel_client, &ldap_users, &mut seen_emails, &user)
282+
.await
283+
.inspect_err(|e| tracing::error!("Error fixing user {:?}: {e:?}", user.user_id()));
284+
}
285+
286+
Ok(())
287+
}
288+
289+
/// Set LDAP ID in Zitadel
290+
async fn link_user_id(
291+
zitadel_client: &Zitadel<'_>,
292+
ldap_users: &HashMap<String, User>,
293+
seen_emails: &mut HashSet<String>,
294+
user: &zitadel_rust_client::v2::users::User,
295+
) -> Result<()> {
296+
let zitadel_id = user.user_id().context(
297+
"Skipping user without a Zitadel ID. Users like this should never appear, this Zitadel instance is very broken."
298+
)?;
299+
300+
let human_user = user
301+
.human()
302+
.with_context(|| format!("Skipping ID linking for non-human user `{zitadel_id}`"))?;
303+
304+
let email = human_user.email().and_then(|e| e.email()).with_context(|| {
305+
format!("Skipping ID linking for user `{zitadel_id}` without an email address")
306+
})?;
307+
308+
if !seen_emails.insert(email.to_owned()) {
309+
// Zitadel doesn't actually allow this case, but it's here
310+
// just in case
311+
bail!(
312+
"Multiple users with the same email address exist\nRefusing to duplicate ID of user `{zitadel_id}`\nManual conversion of some users will be required"
313+
);
314+
};
315+
316+
let given_name = human_user.profile().and_then(|p| p.given_name()).with_context(||
317+
format!(
309318
"Skipping work for a user without a given name, because they are immune to Zitadel's API. Give user `{zitadel_id}` a name!"
310-
);
311-
continue;
312-
};
313-
let Some(last_name) = human_user.profile().and_then(|p| p.family_name()) else {
314-
tracing::error!(
319+
)
320+
)?;
321+
let last_name = human_user.profile().and_then(|p| p.family_name()).with_context(||
322+
format!(
315323
"Skipping work for a user without a last name, because they are immune to Zitadel's API. Give user `{zitadel_id}` a name!"
324+
)
325+
)?;
326+
let nick = human_user.profile().and_then(|p| p.nick_name());
327+
let ldap_id = ldap_users
328+
.get(email)
329+
.map(|lu| lu.external_user_id.clone())
330+
.with_context(|| format!("User `{zitadel_id}` does not have a corresponding LDAP user"))?;
331+
332+
match nick {
333+
Some(nick) if nick.is_empty() => {
334+
let mut request = UpdateHumanUserRequest::new();
335+
request.set_profile(
336+
SetHumanProfile::new(given_name.clone(), last_name.clone()).with_nick_name(ldap_id),
316337
);
317-
continue;
318-
};
319-
let nick = human_user.profile().and_then(|p| p.nick_name());
320-
let Some(ldap_id) = ldap_users.get(email).map(|lu| lu.external_user_id.clone()) else {
321-
tracing::error!("User `{zitadel_id}` does not have a corresponding LDAP user");
322-
continue;
323-
};
324-
325-
match nick {
326-
Some(nick) if nick.is_empty() => {
327-
let mut request = UpdateHumanUserRequest::new();
328-
request.set_profile(
329-
SetHumanProfile::new(given_name.clone(), last_name.clone())
330-
.with_nick_name(ldap_id),
331-
);
332-
333-
if let Err(error) =
334-
zitadel_client.zitadel_client.update_human_user(zitadel_id, request).await
335-
{
336-
tracing::error!(
337-
"Failed to set nickname field for user `{zitadel_id}: {:?}",
338-
error
339-
);
340-
continue;
341-
};
342-
343-
tracing::info!("Updated LDAP link for user `{zitadel_id}`");
344-
}
345-
Some(nick) if *nick != ldap_id => {
346-
tracing::error!(
347-
"External ID for user `{zitadel_id}` does not match the external ID for the LDAP user with their email address, {nick} {ldap_id}"
348-
);
349-
tracing::error!(
350-
"Something has gone very wrong for this user, please correct their data manually"
351-
);
352-
continue;
353-
}
354-
Some(nick) => {
355-
tracing::info!("User `{zitadel_id}` is already linked to user `{nick}`");
356-
}
357-
None => {
358-
unreachable!()
359-
}
338+
339+
zitadel_client
340+
.zitadel_client
341+
.update_human_user(zitadel_id, request)
342+
.await
343+
.with_context(|| format!("Failed to set nickname field for user `{zitadel_id}",))?;
344+
345+
tracing::info!("Updated LDAP link for user `{zitadel_id}`");
346+
}
347+
Some(nick) if *nick != ldap_id => {
348+
bail!(
349+
"External ID for user `{zitadel_id}` does not match the external ID for the LDAP user with their email address, {nick} {ldap_id}\nSomething has gone very wrong for this user, please correct their data manually"
350+
);
351+
}
352+
Some(nick) => {
353+
tracing::info!("User `{zitadel_id}` is already linked to user `{nick}`");
354+
}
355+
None => {
356+
unreachable!()
360357
}
361358
}
362-
363359
Ok(())
364360
}
365361

0 commit comments

Comments
 (0)