diff --git a/crates/storage-pg/.sqlx/query-f0b4af5a9d6f1cc707a935fd5f34526a54ebbed8eef8f885f3a6723bc8490908.json b/crates/storage-pg/.sqlx/query-f0b4af5a9d6f1cc707a935fd5f34526a54ebbed8eef8f885f3a6723bc8490908.json new file mode 100644 index 000000000..1622b4062 --- /dev/null +++ b/crates/storage-pg/.sqlx/query-f0b4af5a9d6f1cc707a935fd5f34526a54ebbed8eef8f885f3a6723bc8490908.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM user_unsupported_third_party_ids\n WHERE user_id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "f0b4af5a9d6f1cc707a935fd5f34526a54ebbed8eef8f885f3a6723bc8490908" +} diff --git a/crates/storage-pg/src/user/mod.rs b/crates/storage-pg/src/user/mod.rs index bbf02567e..f63fce2c5 100644 --- a/crates/storage-pg/src/user/mod.rs +++ b/crates/storage-pg/src/user/mod.rs @@ -1,3 +1,4 @@ +// Copyright 2025, 2026 Element Creations Ltd. // Copyright 2024, 2025 New Vector Ltd. // Copyright 2021-2024 The Matrix.org Foundation C.I.C. // @@ -434,6 +435,30 @@ impl UserRepository for PgUserRepository<'_> { Ok(user) } + #[tracing::instrument( + name = "db.user.delete_unsupported_threepids", + skip_all, + fields( + db.query.text, + %user.id, + ), + err, + )] + async fn delete_unsupported_threepids(&mut self, user: &User) -> Result { + let res = sqlx::query!( + r#" + DELETE FROM user_unsupported_third_party_ids + WHERE user_id = $1 + "#, + Uuid::from(user.id), + ) + .traced() + .execute(&mut *self.conn) + .await?; + + Ok(res.rows_affected().try_into().unwrap_or(usize::MAX)) + } + #[tracing::instrument( name = "db.user.set_can_request_admin", skip_all, diff --git a/crates/storage/src/user/mod.rs b/crates/storage/src/user/mod.rs index 657909ef4..bfc0eaae1 100644 --- a/crates/storage/src/user/mod.rs +++ b/crates/storage/src/user/mod.rs @@ -1,3 +1,4 @@ +// Copyright 2025, 2026 Element Creations Ltd. // Copyright 2024, 2025 New Vector Ltd. // Copyright 2021-2024 The Matrix.org Foundation C.I.C. // @@ -295,6 +296,24 @@ pub trait UserRepository: Send + Sync { /// Returns [`Self::Error`] if the underlying repository fails async fn reactivate(&mut self, user: User) -> Result; + /// Delete all the unsupported third-party IDs of a [`User`]. + /// + /// Those were imported by syn2mas and kept in case we wanted to support + /// them later. They still need to be cleaned up when a user deactivate + /// their account. + /// + /// Returns the number of deleted third-party IDs. + /// + /// # Parameters + /// + /// * `user`: The [`User`] whose unsupported third-party IDs should be + /// deleted + /// + /// # Errors + /// + /// Returns [`Self::Error`] if the underlying repository fails + async fn delete_unsupported_threepids(&mut self, user: &User) -> Result; + /// Set whether a [`User`] can request admin /// /// Returns the [`User`] with the new `can_request_admin` value @@ -367,6 +386,7 @@ repository_impl!(UserRepository: async fn unlock(&mut self, user: User) -> Result; async fn deactivate(&mut self, clock: &dyn Clock, user: User) -> Result; async fn reactivate(&mut self, user: User) -> Result; + async fn delete_unsupported_threepids(&mut self, user: &User) -> Result; async fn set_can_request_admin( &mut self, user: User, diff --git a/crates/tasks/src/user.rs b/crates/tasks/src/user.rs index e605670cc..73ea444a3 100644 --- a/crates/tasks/src/user.rs +++ b/crates/tasks/src/user.rs @@ -119,6 +119,17 @@ impl RunnableJob for DeactivateUserJob { .map_err(JobError::retry)?; info!(affected = n, "Removed all email addresses for user"); + // Delete all unsupported third-party IDs for the user + let n = repo + .user() + .delete_unsupported_threepids(&user) + .await + .map_err(JobError::retry)?; + info!( + affected = n, + "Removed all unsupported third-party IDs for user" + ); + // Before calling back to the homeserver, commit the changes to the database, as // we want the user to be locked out as soon as possible repo.save().await.map_err(JobError::retry)?;