feat: leave workspace api ()

* feat: leave workpspace event

* feat: add leave workspace event

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
Zack 2024-03-29 17:53:59 +09:00 committed by GitHub
parent 490cb48354
commit 3f4a409364
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 108 additions and 20 deletions
frontend/rust-lib
event-integration
flowy-server/src/af_cloud/impls/user
flowy-user-pub/src
flowy-user/src

@ -313,6 +313,17 @@ impl EventIntegrationTest {
.async_send()
.await;
}
pub async fn leave_workspace(&self, workspace_id: &str) {
let payload = UserWorkspaceIdPB {
workspace_id: workspace_id.to_string(),
};
EventBuilder::new(self.clone())
.event(UserEvent::LeaveWorkspace)
.payload(payload)
.async_send()
.await;
}
}
#[derive(Clone)]

@ -1,3 +1,4 @@
use crate::user::af_cloud_test::util::get_synced_workspaces;
use event_integration::user_event::user_localhost_af_cloud;
use event_integration::EventIntegrationTest;
@ -45,3 +46,28 @@ async fn af_cloud_delete_workspace_member_test() {
assert_eq!(members.len(), 1);
assert_eq!(members[0].email, user_1.email);
}
#[tokio::test]
async fn af_cloud_leave_workspace_test() {
user_localhost_af_cloud().await;
let test_1 = EventIntegrationTest::new().await;
let user_1 = test_1.af_cloud_sign_up().await;
let test_2 = EventIntegrationTest::new().await;
let user_2 = test_2.af_cloud_sign_up().await;
test_1
.add_workspace_member(&user_1.workspace_id, &user_2.email)
.await;
// test_2 should have 2 workspace
let workspaces = get_synced_workspaces(&test_2, user_2.id).await;
assert_eq!(workspaces.len(), 2);
// user_2 leaves the workspace
test_2.leave_workspace(&user_1.workspace_id).await;
// user_2 should have 1 workspace
let workspaces = get_synced_workspaces(&test_2, user_2.id).await;
assert_eq!(workspaces.len(), 1);
}

@ -2,4 +2,5 @@ mod anon_user_test;
mod auth_test;
mod import_af_data_folder_test;
mod member_test;
mod util;
mod workspace_test;

@ -0,0 +1,27 @@
use std::time::Duration;
use event_integration::EventIntegrationTest;
use flowy_user::{
entities::{RepeatedUserWorkspacePB, UserWorkspacePB},
protobuf::UserNotification,
};
use crate::util::receive_with_timeout;
pub async fn get_synced_workspaces(
test: &EventIntegrationTest,
user_id: i64,
) -> Vec<UserWorkspacePB> {
let _workspaces = test.get_all_workspaces().await.items;
let sub_id = user_id.to_string();
let rx = test
.notification_sender
.subscribe::<RepeatedUserWorkspacePB>(
&sub_id,
UserNotification::DidUpdateUserWorkspaces as i32,
);
receive_with_timeout(rx, Duration::from_secs(30))
.await
.unwrap()
.items
}

@ -1,11 +1,7 @@
use std::time::Duration;
use event_integration::user_event::user_localhost_af_cloud;
use event_integration::EventIntegrationTest;
use flowy_user::entities::{RepeatedUserWorkspacePB, UserWorkspacePB};
use flowy_user::protobuf::UserNotification;
use crate::util::receive_with_timeout;
use crate::user::af_cloud_test::util::get_synced_workspaces;
#[tokio::test]
async fn af_cloud_workspace_delete() {
@ -111,18 +107,3 @@ async fn af_cloud_open_workspace_test() {
assert_eq!(views[1].name, "my first document".to_string());
assert_eq!(views[2].name, "my second document".to_string());
}
async fn get_synced_workspaces(test: &EventIntegrationTest, user_id: i64) -> Vec<UserWorkspacePB> {
let _workspaces = test.get_all_workspaces().await.items;
let sub_id = user_id.to_string();
let rx = test
.notification_sender
.subscribe::<RepeatedUserWorkspacePB>(
&sub_id,
UserNotification::DidUpdateUserWorkspaces as i32,
);
receive_with_timeout(rx, Duration::from_secs(30))
.await
.unwrap()
.items
}

@ -346,6 +346,16 @@ where
Ok(())
})
}
fn leave_workspace(&self, workspace_id: &str) -> FutureResult<(), FlowyError> {
let try_get_client = self.server.try_get_client();
let workspace_id = workspace_id.to_string();
FutureResult::new(async move {
let client = try_get_client?;
client.leave_workspace(&workspace_id).await?;
Ok(())
})
}
}
async fn get_admin_client(client: &Arc<AFCloudClient>) -> FlowyResult<Client> {

@ -234,6 +234,10 @@ pub trait UserCloudService: Send + Sync + 'static {
workspace_id: &str,
objects: Vec<UserCollabParams>,
) -> FutureResult<(), FlowyError>;
fn leave_workspace(&self, workspace_id: &str) -> FutureResult<(), FlowyError> {
FutureResult::new(async { Ok(()) })
}
}
pub type UserUpdateReceiver = tokio::sync::mpsc::Receiver<UserUpdate>;

@ -709,3 +709,14 @@ pub async fn change_workspace_icon_handler(
.await?;
Ok(())
}
#[tracing::instrument(level = "debug", skip_all, err)]
pub async fn leave_workspace_handler(
param: AFPluginData<UserWorkspaceIdPB>,
manager: AFPluginState<Weak<UserManager>>,
) -> Result<(), FlowyError> {
let workspace_id = param.into_inner().workspace_id;
let manager = upgrade_manager(manager)?;
manager.leave_workspace(&workspace_id).await?;
Ok(())
}

@ -64,6 +64,7 @@ pub fn init(user_manager: Weak<UserManager>) -> AFPlugin {
.event(UserEvent::DeleteWorkspace, delete_workspace_handler)
.event(UserEvent::RenameWorkspace, rename_workspace_handler)
.event(UserEvent::ChangeWorkspaceIcon, change_workspace_icon_handler)
.event(UserEvent::LeaveWorkspace, leave_workspace_handler)
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
@ -208,6 +209,9 @@ pub enum UserEvent {
#[event(input = "ChangeWorkspaceIconPB")]
ChangeWorkspaceIcon = 45,
#[event(input = "UserWorkspaceIdPB")]
LeaveWorkspace = 46,
}
pub trait UserStatusCallback: Send + Sync + 'static {

@ -202,6 +202,19 @@ impl UserManager {
save_user_workspaces(uid, conn, &[user_workspace])
}
pub async fn leave_workspace(&self, workspace_id: &str) -> FlowyResult<()> {
self
.cloud_services
.get_user_service()?
.leave_workspace(workspace_id)
.await?;
// delete workspace from local sqlite db
let uid = self.user_id()?;
let conn = self.db_connection(uid)?;
delete_user_workspaces(conn, workspace_id)
}
pub async fn delete_workspace(&self, workspace_id: &str) -> FlowyResult<()> {
self
.cloud_services