feat: revoke notification endpoint

This commit is contained in:
sychic
2026-06-02 17:09:50 +01:00
committed by Calum H. (IMB11)
parent cd7dced0a6
commit f12ea058de
3 changed files with 73 additions and 2 deletions
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id\n FROM notifications\n WHERE body @> $1::jsonb\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Jsonb"
]
},
"nullable": [
false
]
},
"hash": "00d809d1dc9dd1eb2c49ebaac2387f82c5730d835ae1c52d5df23b5f09cd1925"
}
@@ -597,6 +597,33 @@ impl DBNotification {
Ok(Some(()))
}
pub async fn remove_many_matching_body(
body_filter: &serde_json::Value,
transaction: &mut PgTransaction<'_>,
redis: &RedisPool,
) -> Result<usize, DatabaseError> {
let ids = sqlx::query!(
"
SELECT id
FROM notifications
WHERE body @> $1::jsonb
",
body_filter
)
.fetch(&mut *transaction)
.map_ok(|x| DBNotificationId(x.id))
.try_collect::<Vec<_>>()
.await?;
if ids.is_empty() {
return Ok(0);
}
Self::remove_many(&ids, transaction, redis).await?;
Ok(ids.len())
}
pub async fn clear_user_notifications_cache(
user_ids: impl IntoIterator<Item = &DBUserId>,
redis: &RedisPool,
@@ -1,12 +1,13 @@
use crate::auth::get_user_from_headers;
use crate::database::PgPool;
use crate::database::models::ids::DBUserId;
use crate::database::models::notification_item::DBNotification;
use crate::database::models::notification_item::NotificationBuilder;
use crate::database::models::user_item::DBUser;
use crate::database::redis::RedisPool;
use crate::models::users::Role;
use crate::models::v3::notifications::{
NotificationBody, NotificationDeliveryStatus,
NotificationBody, NotificationDeliveryStatus, NotificationType,
};
use crate::models::v3::pats::Scopes;
use crate::queue::email::EmailQueue;
@@ -16,7 +17,7 @@ use crate::util::guards::external_notification_key_guard;
use actix_web::http::StatusCode;
use actix_web::web;
use actix_web::{
CustomizeResponder, HttpRequest, HttpResponse, Responder, post,
CustomizeResponder, HttpRequest, HttpResponse, Responder, delete, post,
};
use ariadne::ids::UserId;
use eyre::eyre;
@@ -26,6 +27,7 @@ use serde::Deserialize;
pub fn config(cfg: &mut web::ServiceConfig) {
cfg.service(create)
.service(create_direct_email)
.service(remove)
.service(send_custom_email);
}
@@ -158,6 +160,26 @@ pub async fn create_direct_email(
Ok(web::Json(failed).customize().with_status(status))
}
#[delete("external_notifications", guard = "external_notification_key_guard")]
pub async fn remove(
pool: web::Data<PgPool>,
redis: web::Data<RedisPool>,
notification_filter: web::Json<serde_json::Value>,
) -> Result<HttpResponse, ApiError> {
let mut txn = pool.begin().await?;
DBNotification::remove_many_matching_body(
&notification_filter,
&mut txn,
&redis,
)
.await?;
txn.commit().await?;
Ok(HttpResponse::NoContent().finish())
}
#[derive(Deserialize)]
struct SendEmail {
pub users: Vec<UserId>,