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());
+ }
}