user_cleanup_identity.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. package service
  2. import (
  3. "context"
  4. "database/sql"
  5. "github.com/lib/pq"
  6. )
  7. // Preserve a private recovery snapshot before releasing canonical login bindings.
  8. // This reproduces UserRepository.deleteUser's binding cleanup while preserving all
  9. // source rows internally; regular users and admin result DTOs cannot read the archive.
  10. func cleanupArchiveIdentities(ctx context.Context, tx *sql.Tx, ids []int64, previewID string) error {
  11. for _, query := range []string{
  12. `SELECT id FROM auth_identities WHERE user_id=ANY($1) ORDER BY id FOR UPDATE`,
  13. `SELECT c.id FROM auth_identity_channels c JOIN auth_identities a ON a.id=c.identity_id WHERE a.user_id=ANY($1) ORDER BY c.id FOR UPDATE OF c`,
  14. `SELECT d.id FROM identity_adoption_decisions d JOIN auth_identities a ON a.id=d.identity_id WHERE a.user_id=ANY($1) ORDER BY d.id FOR UPDATE OF d`,
  15. } {
  16. rows, err := tx.QueryContext(ctx, query, pq.Array(ids))
  17. if err != nil {
  18. return err
  19. }
  20. for rows.Next() {
  21. var id int64
  22. if err := rows.Scan(&id); err != nil {
  23. _ = rows.Close()
  24. return err
  25. }
  26. }
  27. err = rows.Err()
  28. _ = rows.Close()
  29. if err != nil {
  30. return err
  31. }
  32. }
  33. _, err := tx.ExecContext(ctx, `
  34. INSERT INTO user_cleanup_identity_archives(preview_id,user_id,identities,channels,adoption_decisions)
  35. SELECT $2::uuid,u.id,
  36. COALESCE((SELECT jsonb_agg(to_jsonb(a) ORDER BY a.id) FROM auth_identities a WHERE a.user_id=u.id),'[]'::jsonb),
  37. COALESCE((SELECT jsonb_agg(to_jsonb(c) ORDER BY c.id) FROM auth_identity_channels c JOIN auth_identities a ON a.id=c.identity_id WHERE a.user_id=u.id),'[]'::jsonb),
  38. COALESCE((SELECT jsonb_agg(to_jsonb(d) ORDER BY d.id) FROM identity_adoption_decisions d JOIN auth_identities a ON a.id=d.identity_id WHERE a.user_id=u.id),'[]'::jsonb)
  39. FROM users u WHERE u.id=ANY($1)`, pq.Array(ids), previewID)
  40. if err != nil {
  41. return err
  42. }
  43. for _, query := range []string{
  44. `UPDATE identity_adoption_decisions SET identity_id=NULL WHERE identity_id IN (SELECT id FROM auth_identities WHERE user_id=ANY($1))`,
  45. `DELETE FROM auth_identity_channels WHERE identity_id IN (SELECT id FROM auth_identities WHERE user_id=ANY($1))`,
  46. `DELETE FROM auth_identities WHERE user_id=ANY($1)`,
  47. } {
  48. if _, err := tx.ExecContext(ctx, query, pq.Array(ids)); err != nil {
  49. return err
  50. }
  51. }
  52. return nil
  53. }