From 83376544d86d333974e6c7a15cf8818bdf832927 Mon Sep 17 00:00:00 2001 From: BlackDex Date: Thu, 25 May 2023 20:57:31 +0200 Subject: [PATCH] Fix collection change ws notifications When chaning a collection this did not got notified via WebSockets. This PR adds this feature and resolves #3534 --- src/api/core/ciphers.rs | 29 ++++++++++++++++++++++++----- src/api/notifications.rs | 19 +++++++++++++++---- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index a6270046..425ac6d4 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -512,7 +512,7 @@ pub async fn update_cipher_from_data( .await; } - nt.send_cipher_update(ut, cipher, &cipher.update_users_revision(conn).await, &headers.device.uuid).await; + nt.send_cipher_update(ut, cipher, &cipher.update_users_revision(conn).await, &headers.device.uuid, None).await; } Ok(()) @@ -702,8 +702,9 @@ async fn put_collections_update( data: JsonUpcase, headers: Headers, conn: DbConn, + nt: Notify<'_>, ) -> EmptyResult { - post_collections_admin(uuid, data, headers, conn).await + post_collections_admin(uuid, data, headers, conn, nt).await } #[post("/ciphers//collections", data = "")] @@ -712,8 +713,9 @@ async fn post_collections_update( data: JsonUpcase, headers: Headers, conn: DbConn, + nt: Notify<'_>, ) -> EmptyResult { - post_collections_admin(uuid, data, headers, conn).await + post_collections_admin(uuid, data, headers, conn, nt).await } #[put("/ciphers//collections-admin", data = "")] @@ -722,8 +724,9 @@ async fn put_collections_admin( data: JsonUpcase, headers: Headers, conn: DbConn, + nt: Notify<'_>, ) -> EmptyResult { - post_collections_admin(uuid, data, headers, conn).await + post_collections_admin(uuid, data, headers, conn, nt).await } #[post("/ciphers//collections-admin", data = "")] @@ -732,6 +735,7 @@ async fn post_collections_admin( data: JsonUpcase, headers: Headers, mut conn: DbConn, + nt: Notify<'_>, ) -> EmptyResult { let data: CollectionsAdminData = data.into_inner().data; @@ -767,6 +771,15 @@ async fn post_collections_admin( } } + nt.send_cipher_update( + UpdateType::SyncCipherUpdate, + &cipher, + &cipher.update_users_revision(&mut conn).await, + &headers.device.uuid, + Some(Vec::from_iter(posted_collections)), + ) + .await; + log_event( EventType::CipherUpdatedCollections as i32, &cipher.uuid, @@ -1108,6 +1121,7 @@ async fn save_attachment( &cipher, &cipher.update_users_revision(&mut conn).await, &headers.device.uuid, + None, ) .await; @@ -1393,7 +1407,8 @@ async fn move_cipher_selected( // Move cipher cipher.move_to_folder(data.FolderId.clone(), &user_uuid, &mut conn).await?; - nt.send_cipher_update(UpdateType::SyncCipherUpdate, &cipher, &[user_uuid.clone()], &headers.device.uuid).await; + nt.send_cipher_update(UpdateType::SyncCipherUpdate, &cipher, &[user_uuid.clone()], &headers.device.uuid, None) + .await; } Ok(()) @@ -1503,6 +1518,7 @@ async fn _delete_cipher_by_uuid( &cipher, &cipher.update_users_revision(conn).await, &headers.device.uuid, + None, ) .await; } else { @@ -1512,6 +1528,7 @@ async fn _delete_cipher_by_uuid( &cipher, &cipher.update_users_revision(conn).await, &headers.device.uuid, + None, ) .await; } @@ -1581,6 +1598,7 @@ async fn _restore_cipher_by_uuid(uuid: &str, headers: &Headers, conn: &mut DbCon &cipher, &cipher.update_users_revision(conn).await, &headers.device.uuid, + None, ) .await; if let Some(org_uuid) = &cipher.organization_uuid { @@ -1662,6 +1680,7 @@ async fn _delete_cipher_attachment_by_id( &cipher, &cipher.update_users_revision(conn).await, &headers.device.uuid, + None, ) .await; if let Some(org_uuid) = cipher.organization_uuid { diff --git a/src/api/notifications.rs b/src/api/notifications.rs index 7bc502ee..76f33f7c 100644 --- a/src/api/notifications.rs +++ b/src/api/notifications.rs @@ -4,7 +4,7 @@ use std::{ time::Duration, }; -use chrono::NaiveDateTime; +use chrono::{NaiveDateTime, Utc}; use rmpv::Value; use rocket::{ futures::{SinkExt, StreamExt}, @@ -265,17 +265,28 @@ impl WebSocketUsers { cipher: &Cipher, user_uuids: &[String], acting_device_uuid: &String, + collection_uuids: Option>, ) { - let user_uuid = convert_option(cipher.user_uuid.clone()); let org_uuid = convert_option(cipher.organization_uuid.clone()); + // Depending if there are collections provided or not, we need to have different values for the following variables. + // The user_uuid should be `null`, and the revision date should be set to now, else the clients won't sync the collection change. + let (user_uuid, collection_uuids, revision_date) = if let Some(collection_uuids) = collection_uuids { + ( + Value::Nil, + Value::Array(collection_uuids.into_iter().map(|v| v.into()).collect::>()), + serialize_date(Utc::now().naive_utc()), + ) + } else { + (convert_option(cipher.user_uuid.clone()), Value::Nil, serialize_date(cipher.updated_at)) + }; let data = create_update( vec![ ("Id".into(), cipher.uuid.clone().into()), ("UserId".into(), user_uuid), ("OrganizationId".into(), org_uuid), - ("CollectionIds".into(), Value::Nil), - ("RevisionDate".into(), serialize_date(cipher.updated_at)), + ("CollectionIds".into(), collection_uuids), + ("RevisionDate".into(), revision_date), ], ut, Some(acting_device_uuid.into()),