Add mark as new API endpoint for notifications

POST /api/notifications/{id}/mark_as_new sets is_new=1, allowing a notification to be flagged as unread after it has been read.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
rzuasti
2026-05-27 10:13:56 -04:00
co-authored by Claude Sonnet 4.6
parent 913bf0e839
commit 8153a216b9
3 changed files with 64 additions and 1 deletions
+45
View File
@@ -93,6 +93,21 @@ pub fn mark_as_old(id: i64) -> Result<(), DbError> {
}
}
pub fn mark_as_new(id: i64) -> Result<(), DbError> {
let conn = db::get_db_connection();
match conn.execute("UPDATE notifications SET is_new=1 WHERE id=?1", params![id]) {
Ok(_) => {
debug!("Notification id={} flagged as new", id);
Ok(())
}
Err(error) => {
error!("Error marking notification ({id}) as new: {error}");
Err(DbError::from(error))
}
}
}
pub fn read(id: i64) -> Option<Notification> {
let conn = db::get_db_connection();
@@ -162,6 +177,36 @@ mod tests {
);
}
#[tokio::test]
async fn test_mark_as_new() {
tests_common::setup().await;
// Mark non-existant notification (should be fine)
mark_as_new(9999999).unwrap();
// Create notification with is_new=false
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(),
false,
))
.unwrap();
// Mark it as new
mark_as_new(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=1."
);
}
#[tokio::test]
async fn test_insert() {
tests_common::setup().await;
+5 -1
View File
@@ -5,7 +5,7 @@ use axum::extract::Request;
use axum::http::StatusCode;
use axum::middleware::Next;
use axum::response::Response;
use axum::routing::{delete, get, put};
use axum::routing::{delete, get, post, put};
use axum::{Router, http};
use log::{debug, error, info};
use tower::ServiceBuilder;
@@ -38,6 +38,10 @@ pub async fn serve() -> Result<(), Box<dyn Error>> {
"/api/notifications/{id}/read_without_flagging",
get(notifications::read_without_flagging),
)
.route(
"/api/notifications/{id}/mark_as_new",
post(notifications::mark_as_new),
)
.route_layer(axum::middleware::from_fn(auth))
.layer(ServiceBuilder::new().layer(cors_layer))
.route(
+14
View File
@@ -4,6 +4,7 @@ use axum::{
Json,
extract::{Path, Query},
http::StatusCode,
response::IntoResponse,
};
use log::error;
@@ -31,6 +32,19 @@ pub async fn read_without_flagging(Path(id): Path<i64>) -> Result<Json<Notificat
}
}
pub async fn mark_as_new(Path(id): Path<i64>) -> impl IntoResponse {
match db::notifications::mark_as_new(id) {
Ok(_) => (StatusCode::OK, "Notification marked as new"),
Err(err) => {
error!("Error marking notification (id={id}) as new: {}", err);
(
StatusCode::INTERNAL_SERVER_ERROR,
"Error updating notification in the server, check your logs",
)
}
}
}
pub async fn list(
Query(params): Query<HashMap<String, String>>,
) -> Result<Json<Vec<Notification>>, StatusCode> {