From a6912af8128dc92d1be19abb234ef96590032477 Mon Sep 17 00:00:00 2001 From: Antti Leinonen Date: Fri, 10 Jul 2026 09:54:33 +0300 Subject: [PATCH 1/2] Fix signup duplicate upstream id --- .../server/src/controllers/auth.rs | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/services/headless-lms/server/src/controllers/auth.rs b/services/headless-lms/server/src/controllers/auth.rs index 4f01f2a1e023..70456306626e 100644 --- a/services/headless-lms/server/src/controllers/auth.rs +++ b/services/headless-lms/server/src/controllers/auth.rs @@ -218,21 +218,37 @@ pub async fn signup( .await; let user = match user { Ok(user) => user, - Err(error) => match error.error_type() { - ModelErrorType::DatabaseConstraint { constraint, .. } - if constraint == "users_email" => - { - let token = skip_authorize(); - return token.authorized_ok(web::Json(SignupResponse::EmailAlreadyExists)); - } - _ => { - return Err(controller_err!( - InternalServerError, - "Failed to insert user.".to_string(), - anyhow!(error) - )); - } - }, + Err(error) + if matches!( + error.error_type(), + ModelErrorType::DatabaseConstraint { constraint, .. } + if constraint == "users_email" + ) => + { + let token = skip_authorize(); + return token.authorized_ok(web::Json(SignupResponse::EmailAlreadyExists)); + } + // TMC synchronously posts the new user back to /api/v0/tmc-server/users/create + // while post_new_user_to_tmc is still in flight, so that callback has usually + // already created the user; continue with the existing row. + Err(error) + if matches!( + error.error_type(), + ModelErrorType::DatabaseConstraint { constraint, .. } + if constraint == "users_upstream_id_active_uniq_idx" + ) => + { + models::users::find_by_upstream_id(&mut conn, upstream_id) + .await? + .ok_or(error)? + } + Err(error) => { + return Err(controller_err!( + InternalServerError, + "Failed to insert user.".to_string(), + anyhow!(error) + )); + } }; let country = user_details.country.clone(); From eba5b3b4d291767d487bfe0745c8b09e70b8e176 Mon Sep 17 00:00:00 2001 From: Antti Leinonen Date: Fri, 10 Jul 2026 10:45:38 +0300 Subject: [PATCH 2/2] Ignore soft-deleted users wehen looking up by upstream id --- ...ba7a681e55b02ca8db9f4f52c921431259b90dd9bd3c79a6aa76.json} | 4 ++-- services/headless-lms/models/src/users.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename services/headless-lms/models/.sqlx/{query-375b467ba026680d07ba6fa844de91afd942e86b2715431e41b6788df0d2b3c0.json => query-3ad1dd4e432eba7a681e55b02ca8db9f4f52c921431259b90dd9bd3c79a6aa76.json} (91%) diff --git a/services/headless-lms/models/.sqlx/query-375b467ba026680d07ba6fa844de91afd942e86b2715431e41b6788df0d2b3c0.json b/services/headless-lms/models/.sqlx/query-3ad1dd4e432eba7a681e55b02ca8db9f4f52c921431259b90dd9bd3c79a6aa76.json similarity index 91% rename from services/headless-lms/models/.sqlx/query-375b467ba026680d07ba6fa844de91afd942e86b2715431e41b6788df0d2b3c0.json rename to services/headless-lms/models/.sqlx/query-3ad1dd4e432eba7a681e55b02ca8db9f4f52c921431259b90dd9bd3c79a6aa76.json index 5b8c573eaeae..835f2088c1f7 100644 --- a/services/headless-lms/models/.sqlx/query-375b467ba026680d07ba6fa844de91afd942e86b2715431e41b6788df0d2b3c0.json +++ b/services/headless-lms/models/.sqlx/query-3ad1dd4e432eba7a681e55b02ca8db9f4f52c921431259b90dd9bd3c79a6aa76.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT * FROM users WHERE upstream_id = $1", + "query": "SELECT * FROM users WHERE upstream_id = $1 AND deleted_at IS NULL", "describe": { "columns": [ { @@ -84,5 +84,5 @@ true ] }, - "hash": "375b467ba026680d07ba6fa844de91afd942e86b2715431e41b6788df0d2b3c0" + "hash": "3ad1dd4e432eba7a681e55b02ca8db9f4f52c921431259b90dd9bd3c79a6aa76" } diff --git a/services/headless-lms/models/src/users.rs b/services/headless-lms/models/src/users.rs index ba8f8a262199..802b7265f9c5 100644 --- a/services/headless-lms/models/src/users.rs +++ b/services/headless-lms/models/src/users.rs @@ -128,7 +128,7 @@ pub async fn find_by_upstream_id( ) -> ModelResult> { let user = sqlx::query_as!( User, - "SELECT * FROM users WHERE upstream_id = $1", + "SELECT * FROM users WHERE upstream_id = $1 AND deleted_at IS NULL", upstream_id ) .fetch_optional(conn) @@ -209,7 +209,7 @@ pub async fn update_email_for_user( let user = sqlx::query_as!( User, - "SELECT * FROM users WHERE upstream_id = $1", + "SELECT * FROM users WHERE upstream_id = $1 AND deleted_at IS NULL", upstream_id ) .fetch_one(&mut *tx)