Skip to main content

hvz/endpoints/
notifications.rs

1use actix_web::{HttpRequest, HttpResponse, Responder, delete, post, web};
2use serde::{Deserialize, Serialize};
3
4use crate::{
5    notifications::{Notification, PlayerGroups, PushSubscription},
6    player::Player,
7    token::Token,
8};
9
10/// Struct representing a push subscription request
11#[derive(Debug, Serialize, Deserialize)]
12pub struct PushSubscriptionRequest {
13    endpoint: String,
14    p256dh: String,
15    auth: String,
16}
17
18/// Struct representing a push notification request
19#[derive(Debug, Serialize, Deserialize)]
20pub struct PushNotificationRequest {
21    title: String,
22    content: String,
23    player_groups: PlayerGroups,
24}
25
26/// **POST /notifications/subscribe/{url_id}** - Subscribe to notifications
27#[post("/notifications/subscribe/{url_id}")]
28pub async fn subscribe(
29    url_id: web::Path<String>,
30    req: HttpRequest,
31    form: web::Json<PushSubscriptionRequest>,
32) -> impl Responder {
33    if let Err(e) = Token::check_token(&req, &url_id).await {
34        return HttpResponse::Forbidden().body(e);
35    }
36
37    let player = match Player::get_player(url_id.into_inner()).await {
38        Ok(Some(player)) => player,
39        Ok(None) => return HttpResponse::NotFound().body("Player not found"),
40        Err(err) => return HttpResponse::Forbidden().body(err),
41    };
42
43    let subscription = PushSubscription::new(
44        player.id.clone(),
45        form.endpoint.clone(),
46        form.p256dh.clone(),
47        form.auth.clone(),
48    )
49    .await;
50
51    match subscription.save().await {
52        Ok(sub) => HttpResponse::Ok().json(sub),
53        Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
54    }
55}
56
57/// **DELETE /subscriptions/unsubscribe/{url_id}** - Unsubscribe a player from push notifications
58#[delete("/subscriptions/unsubscribe/{url_id}")]
59pub async fn unsubscribe(url_id: web::Path<String>, req: HttpRequest) -> impl Responder {
60    if let Err(e) = Token::check_token(&req, &url_id).await {
61        return HttpResponse::Forbidden().body(e);
62    }
63
64    let player = match Player::get_player(url_id.into_inner()).await {
65        Ok(Some(player)) => player,
66        Ok(None) => return HttpResponse::NotFound().body("Player not found"),
67        Err(err) => return HttpResponse::InternalServerError().body(err.to_string()),
68    };
69
70    match PushSubscription::unsubscribe(player.id).await {
71        Ok(_) => HttpResponse::NoContent().finish(),
72        Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
73    }
74}
75
76/// **POST /notifications/send/{url_id}** - Send notifications to a subscription
77#[post("/notifications/send/{url_id}")]
78pub async fn send_notification(
79    url_id: web::Path<String>,
80    req: HttpRequest,
81    form: web::Json<PushNotificationRequest>,
82) -> impl Responder {
83    if let Err(e) = Token::check_token(&req, &url_id).await {
84        return HttpResponse::Forbidden().body(e);
85    }
86
87    let player = match Player::get_player(url_id.into_inner()).await {
88        Ok(Some(player)) => {
89            if let Err(err) = player.ensure_admin().await {
90                return HttpResponse::Unauthorized().body(err);
91            };
92            player
93        }
94        Ok(None) => return HttpResponse::NotFound().body("Player not found"),
95        Err(err) => return HttpResponse::Forbidden().body(err),
96    };
97
98    let notification = Notification::new(
99        player.id,
100        form.title.clone(),
101        form.content.clone(),
102        PlayerGroups::All,
103    )
104    .await;
105
106    match notification.save().await {
107        Ok(_) => {}
108        Err(err) => return HttpResponse::InternalServerError().body(err.to_string()),
109    }
110
111    match notification.send_push_notification().await {
112        Ok(response) => HttpResponse::Ok().json(response),
113        Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
114    }
115}