From 60e9ab8f9381b7c2bc1f82b2f84ba346c537b386 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Tue, 8 Jul 2025 10:08:17 -0400 Subject: [PATCH] Delete access tokens on user delete (#34036) Trying to delete a user record from our admin panel throws the following error: `update or delete on table "users" violates foreign key constraint "access_tokens_user_id_fkey" on table "access_tokens" Detail: Key (id)=(....) is still referenced from table "access_tokens".` We need to add a cascade delete to the `access_tokens` table. Release Notes: - N/A --- .../20221109000000_test_schema.sql | 2 +- ...d_access_tokens_cascade_delete_on_user.sql | 3 ++ crates/collab/src/db/tests/user_tests.rs | 50 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 crates/collab/migrations/20250707182700_add_access_tokens_cascade_delete_on_user.sql diff --git a/crates/collab/migrations.sqlite/20221109000000_test_schema.sql b/crates/collab/migrations.sqlite/20221109000000_test_schema.sql index 91cf4d7af0..ca840493ad 100644 --- a/crates/collab/migrations.sqlite/20221109000000_test_schema.sql +++ b/crates/collab/migrations.sqlite/20221109000000_test_schema.sql @@ -26,7 +26,7 @@ CREATE UNIQUE INDEX "index_users_on_github_user_id" ON "users" ("github_user_id" CREATE TABLE "access_tokens" ( "id" INTEGER PRIMARY KEY AUTOINCREMENT, - "user_id" INTEGER REFERENCES users (id), + "user_id" INTEGER REFERENCES users (id) ON DELETE CASCADE, "impersonated_user_id" INTEGER REFERENCES users (id), "hash" VARCHAR(128) ); diff --git a/crates/collab/migrations/20250707182700_add_access_tokens_cascade_delete_on_user.sql b/crates/collab/migrations/20250707182700_add_access_tokens_cascade_delete_on_user.sql new file mode 100644 index 0000000000..ae0ffe24f6 --- /dev/null +++ b/crates/collab/migrations/20250707182700_add_access_tokens_cascade_delete_on_user.sql @@ -0,0 +1,3 @@ +ALTER TABLE access_tokens DROP CONSTRAINT access_tokens_user_id_fkey; +ALTER TABLE access_tokens ADD CONSTRAINT access_tokens_user_id_fkey + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; diff --git a/crates/collab/src/db/tests/user_tests.rs b/crates/collab/src/db/tests/user_tests.rs index bb2dac1f77..dd61da55ca 100644 --- a/crates/collab/src/db/tests/user_tests.rs +++ b/crates/collab/src/db/tests/user_tests.rs @@ -44,3 +44,53 @@ async fn test_accepted_tos(db: &Arc) { let user = db.get_user_by_id(user_id).await.unwrap().unwrap(); assert!(user.accepted_tos_at.is_none()); } + +test_both_dbs!( + test_destroy_user_cascade_deletes_access_tokens, + test_destroy_user_cascade_deletes_access_tokens_postgres, + test_destroy_user_cascade_deletes_access_tokens_sqlite +); + +async fn test_destroy_user_cascade_deletes_access_tokens(db: &Arc) { + let user_id = db + .create_user( + "user1@example.com", + Some("user1"), + false, + NewUserParams { + github_login: "user1".to_string(), + github_user_id: 12345, + }, + ) + .await + .unwrap() + .user_id; + + let user = db.get_user_by_id(user_id).await.unwrap(); + assert!(user.is_some()); + + let token_1_id = db + .create_access_token(user_id, None, "token-1", 10) + .await + .unwrap(); + + let token_2_id = db + .create_access_token(user_id, None, "token-2", 10) + .await + .unwrap(); + + let token_1 = db.get_access_token(token_1_id).await; + let token_2 = db.get_access_token(token_2_id).await; + assert!(token_1.is_ok()); + assert!(token_2.is_ok()); + + db.destroy_user(user_id).await.unwrap(); + + let user = db.get_user_by_id(user_id).await.unwrap(); + assert!(user.is_none()); + + let token_1 = db.get_access_token(token_1_id).await; + let token_2 = db.get_access_token(token_2_id).await; + assert!(token_1.is_err()); + assert!(token_2.is_err()); +}