From 3e157e5b0ae049dbef0d913454feec924cb1d7b2 Mon Sep 17 00:00:00 2001 From: Wei Zhang Date: Fri, 13 Dec 2024 12:14:29 +0800 Subject: [PATCH] fix(graphQL): fix wrong read status when list notifications (#3555) Signed-off-by: Wei Zhang --- ee/tabby-db/src/notifications.rs | 7 +- .../src/service/notification.rs | 163 +++++++++++++++++- 2 files changed, 159 insertions(+), 11 deletions(-) diff --git a/ee/tabby-db/src/notifications.rs b/ee/tabby-db/src/notifications.rs index 0abda892caac..689c92a112e8 100644 --- a/ee/tabby-db/src/notifications.rs +++ b/ee/tabby-db/src/notifications.rs @@ -109,10 +109,10 @@ SELECT notifications.id, notifications.created_at, notifications.updated_at, - recipient, - content, + notifications.recipient, + notifications.content, CASE - WHEN read_notifications.user_id IS NOT NULL THEN 1 + WHEN read_notifications.user_id = '{user_id}' THEN 1 ELSE 0 END AS read FROM @@ -121,6 +121,7 @@ LEFT JOIN read_notifications ON notifications.id = read_notifications.notification_id + AND read_notifications.user_id = '{user_id}' WHERE ({recipient_clause}) AND notifications.created_at > '{date_7days_ago}' diff --git a/ee/tabby-webserver/src/service/notification.rs b/ee/tabby-webserver/src/service/notification.rs index 0eba4fa2dad5..0ac99e0a443c 100644 --- a/ee/tabby-webserver/src/service/notification.rs +++ b/ee/tabby-webserver/src/service/notification.rs @@ -47,7 +47,7 @@ mod tests { use super::*; #[tokio::test] - async fn test_notification_admin_list() { + async fn test_admin_list() { let db = DbConn::new_in_memory().await.unwrap(); let service = create(db.clone()); @@ -70,7 +70,7 @@ mod tests { } #[tokio::test] - async fn test_notification_admin_list_read() { + async fn test_admin_list_read() { let db = DbConn::new_in_memory().await.unwrap(); let service = create(db.clone()); @@ -94,7 +94,7 @@ mod tests { } #[tokio::test] - async fn test_notification_admin_list_all() { + async fn test_admin_list_all() { let db = DbConn::new_in_memory().await.unwrap(); let service = create(db.clone()); @@ -121,7 +121,7 @@ mod tests { } #[tokio::test] - async fn test_notification_admin_mark_all_read_admin() { + async fn test_admin_mark_all_read_admin() { let db = DbConn::new_in_memory().await.unwrap(); let service = create(db.clone()); @@ -139,7 +139,7 @@ mod tests { } #[tokio::test] - async fn test_notification_admin_mark_read_twice() { + async fn test_admin_mark_read_twice() { let db = DbConn::new_in_memory().await.unwrap(); let service = create(db.clone()); @@ -169,7 +169,7 @@ mod tests { } #[tokio::test] - async fn test_notification_admin_mark_all_read_twice() { + async fn test_admin_mark_all_read_twice() { let db = DbConn::new_in_memory().await.unwrap(); let service = create(db.clone()); @@ -196,7 +196,7 @@ mod tests { } #[tokio::test] - async fn test_notification_admin_mark_all_read_admin_and_all_user() { + async fn test_admin_mark_all_read_admin_and_all_user() { let db = DbConn::new_in_memory().await.unwrap(); let service = create(db.clone()); @@ -218,7 +218,7 @@ mod tests { } #[tokio::test] - async fn test_notification_user_mark_all_read_admin_and_all_user() { + async fn test_user_mark_all_read_admin_and_all_user() { let db = DbConn::new_in_memory().await.unwrap(); let service = create(db.clone()); @@ -237,4 +237,151 @@ mod tests { assert_eq!(notifications.len(), 1); assert!(notifications[0].read); } + + #[tokio::test] + async fn test_multi_user_list() { + let db = DbConn::new_in_memory().await.unwrap(); + let service = create(db.clone()); + + let user1 = db + .create_user("test1".into(), None, false, None) + .await + .unwrap() + .as_id(); + let user2 = db + .create_user("test2".into(), None, false, None) + .await + .unwrap() + .as_id(); + db.create_notification("admin", "admin_list").await.unwrap(); + db.create_notification("all_user", "all_user") + .await + .unwrap(); + + let notifications = service.list(&user1).await.unwrap(); + assert_eq!(notifications.len(), 1); + assert!(!notifications[0].read); + + let notifications = service.list(&user2).await.unwrap(); + assert_eq!(notifications.len(), 1); + assert!(!notifications[0].read); + } + + #[tokio::test] + async fn test_multi_user_mark_read() { + let db = DbConn::new_in_memory().await.unwrap(); + let service = create(db.clone()); + + let user1 = db + .create_user("test1".into(), None, false, None) + .await + .unwrap() + .as_id(); + let user2 = db + .create_user("test2".into(), None, false, None) + .await + .unwrap() + .as_id(); + db.create_notification("admin", "admin_list").await.unwrap(); + db.create_notification("all_user", "all_user") + .await + .unwrap(); + + // user1 mark read + service.mark_read(&user1, None).await.unwrap(); + let notifications = service.list(&user1).await.unwrap(); + assert_eq!(notifications.len(), 1); + assert!(notifications[0].read); + + // user2 should still have unread notification + let notifications = service.list(&user2).await.unwrap(); + assert_eq!(notifications.len(), 1); + assert!(!notifications[0].read); + + // user2 mark read + service.mark_read(&user2, None).await.unwrap(); + let notifications = service.list(&user2).await.unwrap(); + assert_eq!(notifications.len(), 1); + assert!(notifications[0].read); + } + + #[tokio::test] + async fn test_multi_admin_mark_read() { + let db = DbConn::new_in_memory().await.unwrap(); + let service = create(db.clone()); + + let user1 = db + .create_user("test1".into(), None, true, None) + .await + .unwrap() + .as_id(); + let user2 = db + .create_user("test2".into(), None, true, None) + .await + .unwrap() + .as_id(); + db.create_notification("admin", "admin_list").await.unwrap(); + db.create_notification("all_user", "all_user") + .await + .unwrap(); + + // user1 mark read + service.mark_read(&user1, None).await.unwrap(); + let notifications = service.list(&user1).await.unwrap(); + assert_eq!(notifications.len(), 2); + assert!(notifications[0].read); + assert!(notifications[1].read); + + // user2 should still have unread notification + let notifications = service.list(&user2).await.unwrap(); + assert_eq!(notifications.len(), 2); + assert!(!notifications[0].read); + assert!(!notifications[1].read); + + // user2 mark read + service.mark_read(&user2, None).await.unwrap(); + let notifications = service.list(&user2).await.unwrap(); + assert_eq!(notifications.len(), 2); + assert!(notifications[0].read); + assert!(notifications[1].read); + } + + #[tokio::test] + async fn test_multi_admin_user_mark_read() { + let db = DbConn::new_in_memory().await.unwrap(); + let service = create(db.clone()); + + let admin = db + .create_user("test1".into(), None, true, None) + .await + .unwrap() + .as_id(); + let user = db + .create_user("test2".into(), None, false, None) + .await + .unwrap() + .as_id(); + db.create_notification("admin", "admin_list").await.unwrap(); + db.create_notification("all_user", "all_user") + .await + .unwrap(); + + // admin mark read + service.mark_read(&admin, None).await.unwrap(); + let notifications = service.list(&admin).await.unwrap(); + assert_eq!(notifications.len(), 2); + assert!(notifications[0].read); + assert!(notifications[1].read); + + // user should still have unread notification + let notifications = service.list(&user).await.unwrap(); + assert_eq!(notifications.len(), 1); + assert!(!notifications[0].read); + + // user mark read + service.mark_read(&user, None).await.unwrap(); + let notifications = service.list(&user).await.unwrap(); + assert_eq!(notifications.len(), 1); + assert!(notifications[0].read); + } }