@@ -272,6 +272,68 @@ const readUserRow = async (env: Env, userId: string): Promise<UserRow | null> =>
272272 . first < UserRow > ( ) ;
273273} ;
274274
275+ const reconcileUserIdentityByEmail = async ( env : Env , userId : string , email : string ) : Promise < void > => {
276+ const normalized = sanitizeEmail ( email ) ;
277+ if ( ! normalized ) return ;
278+
279+ const existing = await env . DB
280+ . prepare (
281+ `SELECT id, username, email, bio, avatar_url, is_admin, is_approved, approved_at, approved_by_user_id, created_at, updated_at
282+ FROM users
283+ WHERE lower(email) = lower(?) AND id <> ?
284+ ORDER BY is_admin DESC, is_approved DESC, created_at ASC
285+ LIMIT 1` ,
286+ )
287+ . bind ( normalized , userId )
288+ . first < UserRow > ( ) ;
289+ if ( ! existing ) return ;
290+
291+ const now = new Date ( ) . toISOString ( ) ;
292+ await env . DB
293+ . prepare (
294+ `UPDATE users
295+ SET is_admin = CASE WHEN ? = 1 THEN 1 ELSE is_admin END,
296+ is_approved = CASE WHEN ? = 1 THEN 1 ELSE is_approved END,
297+ approved_at = CASE WHEN ? = 1 THEN COALESCE(approved_at, ?) ELSE approved_at END,
298+ approved_by_user_id = CASE WHEN ? = 1 THEN COALESCE(approved_by_user_id, ?) ELSE approved_by_user_id END,
299+ updated_at = ?
300+ WHERE id = ?` ,
301+ )
302+ . bind (
303+ existing . is_admin === 1 ? 1 : 0 ,
304+ existing . is_approved === 1 ? 1 : 0 ,
305+ existing . is_approved === 1 ? 1 : 0 ,
306+ existing . approved_at ?? now ,
307+ existing . is_approved === 1 ? 1 : 0 ,
308+ existing . approved_by_user_id ?? existing . id ,
309+ now ,
310+ userId ,
311+ )
312+ . run ( ) ;
313+
314+ await env . DB . batch ( [
315+ env . DB . prepare ( "UPDATE sites SET owner_user_id = ? WHERE owner_user_id = ?" ) . bind ( userId , existing . id ) ,
316+ env . DB
317+ . prepare (
318+ `UPDATE sites
319+ SET created_by_user_id = CASE WHEN created_by_user_id = ? THEN ? ELSE created_by_user_id END,
320+ last_edited_by_user_id = CASE WHEN last_edited_by_user_id = ? THEN ? ELSE last_edited_by_user_id END` ,
321+ )
322+ . bind ( existing . id , userId , existing . id , userId ) ,
323+ env . DB . prepare ( "UPDATE simulations SET owner_user_id = ? WHERE owner_user_id = ?" ) . bind ( userId , existing . id ) ,
324+ env . DB
325+ . prepare (
326+ `UPDATE simulations
327+ SET created_by_user_id = CASE WHEN created_by_user_id = ? THEN ? ELSE created_by_user_id END,
328+ last_edited_by_user_id = CASE WHEN last_edited_by_user_id = ? THEN ? ELSE last_edited_by_user_id END` ,
329+ )
330+ . bind ( existing . id , userId , existing . id , userId ) ,
331+ env . DB . prepare ( "UPDATE site_roles SET user_id = ? WHERE user_id = ?" ) . bind ( userId , existing . id ) ,
332+ env . DB . prepare ( "UPDATE simulation_roles SET user_id = ? WHERE user_id = ?" ) . bind ( userId , existing . id ) ,
333+ env . DB . prepare ( "UPDATE resource_changes SET actor_user_id = ? WHERE actor_user_id = ?" ) . bind ( userId , existing . id ) ,
334+ ] ) ;
335+ } ;
336+
275337export const ensureUser = async (
276338 env : Env ,
277339 userId : string ,
@@ -326,6 +388,8 @@ export const ensureUser = async (
326388 userId ,
327389 )
328390 . run ( ) ;
391+
392+ await reconcileUserIdentityByEmail ( env , userId , email ) ;
329393} ;
330394
331395export const fetchUserProfile = async ( env : Env , userId : string ) => {
0 commit comments