mirror of https://github.com/buster-so/buster.git
existing user no error on invites
This commit is contained in:
parent
ed69ae8b07
commit
05f03877b6
|
@ -30,7 +30,7 @@ pub async fn invite_user_handler(
|
||||||
|
|
||||||
// Fetch inviter details
|
// Fetch inviter details
|
||||||
let inviter = users::table
|
let inviter = users::table
|
||||||
.find(inviting_user.id)
|
.filter(users::id.eq(inviting_user.id)) // Find the specific user
|
||||||
.select(User::as_select())
|
.select(User::as_select())
|
||||||
.first::<User>(&mut conn)
|
.first::<User>(&mut conn)
|
||||||
.await
|
.await
|
||||||
|
@ -45,6 +45,7 @@ pub async fn invite_user_handler(
|
||||||
|
|
||||||
// Fetch organization details
|
// Fetch organization details
|
||||||
let organization = organizations::table
|
let organization = organizations::table
|
||||||
|
.filter(organizations::id.eq(organization_id)) // Find the specific organization
|
||||||
.first::<Organization>(&mut conn)
|
.first::<Organization>(&mut conn)
|
||||||
.await
|
.await
|
||||||
.context("Failed to find organization")?;
|
.context("Failed to find organization")?;
|
||||||
|
@ -53,6 +54,7 @@ pub async fn invite_user_handler(
|
||||||
let inviter_id = inviting_user.id;
|
let inviter_id = inviting_user.id;
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
let mut successful_emails: Vec<String> = Vec::new();
|
let mut successful_emails: Vec<String> = Vec::new();
|
||||||
|
let assigned_role = UserOrganizationRole::RestrictedQuerier; // Define role once
|
||||||
|
|
||||||
for email in emails {
|
for email in emails {
|
||||||
// Use a separate connection for each user to avoid holding one connection for the whole loop
|
// Use a separate connection for each user to avoid holding one connection for the whole loop
|
||||||
|
@ -64,21 +66,39 @@ pub async fn invite_user_handler(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 1. Generate ID and construct attributes first
|
let email_for_lookup = email.clone(); // Clone email for lookup/use
|
||||||
|
let existing_user_result = users::table
|
||||||
|
.filter(users::email.eq(&email_for_lookup))
|
||||||
|
.select(User::as_select())
|
||||||
|
.first::<User>(&mut user_conn)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let user_id: Uuid;
|
||||||
|
let user_email_for_attributes: String;
|
||||||
|
|
||||||
|
match existing_user_result {
|
||||||
|
Ok(user) => {
|
||||||
|
// User exists, use their ID
|
||||||
|
user_id = user.id;
|
||||||
|
user_email_for_attributes = user.email; // Use existing user's email
|
||||||
|
tracing::info!(email = %user_email_for_attributes, user_id = %user_id, "User already exists, using existing ID for organization association.");
|
||||||
|
}
|
||||||
|
Err(diesel::NotFound) => {
|
||||||
|
// User does not exist, create them
|
||||||
let new_user_id = Uuid::new_v4();
|
let new_user_id = Uuid::new_v4();
|
||||||
let user_email = email.clone();
|
user_email_for_attributes = email.clone(); // Use the email from the loop input
|
||||||
let assigned_role = UserOrganizationRole::RestrictedQuerier;
|
|
||||||
|
// Attributes for the new user
|
||||||
let user_attributes = json!({
|
let user_attributes = json!({
|
||||||
"user_id": new_user_id.to_string(),
|
"user_id": new_user_id.to_string(),
|
||||||
"user_email": user_email,
|
"user_email": user_email_for_attributes,
|
||||||
"organization_id": organization_id.to_string(),
|
"organization_id": organization_id.to_string(),
|
||||||
"organization_role": format!("{:?}", assigned_role)
|
"organization_role": format!("{:?}", assigned_role) // Use pre-defined role
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. Create User struct instance
|
|
||||||
let user_to_insert = User {
|
let user_to_insert = User {
|
||||||
id: new_user_id,
|
id: new_user_id,
|
||||||
email: email.clone(),
|
email: email.clone(), // Use email from loop input
|
||||||
name: None,
|
name: None,
|
||||||
config: json!({}),
|
config: json!({}),
|
||||||
created_at: now,
|
created_at: now,
|
||||||
|
@ -87,22 +107,37 @@ pub async fn invite_user_handler(
|
||||||
avatar_url: None,
|
avatar_url: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 3. Insert user
|
// Insert the new user
|
||||||
let user_insert_result = diesel::insert_into(users::table)
|
match diesel::insert_into(users::table)
|
||||||
.values(&user_to_insert)
|
.values(&user_to_insert)
|
||||||
.execute(&mut user_conn)
|
.execute(&mut user_conn)
|
||||||
.await;
|
.await
|
||||||
|
{
|
||||||
if let Err(e) = user_insert_result {
|
Ok(_) => {
|
||||||
tracing::error!(error = %e, email = %email, "Failed to insert user record");
|
user_id = new_user_id; // Assign the new ID
|
||||||
continue; // Skip this user if insertion fails
|
tracing::info!(email = %email, user_id = %user_id, "Successfully inserted new user.");
|
||||||
}
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// Handle unexpected insertion errors (e.g., DB connection issue mid-operation)
|
||||||
|
tracing::error!(error = %e, email = %email, "Failed to insert non-existent user record");
|
||||||
|
continue; // Skip this user if insertion fails unexpectedly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// Other database error during lookup
|
||||||
|
tracing::error!(error = %e, email = %email, "Failed to query for existing user");
|
||||||
|
continue; // Skip this user
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// At this point, user_id is set (either existing or newly created)
|
||||||
|
// Attempt to add the user to the organization, ignoring conflicts
|
||||||
|
|
||||||
// 4. Create UserToOrganization struct instance
|
|
||||||
let user_org_to_insert = UserToOrganization {
|
let user_org_to_insert = UserToOrganization {
|
||||||
user_id: new_user_id,
|
user_id, // Use the determined user_id
|
||||||
organization_id,
|
organization_id,
|
||||||
role: assigned_role,
|
role: assigned_role, // Use pre-defined role
|
||||||
sharing_setting: SharingSetting::None,
|
sharing_setting: SharingSetting::None,
|
||||||
edit_sql: false,
|
edit_sql: false,
|
||||||
upload_csv: false,
|
upload_csv: false,
|
||||||
|
@ -117,21 +152,32 @@ pub async fn invite_user_handler(
|
||||||
status: UserOrganizationStatus::Active,
|
status: UserOrganizationStatus::Active,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 5. Insert user organization mapping
|
// Insert user organization mapping with ON CONFLICT DO NOTHING
|
||||||
let user_org_insert_result = diesel::insert_into(users_to_organizations::table)
|
let user_org_insert_result = diesel::insert_into(users_to_organizations::table)
|
||||||
.values(&user_org_to_insert)
|
.values(&user_org_to_insert)
|
||||||
|
.on_conflict((
|
||||||
|
users_to_organizations::user_id,
|
||||||
|
users_to_organizations::organization_id,
|
||||||
|
))
|
||||||
|
.do_nothing() // If user is already in the org, do nothing
|
||||||
.execute(&mut user_conn)
|
.execute(&mut user_conn)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
match user_org_insert_result {
|
match user_org_insert_result {
|
||||||
Ok(_) => {
|
Ok(rows_affected) => {
|
||||||
// Only add email if both inserts were successful
|
// User was either newly inserted or already existed in the org.
|
||||||
successful_emails.push(email.clone());
|
// The association is now confirmed.
|
||||||
|
if rows_affected > 0 {
|
||||||
|
tracing::info!(email = %email, user_id = %user_id, organization_id = %organization_id, "Successfully associated user with organization.");
|
||||||
|
} else {
|
||||||
|
tracing::info!(email = %email, user_id = %user_id, organization_id = %organization_id, "User association with organization already existed.");
|
||||||
|
}
|
||||||
|
successful_emails.push(email); // Use the original email from the loop input
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!(error = %e, email = %email, user_id = %new_user_id, "Failed to insert user_to_organization record");
|
// Handle unexpected insertion errors for the join table
|
||||||
// Consider rolling back the user insert here if desired, although it's complex without a transaction per user.
|
tracing::error!(error = %e, email = %email, user_id = %user_id, "Failed unexpectedly while inserting or ignoring user_to_organization record");
|
||||||
// For now, we just log and don't add the email to the success list.
|
// Don't add to successful_emails if the DB operation failed unexpectedly
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue