diff --git a/frontend/appflowy_flutter/macos/Runner.xcodeproj/project.pbxproj b/frontend/appflowy_flutter/macos/Runner.xcodeproj/project.pbxproj index e34603ede3..827d115052 100644 --- a/frontend/appflowy_flutter/macos/Runner.xcodeproj/project.pbxproj +++ b/frontend/appflowy_flutter/macos/Runner.xcodeproj/project.pbxproj @@ -421,7 +421,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { - ARCHS = "$(ARCHS_STANDARD)"; + ARCHS = arm64; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; @@ -436,7 +436,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - ONLY_ACTIVE_ARCH = YES; + ONLY_ACTIVE_ARCH = false; PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter; PRODUCT_NAME = AppFlowy; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -558,7 +558,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { - ARCHS = "$(ARCHS_STANDARD)"; + ARCHS = arm64; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; @@ -573,6 +573,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; + ONLY_ACTIVE_ARCH = false; PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter; PRODUCT_NAME = AppFlowy; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -586,7 +587,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { - ARCHS = "$(ARCHS_STANDARD)"; + ARCHS = arm64; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; @@ -601,7 +602,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - ONLY_ACTIVE_ARCH = YES; + ONLY_ACTIVE_ARCH = false; PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter; PRODUCT_NAME = AppFlowy; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index 9a0d84a591..c43f9d217c 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -762,7 +762,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "bytes", @@ -1292,7 +1292,7 @@ dependencies = [ "cssparser-macros", "dtoa-short", "itoa 1.0.6", - "phf 0.8.0", + "phf 0.11.2", "smallvec", ] @@ -1438,7 +1438,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "chrono", @@ -2117,6 +2117,7 @@ dependencies = [ "thiserror", "tokio-postgres", "url", + "validator", ] [[package]] @@ -2781,7 +2782,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "futures-util", @@ -2797,7 +2798,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "jsonwebtoken", @@ -3232,7 +3233,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "reqwest", @@ -3451,6 +3452,7 @@ dependencies = [ "thread-id", "tokio", "tracing", + "validator", ] [[package]] @@ -4307,6 +4309,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ + "phf_macros 0.11.2", "phf_shared 0.11.2", ] @@ -4398,6 +4401,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "phf_shared" version = "0.8.0" @@ -4901,7 +4917,7 @@ dependencies = [ [[package]] name = "realtime-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "bytes", "collab", @@ -5623,7 +5639,7 @@ dependencies = [ [[package]] name = "shared_entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "collab-entity", diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index 71d703367a..3ee84542e5 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -38,7 +38,7 @@ custom-protocol = ["tauri/custom-protocol"] # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "cc6b451104e7154b38df5ae9c4e7215a61fcf172" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "c87d0f05e988a02e9272a42722b304289be320e4" } # Please use the following script to update collab. # Working directory: frontend # diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index 7115bac4ec..041ccd56c1 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -660,7 +660,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "bytes", @@ -1265,7 +1265,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "chrono", @@ -1940,6 +1940,7 @@ dependencies = [ "thiserror", "tokio-postgres", "url", + "validator", ] [[package]] @@ -2440,7 +2441,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "futures-util", @@ -2456,7 +2457,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "jsonwebtoken", @@ -2816,7 +2817,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "reqwest", @@ -2951,6 +2952,7 @@ dependencies = [ "thread-id", "tokio", "tracing", + "validator", ] [[package]] @@ -4251,7 +4253,7 @@ dependencies = [ [[package]] name = "realtime-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "bytes", "collab", @@ -4872,7 +4874,7 @@ dependencies = [ [[package]] name = "shared_entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=cc6b451104e7154b38df5ae9c4e7215a61fcf172#cc6b451104e7154b38df5ae9c4e7215a61fcf172" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=c87d0f05e988a02e9272a42722b304289be320e4#c87d0f05e988a02e9272a42722b304289be320e4" dependencies = [ "anyhow", "collab-entity", diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index 8f07b4df8f..1aaf419f15 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -82,7 +82,7 @@ incremental = false # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "cc6b451104e7154b38df5ae9c4e7215a61fcf172" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "c87d0f05e988a02e9272a42722b304289be320e4" } # Please use the following script to update collab. # Working directory: frontend # diff --git a/frontend/rust-lib/collab-integrate/Cargo.toml b/frontend/rust-lib/collab-integrate/Cargo.toml index 9f3f4d592c..d801024469 100644 --- a/frontend/rust-lib/collab-integrate/Cargo.toml +++ b/frontend/rust-lib/collab-integrate/Cargo.toml @@ -25,6 +25,7 @@ lib-infra = { path = "../../../shared-lib/lib-infra" } [features] default = [] -supabase_integrate = ["collab-plugins/postgres_storage_plugin", "collab-plugins/rocksdb_plugin"] -appflowy_cloud_integrate = ["collab-plugins/rocksdb_plugin"] -snapshot_plugin = ["collab-plugins/snapshot_plugin"] \ No newline at end of file +supabase_integrate = ["collab-plugins/postgres_storage_plugin", "rocksdb_plugin"] +appflowy_cloud_integrate = ["rocksdb_plugin"] +snapshot_plugin = ["collab-plugins/snapshot_plugin"] +rocksdb_plugin = ["collab-plugins/rocksdb_plugin"] \ No newline at end of file diff --git a/frontend/rust-lib/event-integration/src/folder_event.rs b/frontend/rust-lib/event-integration/src/folder_event.rs index d5f0e7a141..5061cf3ce5 100644 --- a/frontend/rust-lib/event-integration/src/folder_event.rs +++ b/frontend/rust-lib/event-integration/src/folder_event.rs @@ -2,13 +2,51 @@ use flowy_folder2::entities::icon::UpdateViewIconPayloadPB; use flowy_folder2::entities::*; use flowy_folder2::event_map::FolderEvent; use flowy_folder2::event_map::FolderEvent::*; +use flowy_user::entities::{ + AddWorkspaceMemberPB, QueryWorkspacePB, RemoveWorkspaceMemberPB, RepeatedWorkspaceMemberPB, + WorkspaceMemberPB, +}; use flowy_user::errors::FlowyError; +use flowy_user::event_map::UserEvent; use crate::event_builder::EventBuilder; use crate::EventIntegrationTest; impl EventIntegrationTest { - // Must sign up/ sign in first + pub async fn add_workspace_member(&self, workspace_id: &str, email: &str) { + EventBuilder::new(self.clone()) + .event(UserEvent::AddWorkspaceMember) + .payload(AddWorkspaceMemberPB { + workspace_id: workspace_id.to_string(), + email: email.to_string(), + }) + .async_send() + .await; + } + + pub async fn delete_workspace_member(&self, workspace_id: &str, email: &str) { + EventBuilder::new(self.clone()) + .event(UserEvent::RemoveWorkspaceMember) + .payload(RemoveWorkspaceMemberPB { + workspace_id: workspace_id.to_string(), + email: email.to_string(), + }) + .async_send() + .await; + } + + pub async fn get_workspace_members(&self, workspace_id: &str) -> Vec { + EventBuilder::new(self.clone()) + .event(UserEvent::GetWorkspaceMember) + .payload(QueryWorkspacePB { + workspace_id: workspace_id.to_string(), + }) + .async_send() + .await + .parse::() + .items + } + pub async fn get_current_workspace(&self) -> WorkspaceSettingPB { EventBuilder::new(self.clone()) .event(FolderEvent::GetCurrentWorkspace) diff --git a/frontend/rust-lib/event-integration/tests/user/af_cloud_test/test.rs b/frontend/rust-lib/event-integration/tests/user/af_cloud_test/auth_test.rs similarity index 100% rename from frontend/rust-lib/event-integration/tests/user/af_cloud_test/test.rs rename to frontend/rust-lib/event-integration/tests/user/af_cloud_test/auth_test.rs diff --git a/frontend/rust-lib/event-integration/tests/user/af_cloud_test/member_test.rs b/frontend/rust-lib/event-integration/tests/user/af_cloud_test/member_test.rs new file mode 100644 index 0000000000..6020c8a56a --- /dev/null +++ b/frontend/rust-lib/event-integration/tests/user/af_cloud_test/member_test.rs @@ -0,0 +1,50 @@ +use event_integration::EventIntegrationTest; + +use crate::util::get_af_cloud_config; + +#[tokio::test] +async fn af_cloud_add_workspace_member_test() { + if get_af_cloud_config().is_some() { + let test_1 = EventIntegrationTest::new(); + let user_1 = test_1.af_cloud_sign_up().await; + + let test_2 = EventIntegrationTest::new(); + let user_2 = test_2.af_cloud_sign_up().await; + + let members = test_1.get_workspace_members(&user_1.workspace_id).await; + assert_eq!(members.len(), 1); + assert_eq!(members[0].email, user_1.email); + + test_1 + .add_workspace_member(&user_1.workspace_id, &user_2.email) + .await; + + let members = test_1.get_workspace_members(&user_1.workspace_id).await; + assert_eq!(members.len(), 2); + assert_eq!(members[0].email, user_1.email); + assert_eq!(members[1].email, user_2.email); + } +} + +#[tokio::test] +async fn af_cloud_delete_workspace_member_test() { + if get_af_cloud_config().is_some() { + let test_1 = EventIntegrationTest::new(); + let user_1 = test_1.af_cloud_sign_up().await; + + let test_2 = EventIntegrationTest::new(); + let user_2 = test_2.af_cloud_sign_up().await; + + test_1 + .add_workspace_member(&user_1.workspace_id, &user_2.email) + .await; + + test_1 + .delete_workspace_member(&user_1.workspace_id, &user_2.email) + .await; + + let members = test_1.get_workspace_members(&user_1.workspace_id).await; + assert_eq!(members.len(), 1); + assert_eq!(members[0].email, user_1.email); + } +} diff --git a/frontend/rust-lib/event-integration/tests/user/af_cloud_test/mod.rs b/frontend/rust-lib/event-integration/tests/user/af_cloud_test/mod.rs index 585722915d..7240a1b662 100644 --- a/frontend/rust-lib/event-integration/tests/user/af_cloud_test/mod.rs +++ b/frontend/rust-lib/event-integration/tests/user/af_cloud_test/mod.rs @@ -1 +1,2 @@ -mod test; +mod auth_test; +mod member_test; diff --git a/frontend/rust-lib/flowy-document2/Cargo.toml b/frontend/rust-lib/flowy-document2/Cargo.toml index 3015da29f9..1bf274ad6d 100644 --- a/frontend/rust-lib/flowy-document2/Cargo.toml +++ b/frontend/rust-lib/flowy-document2/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" collab = { version = "0.1.0" } collab-document = { version = "0.1.0" } collab-entity = { version = "0.1.0" } -collab-integrate = { workspace = true } +collab-integrate = { workspace = true, features = ["rocksdb_plugin", "snapshot_plugin"] } flowy-document-deps = { workspace = true } flowy-storage = { workspace = true } @@ -37,6 +37,7 @@ tokio-stream = { version = "0.1.14", features = ["sync"] } [dev-dependencies] tempfile = "3.4.0" tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } +collab-integrate = { workspace = true } [build-dependencies] flowy-codegen = { path = "../../../shared-lib/flowy-codegen"} diff --git a/frontend/rust-lib/flowy-error/Cargo.toml b/frontend/rust-lib/flowy-error/Cargo.toml index 0c30ac0792..ac48436bb7 100644 --- a/frontend/rust-lib/flowy-error/Cargo.toml +++ b/frontend/rust-lib/flowy-error/Cargo.toml @@ -11,6 +11,7 @@ protobuf = { version = "2.28.0" } bytes = "1.4" anyhow = "1.0" thiserror = "1.0" +validator = "0.16.0" fancy-regex = { version = "0.11.0" } lib-dispatch = { workspace = true, optional = true } diff --git a/frontend/rust-lib/flowy-error/src/errors.rs b/frontend/rust-lib/flowy-error/src/errors.rs index 25e3c33c28..d5a462058d 100644 --- a/frontend/rust-lib/flowy-error/src/errors.rs +++ b/frontend/rust-lib/flowy-error/src/errors.rs @@ -3,6 +3,7 @@ use std::fmt::Debug; use protobuf::ProtobufError; use thiserror::Error; +use validator::{ValidationError, ValidationErrors}; use flowy_derive::ProtoBuf; @@ -132,6 +133,18 @@ impl std::convert::From for FlowyError { } } +impl From for FlowyError { + fn from(value: ValidationError) -> Self { + FlowyError::new(ErrorCode::InvalidParams, value) + } +} + +impl From for FlowyError { + fn from(value: ValidationErrors) -> Self { + FlowyError::new(ErrorCode::InvalidParams, value) + } +} + impl From for FlowyError { fn from(e: anyhow::Error) -> Self { e.downcast::() diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs index 54476dbea8..256282e0ab 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::sync::Arc; use anyhow::{anyhow, Error}; -use client_api::entity::workspace_dto::CreateWorkspaceMember; +use client_api::entity::workspace_dto::{CreateWorkspaceMember, WorkspaceMemberChangeset}; use client_api::entity::{AFRole, AFWorkspace, InsertCollabParams, OAuthProvider}; use collab_entity::CollabObject; @@ -13,7 +13,7 @@ use lib_infra::box_any::BoxAny; use lib_infra::future::FutureResult; use crate::af_cloud::impls::user::dto::{ - af_update_from_update_params, user_profile_from_af_profile, + af_update_from_update_params, from_af_workspace_member, to_af_role, user_profile_from_af_profile, }; use crate::af_cloud::impls::user::util::encryption_type_from_profile; use crate::af_cloud::{AFCloudClient, AFServer}; @@ -155,6 +155,38 @@ where }) } + fn update_workspace_member( + &self, + user_email: String, + workspace_id: String, + role: Role, + ) -> FutureResult<(), Error> { + let try_get_client = self.server.try_get_client(); + FutureResult::new(async move { + let changeset = WorkspaceMemberChangeset::new(user_email).with_role(to_af_role(role)); + try_get_client? + .update_workspace_member(workspace_id, changeset) + .await?; + Ok(()) + }) + } + + fn get_workspace_members( + &self, + workspace_id: String, + ) -> FutureResult, Error> { + let try_get_client = self.server.try_get_client(); + FutureResult::new(async move { + let members = try_get_client? + .get_workspace_members(&workspace_id) + .await? + .into_iter() + .map(from_af_workspace_member) + .collect(); + Ok(members) + }) + } + fn get_user_awareness_updates(&self, _uid: i64) -> FutureResult>, Error> { // TODO(nathan): implement the RESTful API for this FutureResult::new(async { Ok(vec![]) }) diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/dto.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/dto.rs index e2c2922d0c..28fd37688c 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/dto.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/dto.rs @@ -1,9 +1,9 @@ use anyhow::Error; use client_api::entity::auth_dto::{UpdateUserParams, UserMetaData}; -use client_api::entity::AFUserProfile; +use client_api::entity::{AFRole, AFUserProfile, AFWorkspaceMember}; use flowy_user_deps::entities::{ - AuthType, UpdateUserProfileParams, UserProfile, USER_METADATA_ICON_URL, + AuthType, Role, UpdateUserProfileParams, UserProfile, WorkspaceMember, USER_METADATA_ICON_URL, USER_METADATA_OPEN_AI_KEY, USER_METADATA_STABILITY_AI_KEY, }; @@ -63,3 +63,27 @@ pub fn user_profile_from_af_profile( updated_at: profile.updated_at, }) } + +pub fn to_af_role(role: Role) -> AFRole { + match role { + Role::Owner => AFRole::Owner, + Role::Member => AFRole::Member, + Role::Guest => AFRole::Guest, + } +} + +pub fn from_af_role(role: AFRole) -> Role { + match role { + AFRole::Owner => Role::Owner, + AFRole::Member => Role::Member, + AFRole::Guest => Role::Guest, + } +} + +pub fn from_af_workspace_member(member: AFWorkspaceMember) -> WorkspaceMember { + WorkspaceMember { + email: member.email, + role: from_af_role(member.role), + name: member.name, + } +} diff --git a/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs b/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs index e8400b9a16..fcdf519ace 100644 --- a/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs +++ b/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs @@ -120,22 +120,6 @@ impl UserCloudService for LocalServerUserAuthServiceImpl { FutureResult::new(async { Ok(vec![]) }) } - fn add_workspace_member( - &self, - _user_email: String, - _workspace_id: String, - ) -> FutureResult<(), Error> { - FutureResult::new(async { Ok(()) }) - } - - fn remove_workspace_member( - &self, - _user_email: String, - _workspace_id: String, - ) -> FutureResult<(), Error> { - FutureResult::new(async { Ok(()) }) - } - fn get_user_awareness_updates(&self, _uid: i64) -> FutureResult>, Error> { FutureResult::new(async { Ok(vec![]) }) } diff --git a/frontend/rust-lib/flowy-server/src/supabase/api/user.rs b/frontend/rust-lib/flowy-server/src/supabase/api/user.rs index f1b138596d..a08f6f3ef0 100644 --- a/frontend/rust-lib/flowy-server/src/supabase/api/user.rs +++ b/frontend/rust-lib/flowy-server/src/supabase/api/user.rs @@ -234,22 +234,6 @@ where Ok(user_workspaces) }) } - fn add_workspace_member( - &self, - _user_email: String, - _workspace_id: String, - ) -> FutureResult<(), Error> { - todo!() - } - - fn remove_workspace_member( - &self, - _user_email: String, - _workspace_id: String, - ) -> FutureResult<(), Error> { - todo!() - } - fn get_user_awareness_updates(&self, uid: i64) -> FutureResult>, Error> { let try_get_postgrest = self.server.try_get_weak_postgrest(); let awareness_id = uid.to_string(); diff --git a/frontend/rust-lib/flowy-user-deps/src/cloud.rs b/frontend/rust-lib/flowy-user-deps/src/cloud.rs index 7eae820582..2b2b863564 100644 --- a/frontend/rust-lib/flowy-user-deps/src/cloud.rs +++ b/frontend/rust-lib/flowy-user-deps/src/cloud.rs @@ -13,7 +13,8 @@ use lib_infra::box_any::BoxAny; use lib_infra::future::FutureResult; use crate::entities::{ - AuthResponse, UpdateUserProfileParams, UserCredentials, UserProfile, UserWorkspace, + AuthResponse, Role, UpdateUserProfileParams, UserCredentials, UserProfile, UserWorkspace, + WorkspaceMember, }; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -57,6 +58,7 @@ impl Display for UserCloudConfig { /// Provide the generic interface for the user cloud service /// The user cloud service is responsible for the user authentication and user profile management +#[allow(unused_variables)] pub trait UserCloudService: Send + Sync + 'static { /// Sign up a new account. /// The type of the params is defined the this trait's implementation. @@ -98,13 +100,33 @@ pub trait UserCloudService: Send + Sync + 'static { &self, user_email: String, workspace_id: String, - ) -> FutureResult<(), Error>; + ) -> FutureResult<(), Error> { + FutureResult::new(async { Ok(()) }) + } fn remove_workspace_member( &self, user_email: String, workspace_id: String, - ) -> FutureResult<(), Error>; + ) -> FutureResult<(), Error> { + FutureResult::new(async { Ok(()) }) + } + + fn update_workspace_member( + &self, + user_email: String, + workspace_id: String, + role: Role, + ) -> FutureResult<(), Error> { + FutureResult::new(async { Ok(()) }) + } + + fn get_workspace_members( + &self, + workspace_id: String, + ) -> FutureResult, Error> { + FutureResult::new(async { Ok(vec![]) }) + } fn get_user_awareness_updates(&self, uid: i64) -> FutureResult>, Error>; diff --git a/frontend/rust-lib/flowy-user-deps/src/entities.rs b/frontend/rust-lib/flowy-user-deps/src/entities.rs index e94cb6fa1f..beda5f548c 100644 --- a/frontend/rust-lib/flowy-user-deps/src/entities.rs +++ b/frontend/rust-lib/flowy-user-deps/src/entities.rs @@ -377,3 +377,16 @@ pub enum UserTokenState { Refresh { token: String }, Invalid, } + +#[derive(Clone, Debug)] +pub enum Role { + Owner, + Member, + Guest, +} + +pub struct WorkspaceMember { + pub email: String, + pub role: Role, + pub name: String, +} diff --git a/frontend/rust-lib/flowy-user/src/entities/mod.rs b/frontend/rust-lib/flowy-user/src/entities/mod.rs index 9568679078..a81c8c27cb 100644 --- a/frontend/rust-lib/flowy-user/src/entities/mod.rs +++ b/frontend/rust-lib/flowy-user/src/entities/mod.rs @@ -1,8 +1,11 @@ +use validator::ValidationError; + pub use auth::*; pub use realtime::*; pub use reminder::*; pub use user_profile::*; pub use user_setting::*; +pub use workspace_member::*; pub mod auth; pub mod date_time; @@ -11,3 +14,11 @@ pub mod realtime; mod reminder; mod user_profile; mod user_setting; +mod workspace_member; + +pub fn required_not_empty_str(s: &str) -> Result<(), ValidationError> { + if s.is_empty() { + return Err(ValidationError::new("should not be empty string")); + } + Ok(()) +} diff --git a/frontend/rust-lib/flowy-user/src/entities/parser/mod.rs b/frontend/rust-lib/flowy-user/src/entities/parser/mod.rs index 814f8b81da..ead09d3d02 100644 --- a/frontend/rust-lib/flowy-user/src/entities/parser/mod.rs +++ b/frontend/rust-lib/flowy-user/src/entities/parser/mod.rs @@ -1,3 +1,5 @@ +use validator::ValidationError; + pub use user_email::*; pub use user_icon::*; pub use user_id::*; @@ -14,3 +16,10 @@ mod user_name; mod user_openai_key; mod user_password; mod user_stability_ai_key; + +pub fn validate_not_empty_str(s: &str) -> Result<(), ValidationError> { + if s.is_empty() { + return Err(ValidationError::new("should not be empty string")); + } + Ok(()) +} diff --git a/frontend/rust-lib/flowy-user/src/entities/user_profile.rs b/frontend/rust-lib/flowy-user/src/entities/user_profile.rs index fb2907fcc7..2ee46aaaa2 100644 --- a/frontend/rust-lib/flowy-user/src/entities/user_profile.rs +++ b/frontend/rust-lib/flowy-user/src/entities/user_profile.rs @@ -235,24 +235,6 @@ impl From for UserWorkspacePB { } } -#[derive(ProtoBuf, Default)] -pub struct AddWorkspaceUserPB { - #[pb(index = 1)] - pub email: String, - - #[pb(index = 2)] - pub workspace_id: String, -} - -#[derive(ProtoBuf, Default)] -pub struct RemoveWorkspaceUserPB { - #[pb(index = 1)] - pub email: String, - - #[pb(index = 2)] - pub workspace_id: String, -} - #[derive(ProtoBuf, Default, Clone)] pub struct RepeatedHistoricalUserPB { #[pb(index = 1)] diff --git a/frontend/rust-lib/flowy-user/src/entities/workspace_member.rs b/frontend/rust-lib/flowy-user/src/entities/workspace_member.rs new file mode 100644 index 0000000000..d94848c588 --- /dev/null +++ b/frontend/rust-lib/flowy-user/src/entities/workspace_member.rs @@ -0,0 +1,105 @@ +use validator::Validate; + +use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; +use flowy_user_deps::entities::{Role, WorkspaceMember}; + +use crate::entities::required_not_empty_str; + +#[derive(ProtoBuf, Default, Clone)] +pub struct WorkspaceMemberPB { + #[pb(index = 1)] + pub email: String, + + #[pb(index = 2)] + pub name: String, + + #[pb(index = 3)] + pub role: AFRolePB, +} + +impl From for WorkspaceMemberPB { + fn from(value: WorkspaceMember) -> Self { + Self { + email: value.email, + name: value.name, + role: value.role.into(), + } + } +} + +#[derive(ProtoBuf, Default, Clone)] +pub struct RepeatedWorkspaceMemberPB { + #[pb(index = 1)] + pub items: Vec, +} + +#[derive(ProtoBuf, Default, Clone, Validate)] +pub struct AddWorkspaceMemberPB { + #[pb(index = 1)] + #[validate(custom = "required_not_empty_str")] + pub workspace_id: String, + + #[pb(index = 2)] + #[validate(email)] + pub email: String, +} + +#[derive(ProtoBuf, Default, Clone, Validate)] +pub struct QueryWorkspacePB { + #[pb(index = 1)] + #[validate(custom = "required_not_empty_str")] + pub workspace_id: String, +} + +#[derive(ProtoBuf, Default, Clone, Validate)] +pub struct RemoveWorkspaceMemberPB { + #[pb(index = 1)] + #[validate(custom = "required_not_empty_str")] + pub workspace_id: String, + + #[pb(index = 2)] + #[validate(email)] + pub email: String, +} + +#[derive(ProtoBuf, Default, Clone, Validate)] +pub struct UpdateWorkspaceMemberPB { + #[pb(index = 1)] + #[validate(custom = "required_not_empty_str")] + pub workspace_id: String, + + #[pb(index = 2)] + #[validate(email)] + pub email: String, + + #[pb(index = 3)] + pub role: AFRolePB, +} + +#[derive(ProtoBuf_Enum, Clone, Default)] +pub enum AFRolePB { + Owner = 0, + Member = 1, + #[default] + Guest = 2, +} + +impl From for Role { + fn from(value: AFRolePB) -> Self { + match value { + AFRolePB::Owner => Role::Owner, + AFRolePB::Member => Role::Member, + AFRolePB::Guest => Role::Guest, + } + } +} + +impl From for AFRolePB { + fn from(value: Role) -> Self { + match value { + Role::Owner => AFRolePB::Owner, + Role::Member => AFRolePB::Member, + Role::Guest => AFRolePB::Guest, + } + } +} diff --git a/frontend/rust-lib/flowy-user/src/event_handler.rs b/frontend/rust-lib/flowy-user/src/event_handler.rs index 80dcd98fef..e83320b219 100644 --- a/frontend/rust-lib/flowy-user/src/event_handler.rs +++ b/frontend/rust-lib/flowy-user/src/event_handler.rs @@ -445,32 +445,6 @@ pub async fn open_workspace_handler( Ok(()) } -#[tracing::instrument(level = "debug", skip(data, manager), err)] -pub async fn add_user_to_workspace_handler( - data: AFPluginData, - manager: AFPluginState>, -) -> Result<(), FlowyError> { - let manager = upgrade_manager(manager)?; - let params = data.into_inner(); - manager - .add_user_to_workspace(params.email, params.workspace_id) - .await?; - Ok(()) -} - -#[tracing::instrument(level = "debug", skip(data, manager), err)] -pub async fn remove_user_from_workspace_handler( - data: AFPluginData, - manager: AFPluginState>, -) -> Result<(), FlowyError> { - let manager = upgrade_manager(manager)?; - let params = data.into_inner(); - manager - .remove_user_to_workspace(params.email, params.workspace_id) - .await?; - Ok(()) -} - #[tracing::instrument(level = "debug", skip(data, manager), err)] pub async fn update_network_state_handler( data: AFPluginData, @@ -591,3 +565,58 @@ pub async fn update_reminder_event_handler( manager.update_reminder(params).await?; Ok(()) } + +#[tracing::instrument(level = "debug", skip_all, err)] +pub async fn add_workspace_member_handler( + data: AFPluginData, + manager: AFPluginState>, +) -> Result<(), FlowyError> { + let data = data.validate()?.into_inner(); + let manager = upgrade_manager(manager)?; + manager + .add_workspace_member(data.email, data.workspace_id) + .await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip_all, err)] +pub async fn delete_workspace_member_handler( + data: AFPluginData, + manager: AFPluginState>, +) -> Result<(), FlowyError> { + let data = data.validate()?.into_inner(); + let manager = upgrade_manager(manager)?; + manager + .remove_workspace_member(data.email, data.workspace_id) + .await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip_all, err)] +pub async fn get_workspace_member_handler( + data: AFPluginData, + manager: AFPluginState>, +) -> DataResult { + let data = data.validate()?.into_inner(); + let manager = upgrade_manager(manager)?; + let members = manager + .get_workspace_members(data.workspace_id) + .await? + .into_iter() + .map(WorkspaceMemberPB::from) + .collect(); + data_result_ok(RepeatedWorkspaceMemberPB { items: members }) +} + +#[tracing::instrument(level = "debug", skip_all, err)] +pub async fn update_workspace_member_handler( + data: AFPluginData, + manager: AFPluginState>, +) -> Result<(), FlowyError> { + let data = data.validate()?.into_inner(); + let manager = upgrade_manager(manager)?; + manager + .update_workspace_member(data.email, data.workspace_id, data.role.into()) + .await?; + Ok(()) +} diff --git a/frontend/rust-lib/flowy-user/src/event_map.rs b/frontend/rust-lib/flowy-user/src/event_map.rs index 40ade230e2..93bca64030 100644 --- a/frontend/rust-lib/flowy-user/src/event_map.rs +++ b/frontend/rust-lib/flowy-user/src/event_map.rs @@ -15,6 +15,7 @@ use crate::errors::FlowyError; use crate::event_handler::*; use crate::manager::UserManager; +#[rustfmt::skip] pub fn init(user_session: Weak) -> AFPlugin { let store_preferences = user_session .upgrade() @@ -39,20 +40,9 @@ pub fn init(user_session: Weak) -> AFPlugin { .event(UserEvent::CheckEncryptionSign, check_encrypt_secret_handler) .event(UserEvent::OauthSignIn, oauth_handler) .event(UserEvent::GetSignInURL, get_sign_in_url_handler) - .event( - UserEvent::GetOauthURLWithProvider, - sign_in_with_provider_handler, - ) - .event( - UserEvent::GetAllUserWorkspaces, - get_all_user_workspace_handler, - ) + .event(UserEvent::GetOauthURLWithProvider, sign_in_with_provider_handler) + .event(UserEvent::GetAllUserWorkspaces, get_all_user_workspace_handler) .event(UserEvent::OpenWorkspace, open_workspace_handler) - .event(UserEvent::AddUserToWorkspace, add_user_to_workspace_handler) - .event( - UserEvent::RemoveUserToWorkspace, - remove_user_from_workspace_handler, - ) .event(UserEvent::UpdateNetworkState, update_network_state_handler) .event(UserEvent::GetHistoricalUsers, get_historical_users_handler) .event(UserEvent::OpenHistoricalUser, open_historical_users_handler) @@ -64,14 +54,142 @@ pub fn init(user_session: Weak) -> AFPlugin { .event(UserEvent::ResetWorkspace, reset_workspace_handler) .event(UserEvent::SetDateTimeSettings, set_date_time_settings) .event(UserEvent::GetDateTimeSettings, get_date_time_settings) - .event( - UserEvent::SetNotificationSettings, - set_notification_settings, - ) - .event( - UserEvent::GetNotificationSettings, - get_notification_settings, - ) + .event(UserEvent::SetNotificationSettings, set_notification_settings) + .event(UserEvent::GetNotificationSettings, get_notification_settings) + // Workspace member + .event(UserEvent::AddWorkspaceMember, add_workspace_member_handler) + .event(UserEvent::RemoveWorkspaceMember, delete_workspace_member_handler) + .event(UserEvent::GetWorkspaceMember, get_workspace_member_handler) + .event(UserEvent::UpdateWorkspaceMember, update_workspace_member_handler,) +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] +#[event_err = "FlowyError"] +pub enum UserEvent { + /// Only use when the [AuthType] is Local or SelfHosted + /// Logging into an account using a register email and password + #[event(input = "SignInPayloadPB", output = "UserProfilePB")] + SignIn = 0, + + /// Only use when the [AuthType] is Local or SelfHosted + /// Creating a new account + #[event(input = "SignUpPayloadPB", output = "UserProfilePB")] + SignUp = 1, + + /// Logging out fo an account + #[event()] + SignOut = 2, + + /// Update the user information + #[event(input = "UpdateUserProfilePayloadPB")] + UpdateUserProfile = 3, + + /// Get the user information + #[event(output = "UserProfilePB")] + GetUserProfile = 4, + + /// Initialize resources for the current user after launching the application + /// + #[event()] + InitUser = 6, + + /// Change the visual elements of the interface, such as theme, font and more + #[event(input = "AppearanceSettingsPB")] + SetAppearanceSetting = 7, + + /// Get the appearance setting + #[event(output = "AppearanceSettingsPB")] + GetAppearanceSetting = 8, + + /// Get the settings of the user, such as the user storage folder + #[event(output = "UserSettingPB")] + GetUserSetting = 9, + + #[event(input = "OauthSignInPB", output = "UserProfilePB")] + OauthSignIn = 10, + + /// Get the OAuth callback url + /// Only use when the [AuthType] is AFCloud + #[event(input = "SignInUrlPayloadPB", output = "SignInUrlPB")] + GetSignInURL = 11, + + #[event(input = "OauthProviderPB", output = "OauthProviderDataPB")] + GetOauthURLWithProvider = 12, + + #[event(input = "UpdateCloudConfigPB")] + SetCloudConfig = 13, + + #[event(output = "UserCloudConfigPB")] + GetCloudConfig = 14, + + #[event(input = "UserSecretPB")] + SetEncryptionSecret = 15, + + #[event(output = "UserEncryptionConfigurationPB")] + CheckEncryptionSign = 16, + + /// Return the all the workspaces of the user + #[event()] + GetAllUserWorkspaces = 20, + + #[event(input = "UserWorkspacePB")] + OpenWorkspace = 21, + + #[event(input = "NetworkStatePB")] + UpdateNetworkState = 24, + + #[event(output = "RepeatedHistoricalUserPB")] + GetHistoricalUsers = 25, + + #[event(input = "HistoricalUserPB")] + OpenHistoricalUser = 26, + + /// Push a realtime event to the user. Currently, the realtime event + /// is only used when the auth type is: [AuthType::Supabase]. + /// + #[event(input = "RealtimePayloadPB")] + PushRealtimeEvent = 27, + + #[event(input = "ReminderPB")] + CreateReminder = 28, + + #[event(output = "RepeatedReminderPB")] + GetAllReminders = 29, + + #[event(input = "ReminderIdentifierPB")] + RemoveReminder = 30, + + #[event(input = "ReminderPB")] + UpdateReminder = 31, + + #[event(input = "ResetWorkspacePB")] + ResetWorkspace = 32, + + /// Change the Date/Time formats globally + #[event(input = "DateTimeSettingsPB")] + SetDateTimeSettings = 33, + + /// Retrieve the Date/Time formats + #[event(output = "DateTimeSettingsPB")] + GetDateTimeSettings = 34, + + #[event(input = "NotificationSettingsPB")] + SetNotificationSettings = 35, + + #[event(output = "NotificationSettingsPB")] + GetNotificationSettings = 36, + + #[event(output = "AddWorkspaceMemberPB")] + AddWorkspaceMember = 37, + + #[event(output = "RemoveWorkspaceMemberPB")] + RemoveWorkspaceMember = 38, + + #[event(output = "UpdateWorkspaceMemberPB")] + UpdateWorkspaceMember = 39, + + #[event(output = "QueryWorkspacePB")] + GetWorkspaceMember = 40, } pub struct SignUpContext { @@ -205,126 +323,3 @@ impl UserStatusCallback for DefaultUserStatusCallback { to_fut(async { Ok(()) }) } } - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] -#[event_err = "FlowyError"] -pub enum UserEvent { - /// Only use when the [AuthType] is Local or SelfHosted - /// Logging into an account using a register email and password - #[event(input = "SignInPayloadPB", output = "UserProfilePB")] - SignIn = 0, - - /// Only use when the [AuthType] is Local or SelfHosted - /// Creating a new account - #[event(input = "SignUpPayloadPB", output = "UserProfilePB")] - SignUp = 1, - - /// Logging out fo an account - #[event()] - SignOut = 2, - - /// Update the user information - #[event(input = "UpdateUserProfilePayloadPB")] - UpdateUserProfile = 3, - - /// Get the user information - #[event(output = "UserProfilePB")] - GetUserProfile = 4, - - /// Initialize resources for the current user after launching the application - /// - #[event()] - InitUser = 6, - - /// Change the visual elements of the interface, such as theme, font and more - #[event(input = "AppearanceSettingsPB")] - SetAppearanceSetting = 7, - - /// Get the appearance setting - #[event(output = "AppearanceSettingsPB")] - GetAppearanceSetting = 8, - - /// Get the settings of the user, such as the user storage folder - #[event(output = "UserSettingPB")] - GetUserSetting = 9, - - #[event(input = "OauthSignInPB", output = "UserProfilePB")] - OauthSignIn = 10, - - /// Get the OAuth callback url - /// Only use when the [AuthType] is AFCloud - #[event(input = "SignInUrlPayloadPB", output = "SignInUrlPB")] - GetSignInURL = 11, - - #[event(input = "OauthProviderPB", output = "OauthProviderDataPB")] - GetOauthURLWithProvider = 12, - - #[event(input = "UpdateCloudConfigPB")] - SetCloudConfig = 13, - - #[event(output = "UserCloudConfigPB")] - GetCloudConfig = 14, - - #[event(input = "UserSecretPB")] - SetEncryptionSecret = 15, - - #[event(output = "UserEncryptionConfigurationPB")] - CheckEncryptionSign = 16, - - /// Return the all the workspaces of the user - #[event()] - GetAllUserWorkspaces = 20, - - #[event(input = "UserWorkspacePB")] - OpenWorkspace = 21, - - #[event(input = "AddWorkspaceUserPB")] - AddUserToWorkspace = 22, - - #[event(input = "RemoveWorkspaceUserPB")] - RemoveUserToWorkspace = 23, - - #[event(input = "NetworkStatePB")] - UpdateNetworkState = 24, - - #[event(output = "RepeatedHistoricalUserPB")] - GetHistoricalUsers = 25, - - #[event(input = "HistoricalUserPB")] - OpenHistoricalUser = 26, - - /// Push a realtime event to the user. Currently, the realtime event - /// is only used when the auth type is: [AuthType::Supabase]. - /// - #[event(input = "RealtimePayloadPB")] - PushRealtimeEvent = 27, - - #[event(input = "ReminderPB")] - CreateReminder = 28, - - #[event(output = "RepeatedReminderPB")] - GetAllReminders = 29, - - #[event(input = "ReminderIdentifierPB")] - RemoveReminder = 30, - - #[event(input = "ReminderPB")] - UpdateReminder = 31, - - #[event(input = "ResetWorkspacePB")] - ResetWorkspace = 32, - - /// Change the Date/Time formats globally - #[event(input = "DateTimeSettingsPB")] - SetDateTimeSettings = 33, - - /// Retrieve the Date/Time formats - #[event(output = "DateTimeSettingsPB")] - GetDateTimeSettings = 34, - - #[event(input = "NotificationSettingsPB")] - SetNotificationSettings = 35, - - #[event(output = "NotificationSettingsPB")] - GetNotificationSettings = 36, -} diff --git a/frontend/rust-lib/flowy-user/src/services/user_workspace.rs b/frontend/rust-lib/flowy-user/src/services/user_workspace.rs index 2684f31bf8..6002556d9c 100644 --- a/frontend/rust-lib/flowy-user/src/services/user_workspace.rs +++ b/frontend/rust-lib/flowy-user/src/services/user_workspace.rs @@ -6,7 +6,7 @@ use collab_entity::{CollabObject, CollabType}; use flowy_error::{FlowyError, FlowyResult}; use flowy_sqlite::schema::user_workspace_table; use flowy_sqlite::{query_dsl::*, ConnectionPool, ExpressionMethods}; -use flowy_user_deps::entities::UserWorkspace; +use flowy_user_deps::entities::{Role, UserWorkspace, WorkspaceMember}; use crate::entities::{RepeatedUserWorkspacePB, ResetWorkspacePB}; use crate::manager::UserManager; @@ -30,28 +30,54 @@ impl UserManager { Ok(()) } - pub async fn add_user_to_workspace( + pub async fn add_workspace_member( &self, user_email: String, - to_workspace_id: String, + workspace_id: String, ) -> FlowyResult<()> { self .cloud_services .get_user_service()? - .add_workspace_member(user_email, to_workspace_id) + .add_workspace_member(user_email, workspace_id) .await?; Ok(()) } - pub async fn remove_user_to_workspace( + pub async fn remove_workspace_member( &self, user_email: String, - from_workspace_id: String, + workspace_id: String, ) -> FlowyResult<()> { self .cloud_services .get_user_service()? - .remove_workspace_member(user_email, from_workspace_id) + .remove_workspace_member(user_email, workspace_id) + .await?; + Ok(()) + } + + pub async fn get_workspace_members( + &self, + workspace_id: String, + ) -> FlowyResult> { + let members = self + .cloud_services + .get_user_service()? + .get_workspace_members(workspace_id) + .await?; + Ok(members) + } + + pub async fn update_workspace_member( + &self, + user_email: String, + workspace_id: String, + role: Role, + ) -> FlowyResult<()> { + self + .cloud_services + .get_user_service()? + .update_workspace_member(user_email, workspace_id, role) .await?; Ok(()) } diff --git a/frontend/rust-lib/lib-dispatch/Cargo.toml b/frontend/rust-lib/lib-dispatch/Cargo.toml index e3411caf55..99d22d7448 100644 --- a/frontend/rust-lib/lib-dispatch/Cargo.toml +++ b/frontend/rust-lib/lib-dispatch/Cargo.toml @@ -21,6 +21,7 @@ derivative = "2.2.0" serde_json = {version = "1.0", optional = true } serde = { version = "1.0", features = ["derive"], optional = true } serde_repr = { version = "0.1", optional = true } +validator = "0.16.1" #optional crate bincode = { version = "1.3", optional = true} diff --git a/frontend/rust-lib/lib-dispatch/src/data.rs b/frontend/rust-lib/lib-dispatch/src/data.rs index 17c50da12a..9cb028ad64 100644 --- a/frontend/rust-lib/lib-dispatch/src/data.rs +++ b/frontend/rust-lib/lib-dispatch/src/data.rs @@ -2,6 +2,7 @@ use std::fmt::{Debug, Formatter}; use std::ops; use bytes::Bytes; +use validator::ValidationErrors; use crate::{ byte_trait::*, @@ -11,6 +12,12 @@ use crate::{ util::ready::{ready, Ready}, }; +pub trait AFPluginDataValidator { + fn validate(self) -> Result + where + Self: Sized; +} + pub struct AFPluginData(pub T); impl AFPluginData { @@ -27,6 +34,16 @@ impl ops::Deref for AFPluginData { } } +impl AFPluginDataValidator for AFPluginData +where + T: validator::Validate, +{ + fn validate(self) -> Result { + self.0.validate()?; + Ok(self) + } +} + impl ops::DerefMut for AFPluginData { fn deref_mut(&mut self) -> &mut T { &mut self.0