diff --git a/backend/src/db/notifications.rs b/backend/src/db/notifications.rs index 226e41a..27c8222 100644 --- a/backend/src/db/notifications.rs +++ b/backend/src/db/notifications.rs @@ -46,6 +46,21 @@ pub fn insert(notification: Notification) -> Result { } } +pub fn mark_as_old(id: i64) -> Result<(), DbError> { + let conn = db::get_db_connection(); + + match conn.execute("UPDATE notifications SET is_new=0 WHERE id=?1", params![id]) { + Ok(_) => { + debug!("Notification id={} flagged as old", id); + Ok(()) + } + Err(error) => { + error!("Error marking notification ({id}) as old: {error}"); + Err(DbError::from(error)) + } + } +} + pub fn read(id: i64) -> Option { let conn = db::get_db_connection(); @@ -85,6 +100,36 @@ mod tests { use super::*; use crate::{model::notifications::NotificationType, tests_common}; + #[tokio::test] + async fn test_mark_as_old() { + tests_common::setup().await; + + // Mark unexistant notification (should be fine) + mark_as_old(9999999).unwrap(); + + // Create new notification + let created_on = Utc::now(); + let inserted_id = insert(Notification::new( + created_on, + NotificationType::DeviceOnlineAfterTime, + "New notification title".to_string(), + "New notification body".to_string(), + true, + )) + .unwrap(); + + // Mark it as old + mark_as_old(inserted_id).unwrap(); + + // Read it and validate + let notification = read(inserted_id).unwrap(); + + assert!( + !notification.is_new, + "Notification id={inserted_id} should have is_new=0." + ); + } + #[tokio::test] async fn test_insert_default() { tests_common::setup().await; diff --git a/backend/src/web_server.rs b/backend/src/web_server.rs index e30b652..8c02564 100644 --- a/backend/src/web_server.rs +++ b/backend/src/web_server.rs @@ -1,7 +1,6 @@ use std::error::Error; -use axum::{Json, Router, http::StatusCode, routing::get}; -use chrono::Local; +use axum::{Json, Router, extract::Path, http::StatusCode, routing::get}; use log::{debug, error, info}; use tower_http::services::ServeDir; @@ -16,8 +15,13 @@ pub async fn serve() -> Result<(), Box> { let router = Router::new() .route("/", get(|| async { "hello" })) - .route("/devices", get(get_devices)) - .route("/notifications", get(list_notifications)) + .route("/api/devices", get(get_devices)) + .route("/api/notifications", get(list_notifications)) + .route("/api/notifications/{id}", get(read_notification)) + .route( + "/api/notifications/{id}/read_without_flagging", + get(read_notification_without_flagging), + ) .nest_service("/web", static_files); info!("Web server starting at http://0.0.0.0:3000"); // Start the server @@ -30,16 +34,31 @@ pub async fn serve() -> Result<(), Box> { } async fn get_devices() -> Result>, StatusCode> { - let mut devices = Vec::new(); + unimplemented!(); +} - devices.push(Device { - mac_address: "mac".to_string(), - ipv4_address: "ip".to_string(), - vendor: "vendor".to_string(), - last_seen: Local::now().to_utc(), - }); +async fn read_notification(Path(id): Path) -> Result, StatusCode> { + match db::notifications::mark_as_old(id) { + Ok(_) => {} + Err(err) => { + error!("Error marking notification (id={id}) as old: {}", err); + return Err(StatusCode::INTERNAL_SERVER_ERROR); + } + }; - Ok(Json(devices)) + match db::notifications::read(id) { + Some(value) => Ok(Json(value)), + None => Err(StatusCode::NOT_FOUND), + } +} + +async fn read_notification_without_flagging( + Path(id): Path, +) -> Result, StatusCode> { + match db::notifications::read(id) { + Some(value) => Ok(Json(value)), + None => Err(StatusCode::NOT_FOUND), + } } async fn list_notifications() -> Result>, StatusCode> {