diff --git a/migrations/20210509151150_mcaptcha_notifications.sql b/migrations/20210509151150_mcaptcha_notifications.sql new file mode 100644 index 00000000..56e5e733 --- /dev/null +++ b/migrations/20210509151150_mcaptcha_notifications.sql @@ -0,0 +1,10 @@ +-- Add migration script here +CREATE TABLE IF NOT EXISTS mcaptcha_notifications ( + id SERIAL PRIMARY KEY NOT NULL, + tx INTEGER NOT NULL references mcaptcha_users(ID) ON DELETE CASCADE, + rx INTEGER NOT NULL references mcaptcha_users(ID) ON DELETE CASCADE, + heading varchar(30) NOT NULL, + message varchar(250) NOT NULL, + read BOOLEAN DEFAULT NULL, + received timestamptz NOT NULL DEFAULT now() +); diff --git a/src/api/v1/mod.rs b/src/api/v1/mod.rs index 5c8039d5..c16636e3 100644 --- a/src/api/v1/mod.rs +++ b/src/api/v1/mod.rs @@ -21,6 +21,7 @@ pub mod account; pub mod auth; pub mod mcaptcha; pub mod meta; +mod notifications; pub mod pow; mod routes; @@ -31,6 +32,7 @@ pub fn services(cfg: &mut ServiceConfig) { auth::services(cfg); account::services(cfg); mcaptcha::services(cfg); + notifications::services(cfg); pow::services(cfg); } diff --git a/src/api/v1/notifications/add.rs b/src/api/v1/notifications/add.rs new file mode 100644 index 00000000..045e37b0 --- /dev/null +++ b/src/api/v1/notifications/add.rs @@ -0,0 +1,102 @@ +/* +* Copyright (C) 2021 Aravinth Manivannan +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +use actix_identity::Identity; +use actix_web::{web, HttpResponse, Responder}; +use serde::{Deserialize, Serialize}; + +use crate::errors::*; +use crate::Data; + +#[derive(Serialize, Deserialize)] +pub struct AddNotification { + pub to: String, + pub heading: String, + pub message: String, +} + +/// route handler that adds a notification message +pub async fn add_notification( + payload: web::Json, + data: web::Data, + id: Identity, +) -> ServiceResult { + let sender = id.identity().unwrap(); + // TODO handle error where payload.to doesnt exist + sqlx::query!( + "INSERT INTO mcaptcha_notifications ( + heading, message, tx, rx) + VALUES ( + $1, $2, + (SELECT ID FROM mcaptcha_users WHERE name = $3), + (SELECT ID FROM mcaptcha_users WHERE name = $4) + );", + &payload.heading, + &payload.message, + &sender, + &payload.to, + ) + .execute(&data.db) + .await?; + Ok(HttpResponse::Ok()) +} + +#[cfg(test)] +mod tests { + use actix_web::http::{header, StatusCode}; + use actix_web::test; + + use super::*; + use crate::tests::*; + use crate::*; + + #[actix_rt::test] + async fn notification_works() { + const NAME1: &str = "notifuser1"; + const NAME2: &str = "notiuser2"; + const PASSWORD: &str = "longpassworddomain"; + const EMAIL1: &str = "testnotification1@a.com"; + const EMAIL2: &str = "testnotification2@a.com"; + + { + let data = Data::new().await; + delete_user(NAME1, &data).await; + delete_user(NAME2, &data).await; + } + + register_and_signin(NAME1, EMAIL1, PASSWORD).await; + register_and_signin(NAME2, EMAIL2, PASSWORD).await; + let (data, _creds, signin_resp) = signin(NAME1, PASSWORD).await; + let cookies = get_cookie!(signin_resp); + let mut app = get_app!(data).await; + + let msg = AddNotification { + to: NAME2.into(), + heading: "Test notification".into(), + message: "Testeing notifications with a dummy message".into(), + }; + + let send_notification_resp = test::call_service( + &mut app, + post_request!(&msg, V1_API_ROUTES.notifications.add) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(send_notification_resp.status(), StatusCode::OK); + } +} diff --git a/src/api/v1/notifications/mod.rs b/src/api/v1/notifications/mod.rs new file mode 100644 index 00000000..073dbfa8 --- /dev/null +++ b/src/api/v1/notifications/mod.rs @@ -0,0 +1,49 @@ +/* +* Copyright (C) 2021 Aravinth Manivannan +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +mod add; + +pub mod routes { + + pub struct Notifications { + pub add: &'static str, + pub mark_read: &'static str, + pub get: &'static str, + } + + impl Notifications { + pub const fn new() -> Notifications { + Notifications { + add: "/api/v1/notifications/add", + mark_read: "/api/v1/notifications/read/", + get: "/api/v1/notifications/get/", + } + } + } +} + +pub fn services(cfg: &mut actix_web::web::ServiceConfig) { + use crate::define_resource; + use crate::V1_API_ROUTES; + + define_resource!( + cfg, + V1_API_ROUTES.notifications.add, + Methods::ProtectPost, + add::add_notification + ); +} diff --git a/src/api/v1/routes.rs b/src/api/v1/routes.rs index 3236c0f6..560e8e41 100644 --- a/src/api/v1/routes.rs +++ b/src/api/v1/routes.rs @@ -21,6 +21,7 @@ use super::mcaptcha::duration::routes::Duration; use super::mcaptcha::levels::routes::Levels; use super::mcaptcha::mcaptcha::routes::MCaptcha; use super::meta::routes::Meta; +use super::notifications::routes::Notifications; use super::pow::routes::PoW; pub const ROUTES: Routes = Routes::new(); @@ -33,6 +34,7 @@ pub struct Routes { pub duration: Duration, pub meta: Meta, pub pow: PoW, + pub notifications: Notifications, } impl Routes { @@ -45,6 +47,7 @@ impl Routes { duration: Duration::new(), meta: Meta::new(), pow: PoW::new(), + notifications: Notifications::new(), } } } diff --git a/src/pages/routes.rs b/src/pages/routes.rs index 25f5162a..36fb43a3 100644 --- a/src/pages/routes.rs +++ b/src/pages/routes.rs @@ -39,9 +39,9 @@ impl Routes { panel, home, errors: Errors::new(), - about: "/aboubt", + about: "/about", thanks: "/thanks", - donate: "/donat", + donate: "/donate", } } }