From 0e4631ec75fb56f45967b2a767a06b0e381f581a Mon Sep 17 00:00:00 2001 From: ZhenYi <434836402@qq.com> Date: Mon, 20 Apr 2026 15:45:26 +0800 Subject: [PATCH] chore(api/user): update user notification endpoint --- libs/api/user/mod.rs | 8 ++++++ libs/api/user/notification.rs | 51 ++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/libs/api/user/mod.rs b/libs/api/user/mod.rs index 86d1f92..a201403 100644 --- a/libs/api/user/mod.rs +++ b/libs/api/user/mod.rs @@ -55,6 +55,14 @@ pub fn init_user_routes(cfg: &mut web::ServiceConfig) { "/me/notifications/preferences", web::patch().to(notification::update_notification_preferences), ) + .route( + "/me/notifications/push/vapid-key", + web::get().to(notification::get_vapid_public_key), + ) + .route( + "/me/notifications/push/subscription", + web::delete().to(notification::unsubscribe_push), + ) .route( "/me/heatmap", web::get().to(chpc::get_my_contribution_heatmap), diff --git a/libs/api/user/notification.rs b/libs/api/user/notification.rs index 5bbf7eb..0f0305a 100644 --- a/libs/api/user/notification.rs +++ b/libs/api/user/notification.rs @@ -1,8 +1,57 @@ -use crate::{ApiResponse, error::ApiError}; use actix_web::{HttpResponse, Result, web}; +use service::error::AppError; use service::AppService; use session::Session; +use crate::{error::ApiError, ApiResponse}; + +#[derive(serde::Serialize, utoipa::ToSchema)] +pub struct VapidKeyResponse { + pub public_key: String, +} + +#[utoipa::path( + get, + path = "/api/users/me/notifications/push/vapid-key", + responses( + (status = 200, description = "Get VAPID public key for push subscription", body = ApiResponse), + (status = 503, description = "Push notifications not configured"), + ), + tag = "User" +)] +pub async fn get_vapid_public_key( + service: web::Data, +) -> Result { + let public_key = service + .config + .vapid_public_key(); + let public_key = match public_key { + Some(k) => k, + None => { + let err: AppError = AppError::InternalError; + return Err(err.into()); + } + }; + Ok(ApiResponse::ok(VapidKeyResponse { public_key }).to_response()) +} + +#[utoipa::path( + delete, + path = "/api/users/me/notifications/push/subscription", + responses( + (status = 200, description = "Unsubscribe from push notifications", body = ApiResponse), + (status = 401, description = "Unauthorized"), + ), + tag = "User" +)] +pub async fn unsubscribe_push( + service: web::Data, + session: Session, +) -> Result { + service.user_unsubscribe_push(&session).await?; + Ok(ApiResponse::ok(serde_json::json!({ "success": true })).to_response()) +} + #[utoipa::path( get, path = "/api/users/me/notifications/preferences",