use crate::util::test_client::{assert_client_collab, assert_server_collab, TestClient}; use collab_entity::CollabType; use database_entity::dto::AFAccessLevel; use serde_json::json; #[tokio::test] async fn recv_updates_without_permission_test() { let collab_type = CollabType::Document; let mut client_1 = TestClient::new_user().await; let mut client_2 = TestClient::new_user().await; let workspace_id = client_1.workspace_id().await; let object_id = client_1 .create_collab(&workspace_id, collab_type.clone()) .await; client_2 .open_collab(&workspace_id, &object_id, collab_type.clone()) .await; // Edit the collab from client 1 and then the server will broadcast to client 2. But the client 2 // is not the member of the collab, so the client 2 will not receive the update. client_1 .collab_by_object_id .get_mut(&object_id) .unwrap() .collab .lock() .insert("name", "AppFlowy"); client_1.wait_object_sync_complete(&object_id).await; assert_client_collab(&mut client_2, &object_id, json!({}), 3).await; } #[tokio::test] async fn recv_remote_updates_with_readonly_permission_test() { let collab_type = CollabType::Document; let mut client_1 = TestClient::new_user().await; let mut client_2 = TestClient::new_user().await; let workspace_id = client_1.workspace_id().await; let object_id = client_1 .create_collab(&workspace_id, collab_type.clone()) .await; // Add client 2 as the member of the collab then the client 2 will receive the update. client_1 .add_client_as_collab_member( &workspace_id, &object_id, &client_2, AFAccessLevel::ReadOnly, ) .await; client_2 .open_collab(&workspace_id, &object_id, collab_type.clone()) .await; // Edit the collab from client 1 and then the server will broadcast to client 2 client_1 .collab_by_object_id .get_mut(&object_id) .unwrap() .collab .lock() .insert("name", "AppFlowy"); client_1.wait_object_sync_complete(&object_id).await; let expected = json!({ "name": "AppFlowy" }); assert_client_collab(&mut client_2, &object_id, expected.clone(), 10).await; assert_server_collab( &workspace_id, &mut client_1.api_client, &object_id, &collab_type, 10, expected, ) .await; } #[tokio::test] async fn init_sync_with_readonly_permission_test() { let collab_type = CollabType::Document; let mut client_1 = TestClient::new_user().await; let mut client_2 = TestClient::new_user().await; let workspace_id = client_1.workspace_id().await; let object_id = client_1 .create_collab(&workspace_id, collab_type.clone()) .await; client_1 .collab_by_object_id .get_mut(&object_id) .unwrap() .collab .lock() .insert("name", "AppFlowy"); client_1.wait_object_sync_complete(&object_id).await; // let expected = json!({ "name": "AppFlowy" }); assert_server_collab( &workspace_id, &mut client_1.api_client, &object_id, &collab_type, 10, expected.clone(), ) .await; // Add client 2 as the member of the collab with readonly permission. // client 2 can pull the latest updates via the init sync. But it's not allowed to send local changes. client_1 .add_client_as_collab_member( &workspace_id, &object_id, &client_2, AFAccessLevel::ReadOnly, ) .await; client_2 .open_collab(&workspace_id, &object_id, collab_type.clone()) .await; assert_client_collab(&mut client_2, &object_id, expected, 5).await; } #[tokio::test] async fn edit_collab_with_readonly_permission_test() { let collab_type = CollabType::Document; let mut client_1 = TestClient::new_user().await; let mut client_2 = TestClient::new_user().await; let workspace_id = client_1.workspace_id().await; let object_id = client_1 .create_collab(&workspace_id, collab_type.clone()) .await; // Add client 2 as the member of the collab then the client 2 will receive the update. client_1 .add_client_as_collab_member( &workspace_id, &object_id, &client_2, AFAccessLevel::ReadOnly, ) .await; client_2 .open_collab(&workspace_id, &object_id, collab_type.clone()) .await; // client 2 edit the collab and then the server will reject the update which mean the // collab in the server will not be updated. client_2 .collab_by_object_id .get_mut(&object_id) .unwrap() .collab .lock() .insert("name", "AppFlowy"); assert_client_collab( &mut client_2, &object_id, json!({ "name": "AppFlowy" }), 5, ) .await; assert_server_collab( &workspace_id, &mut client_1.api_client, &object_id, &collab_type, 5, json!({}), ) .await; } #[tokio::test] async fn edit_collab_with_read_and_write_permission_test() { let collab_type = CollabType::Document; let mut client_1 = TestClient::new_user().await; let mut client_2 = TestClient::new_user().await; let workspace_id = client_1.workspace_id().await; let object_id = client_1 .create_collab(&workspace_id, collab_type.clone()) .await; // Add client 2 as the member of the collab then the client 2 will receive the update. client_1 .add_client_as_collab_member( &workspace_id, &object_id, &client_2, AFAccessLevel::ReadAndWrite, ) .await; client_2 .open_collab(&workspace_id, &object_id, collab_type.clone()) .await; // client 2 edit the collab and then the server will broadcast the update client_2 .collab_by_object_id .get_mut(&object_id) .unwrap() .collab .lock() .insert("name", "AppFlowy"); let expected = json!({ "name": "AppFlowy" }); assert_client_collab(&mut client_2, &object_id, expected.clone(), 5).await; assert_server_collab( &workspace_id, &mut client_1.api_client, &object_id, &collab_type, 5, expected, ) .await; } #[tokio::test] async fn edit_collab_with_full_access_permission_test() { let collab_type = CollabType::Document; let mut client_1 = TestClient::new_user().await; let mut client_2 = TestClient::new_user().await; let workspace_id = client_1.workspace_id().await; let object_id = client_1 .create_collab(&workspace_id, collab_type.clone()) .await; // Add client 2 as the member of the collab then the client 2 will receive the update. client_1 .add_client_as_collab_member( &workspace_id, &object_id, &client_2, AFAccessLevel::FullAccess, ) .await; client_2 .open_collab(&workspace_id, &object_id, collab_type.clone()) .await; // client 2 edit the collab and then the server will broadcast the update client_2 .collab_by_object_id .get_mut(&object_id) .unwrap() .collab .lock() .insert("name", "AppFlowy"); let expected = json!({ "name": "AppFlowy" }); assert_client_collab(&mut client_2, &object_id, expected.clone(), 5).await; assert_server_collab( &workspace_id, &mut client_1.api_client, &object_id, &collab_type, 5, expected, ) .await; } #[tokio::test] async fn edit_collab_with_full_access_then_readonly_permission() { let collab_type = CollabType::Document; let mut client_1 = TestClient::new_user().await; let mut client_2 = TestClient::new_user().await; let workspace_id = client_1.workspace_id().await; let object_id = client_1 .create_collab(&workspace_id, collab_type.clone()) .await; // Add client 2 as the member of the collab then the client 2 will receive the update. client_1 .add_client_as_collab_member( &workspace_id, &object_id, &client_2, AFAccessLevel::FullAccess, ) .await; // client 2 edit the collab and then the server will broadcast the update { client_2 .open_collab(&workspace_id, &object_id, collab_type.clone()) .await; client_2 .collab_by_object_id .get_mut(&object_id) .unwrap() .collab .lock() .insert("title", "hello world"); client_2.wait_object_sync_complete(&object_id).await; } // update the permission from full access to readonly, then the server will reject the subsequent // updates generated by client 2 { client_1 .update_collab_member_access_level( &workspace_id, &object_id, &client_2, AFAccessLevel::ReadOnly, ) .await; client_2 .collab_by_object_id .get_mut(&object_id) .unwrap() .collab .lock() .insert("subtitle", "Writing Rust, fun"); } assert_client_collab( &mut client_2, &object_id, json!({ "title": "hello world", "subtitle": "Writing Rust, fun" }), 5, ) .await; assert_server_collab( &workspace_id, &mut client_1.api_client, &object_id, &collab_type, 5, json!({ "title": "hello world" }), ) .await; }