diff --git a/ee/tabby-db/schema/schema.sql b/ee/tabby-db/schema/schema.sql index ef1e248389cc..7d9aa5b5bcd4 100644 --- a/ee/tabby-db/schema/schema.sql +++ b/ee/tabby-db/schema/schema.sql @@ -232,7 +232,7 @@ CREATE TABLE notifications( -- content of notification, in markdown format. content TEXT NOT NULL ); -CREATE TABLE readed_notifications( +CREATE TABLE read_notifications( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, notification_id INTEGER NOT NULL, diff --git a/ee/tabby-db/schema/schema.svg b/ee/tabby-db/schema/schema.svg index a5c49d083675..b990bf544729 100644 --- a/ee/tabby-db/schema/schema.svg +++ b/ee/tabby-db/schema/schema.svg @@ -316,7 +316,7 @@ name - + password_reset:e->users:w @@ -365,43 +365,43 @@ - + -readed_notifications - -readed_notifications - -🔑 - -id - -  - -user_id - -  - -notification_id - -  - -created_at - -  - -updated_at - - - -readed_notifications:e->notifications:w - +read_notifications + +read_notifications + +🔑 + +id + +  + +user_id + +  + +notification_id + +  + +created_at + +  + +updated_at + + + +read_notifications:e->notifications:w + - - -readed_notifications:e->users:w - - + + +read_notifications:e->users:w + + @@ -430,7 +430,7 @@ created_at - + refresh_tokens:e->users:w @@ -550,7 +550,7 @@ updated_at - + source_id_read_access_policies:e->user_groups:w @@ -628,13 +628,13 @@ relevant_questions - + thread_messages:e->threads:w - + threads:e->users:w @@ -682,7 +682,7 @@ updated_at - + user_completions:e->users:w @@ -714,7 +714,7 @@ payload - + user_events:e->users:w @@ -750,13 +750,13 @@ updated_at - + user_group_memberships:e->user_groups:w - + user_group_memberships:e->users:w diff --git a/ee/tabby-db/src/notifications.rs b/ee/tabby-db/src/notifications.rs index ceb2a855867b..9482e4b4d3b4 100644 --- a/ee/tabby-db/src/notifications.rs +++ b/ee/tabby-db/src/notifications.rs @@ -33,9 +33,12 @@ impl DbConn { pub async fn mark_notification_read(&self, id: i64, user_id: i64) -> Result<()> { query!( - "INSERT INTO read_notifications (notification_id, user_id) VALUES (?, ?)", + "INSERT INTO read_notifications (notification_id, user_id) + VALUES (?, ?) + ON CONFLICT (notification_id, user_id) + DO NOTHING", id, - user_id + user_id, ) .execute(&self.pool) .await?; @@ -71,7 +74,7 @@ ON notifications.id = read_notifications.notification_id AND read_notifications.user_id = ? WHERE - {} + ({}) AND read_notifications.notification_id IS NULL; "#, recipient_clause diff --git a/ee/tabby-webserver/src/service/notification.rs b/ee/tabby-webserver/src/service/notification.rs index 2200bdb6b266..84f1ee00249b 100644 --- a/ee/tabby-webserver/src/service/notification.rs +++ b/ee/tabby-webserver/src/service/notification.rs @@ -176,7 +176,7 @@ mod tests { assert!(service .mark_read(&user_id, Some(¬ification_id)) .await - .is_err()) + .is_ok()) } #[tokio::test] @@ -419,4 +419,77 @@ mod tests { assert_eq!(notifications.len(), 1); assert!(notifications[0].read); } + + #[tokio::test] + async fn test_admin_mark_single_then_all() { + let db = DbConn::new_in_memory().await.unwrap(); + let service = create(db.clone()); + + let user = db + .create_user("test1".into(), None, true, None) + .await + .unwrap() + .as_id(); + let notification = db + .create_notification("admin", "notification1") + .await + .unwrap() + .as_id(); + db.create_notification("admin", "notification2") + .await + .unwrap(); + + // mark single notification + service.mark_read(&user, Some(¬ification)).await.unwrap(); + let notifications = service.list(&user).await.unwrap(); + assert_eq!(notifications.len(), 2); + assert!(notifications[0].read); + assert!(!notifications[1].read); + + // mark all notifications + service.mark_read(&user, None).await.unwrap(); + let notifications = service.list(&user).await.unwrap(); + assert_eq!(notifications.len(), 2); + assert!(notifications[0].read); + assert!(notifications[1].read); + } + + #[tokio::test] + async fn test_admin_mark_single_twice() { + let db = DbConn::new_in_memory().await.unwrap(); + let service = create(db.clone()); + + let user = db + .create_user("test1".into(), None, true, None) + .await + .unwrap() + .as_id(); + let notification = db + .create_notification("admin", "notification1") + .await + .unwrap() + .as_id(); + + service.mark_read(&user, Some(¬ification)).await.unwrap(); + assert!(service.mark_read(&user, Some(¬ification)).await.is_ok()); + } + + #[tokio::test] + async fn test_admin_mark_all_twice() { + let db = DbConn::new_in_memory().await.unwrap(); + let service = create(db.clone()); + + let user = db + .create_user("test1".into(), None, true, None) + .await + .unwrap() + .as_id(); + db.create_notification("admin", "notification1") + .await + .unwrap() + .as_id(); + + service.mark_read(&user, None).await.unwrap(); + assert!(service.mark_read(&user, None).await.is_ok()); + } }