diff --git a/apps/labrinth/.sqlx/query-00d809d1dc9dd1eb2c49ebaac2387f82c5730d835ae1c52d5df23b5f09cd1925.json b/apps/labrinth/.sqlx/query-147f31c59219c5485531914897618427375b203777a68fd6ece1a50feaf41df9.json similarity index 59% rename from apps/labrinth/.sqlx/query-00d809d1dc9dd1eb2c49ebaac2387f82c5730d835ae1c52d5df23b5f09cd1925.json rename to apps/labrinth/.sqlx/query-147f31c59219c5485531914897618427375b203777a68fd6ece1a50feaf41df9.json index 810f9c5ebb..b7e45e18a1 100644 --- a/apps/labrinth/.sqlx/query-00d809d1dc9dd1eb2c49ebaac2387f82c5730d835ae1c52d5df23b5f09cd1925.json +++ b/apps/labrinth/.sqlx/query-147f31c59219c5485531914897618427375b203777a68fd6ece1a50feaf41df9.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT id\n FROM notifications\n WHERE body @> $1::jsonb\n ", + "query": "\n SELECT id\n FROM notifications\n WHERE body @> $1::jsonb\n AND user_id = ANY($2::bigint[])\n ", "describe": { "columns": [ { @@ -11,12 +11,13 @@ ], "parameters": { "Left": [ - "Jsonb" + "Jsonb", + "Int8Array" ] }, "nullable": [ false ] }, - "hash": "00d809d1dc9dd1eb2c49ebaac2387f82c5730d835ae1c52d5df23b5f09cd1925" + "hash": "147f31c59219c5485531914897618427375b203777a68fd6ece1a50feaf41df9" } diff --git a/apps/labrinth/src/database/models/notification_item.rs b/apps/labrinth/src/database/models/notification_item.rs index 9cc25c053c..5ad8c897b4 100644 --- a/apps/labrinth/src/database/models/notification_item.rs +++ b/apps/labrinth/src/database/models/notification_item.rs @@ -599,16 +599,21 @@ impl DBNotification { pub async fn remove_many_matching_body( body_filter: &serde_json::Value, + users: &[DBUserId], transaction: &mut PgTransaction<'_>, redis: &RedisPool, ) -> Result { + let user_ids = users.iter().map(|x| x.0).collect::>(); + let ids = sqlx::query!( " SELECT id FROM notifications WHERE body @> $1::jsonb + AND user_id = ANY($2::bigint[]) ", - body_filter + body_filter, + &user_ids ) .fetch(&mut *transaction) .map_ok(|x| DBNotificationId(x.id)) diff --git a/apps/labrinth/src/routes/internal/external_notifications.rs b/apps/labrinth/src/routes/internal/external_notifications.rs index 3c53655a4a..36fdce7781 100644 --- a/apps/labrinth/src/routes/internal/external_notifications.rs +++ b/apps/labrinth/src/routes/internal/external_notifications.rs @@ -7,7 +7,7 @@ use crate::database::models::user_item::DBUser; use crate::database::redis::RedisPool; use crate::models::users::Role; use crate::models::v3::notifications::{ - NotificationBody, NotificationDeliveryStatus, NotificationType, + NotificationBody, NotificationDeliveryStatus, }; use crate::models::v3::pats::Scopes; use crate::queue::email::EmailQueue; @@ -160,18 +160,45 @@ pub async fn create_direct_email( Ok(web::Json(failed).customize().with_status(status)) } +#[derive(Deserialize)] +struct NotificationFilter { + pub user_ids: Vec, + #[serde(flatten)] + pub body: serde_json::Map, +} + #[delete("external_notifications", guard = "external_notification_key_guard")] pub async fn remove( pool: web::Data, redis: web::Data, - notification_filter: web::Json, + notification_filter: web::Json, ) -> Result { + let NotificationFilter { user_ids, body } = + notification_filter.into_inner(); + + if user_ids.is_empty() { + return Err(ApiError::Request(eyre!( + "at least one user must be provided to remove notifications from" + ))); + } + + if body.is_empty() { + return Err(ApiError::Request(eyre!( + "at least one `body` field must be provided to match notifications" + ))); + } + + let filters = serde_json::Value::Object(body); + + let user_ids = user_ids + .into_iter() + .map(|x| DBUserId(x.0 as i64)) + .collect::>(); + let mut txn = pool.begin().await?; DBNotification::remove_many_matching_body( - ¬ification_filter, - &mut txn, - &redis, + &filters, &user_ids, &mut txn, &redis, ) .await?;