mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: cloud storage test (#2663)
* chore: show default user name * chore: update * feat: change collab storage type after auth type changed * chore: reload folder * chore: initial the group controller if need * chore: update patch * chore: update patch ref
This commit is contained in:
parent
09d61c79c9
commit
012b6c0066
@ -46,7 +46,8 @@ class MenuUser extends StatelessWidget {
|
||||
String iconUrl = context.read<MenuUserBloc>().state.userProfile.iconUrl;
|
||||
if (iconUrl.isEmpty) {
|
||||
iconUrl = defaultUserAvatar;
|
||||
final String name = context.read<MenuUserBloc>().state.userProfile.name;
|
||||
final String name =
|
||||
userName(context.read<MenuUserBloc>().state.userProfile);
|
||||
final Color color = ColorGenerator().generateColorFromString(name);
|
||||
const initialsCount = 2;
|
||||
// Taking the first letters of the name components and limiting to 2 elements
|
||||
@ -85,10 +86,7 @@ class MenuUser extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _renderUserName(BuildContext context) {
|
||||
String name = context.read<MenuUserBloc>().state.userProfile.name;
|
||||
if (name.isEmpty) {
|
||||
name = context.read<MenuUserBloc>().state.userProfile.email;
|
||||
}
|
||||
String name = userName(context.read<MenuUserBloc>().state.userProfile);
|
||||
return FlowyText.medium(
|
||||
name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
@ -119,13 +117,13 @@ class MenuUser extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
//ToDo: when the user is allowed to create another workspace,
|
||||
//we get the below block back
|
||||
// Widget _renderDropButton(BuildContext context) {
|
||||
// return FlowyDropdownButton(
|
||||
// onPressed: () {
|
||||
// debugPrint('show user profile');
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
|
||||
/// Return the user name, if the user name is empty, return the default user name.
|
||||
String userName(UserProfilePB userProfile) {
|
||||
String name = userProfile.name;
|
||||
if (name.isEmpty) {
|
||||
name = LocaleKeys.defaultUsername.tr();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
25
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
25
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -99,7 +99,7 @@ checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
[[package]]
|
||||
name = "appflowy-integrate"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bb6ab1#bb6ab1bada7b045e0edb2652017cd95795eb1309"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -108,6 +108,7 @@ dependencies = [
|
||||
"collab-folder",
|
||||
"collab-persistence",
|
||||
"collab-plugins",
|
||||
"parking_lot 0.12.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
@ -1023,7 +1024,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bb6ab1#bb6ab1bada7b045e0edb2652017cd95795eb1309"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -1032,6 +1033,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"y-sync",
|
||||
"yrs",
|
||||
@ -1040,7 +1042,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-client-ws"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bb6ab1#bb6ab1bada7b045e0edb2652017cd95795eb1309"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab-sync",
|
||||
@ -1058,10 +1060,11 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bb6ab1#bb6ab1bada7b045e0edb2652017cd95795eb1309"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"base64 0.21.0",
|
||||
"chrono",
|
||||
"collab",
|
||||
"collab-derive",
|
||||
@ -1083,7 +1086,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bb6ab1#bb6ab1bada7b045e0edb2652017cd95795eb1309"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1095,7 +1098,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bb6ab1#bb6ab1bada7b045e0edb2652017cd95795eb1309"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1112,7 +1115,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bb6ab1#bb6ab1bada7b045e0edb2652017cd95795eb1309"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1124,13 +1127,14 @@ dependencies = [
|
||||
"serde_repr",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bb6ab1#bb6ab1bada7b045e0edb2652017cd95795eb1309"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
@ -1150,7 +1154,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bb6ab1#bb6ab1bada7b045e0edb2652017cd95795eb1309"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1180,7 +1184,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-sync"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=bb6ab1#bb6ab1bada7b045e0edb2652017cd95795eb1309"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab",
|
||||
@ -1963,6 +1967,7 @@ dependencies = [
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
"unicode-segmentation",
|
||||
"uuid",
|
||||
|
@ -34,12 +34,12 @@ default = ["custom-protocol"]
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
||||
[patch.crates-io]
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "173661" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "173661" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "173661" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "173661" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "173661" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "173661" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "26438c" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "26438c" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "26438c" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "26438c" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "26438c" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "26438c" }
|
||||
|
||||
#collab = { path = "../../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../../AppFlowy-Collab/collab-folder" }
|
||||
|
25
frontend/rust-lib/Cargo.lock
generated
25
frontend/rust-lib/Cargo.lock
generated
@ -85,7 +85,7 @@ checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
|
||||
[[package]]
|
||||
name = "appflowy-integrate"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=26438c#26438c77de5d4cad723370380da19763da536ac1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -94,6 +94,7 @@ dependencies = [
|
||||
"collab-folder",
|
||||
"collab-persistence",
|
||||
"collab-plugins",
|
||||
"parking_lot 0.12.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
@ -886,7 +887,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=26438c#26438c77de5d4cad723370380da19763da536ac1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -895,6 +896,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"y-sync",
|
||||
"yrs",
|
||||
@ -903,7 +905,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-client-ws"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=26438c#26438c77de5d4cad723370380da19763da536ac1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab-sync",
|
||||
@ -921,10 +923,11 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=26438c#26438c77de5d4cad723370380da19763da536ac1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"base64 0.21.0",
|
||||
"chrono",
|
||||
"collab",
|
||||
"collab-derive",
|
||||
@ -946,7 +949,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=26438c#26438c77de5d4cad723370380da19763da536ac1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -958,7 +961,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=26438c#26438c77de5d4cad723370380da19763da536ac1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -975,7 +978,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=26438c#26438c77de5d4cad723370380da19763da536ac1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -987,13 +990,14 @@ dependencies = [
|
||||
"serde_repr",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=26438c#26438c77de5d4cad723370380da19763da536ac1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
@ -1013,7 +1017,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=26438c#26438c77de5d4cad723370380da19763da536ac1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1043,7 +1047,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-sync"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=173661#173661cc07cc78f4251983fcf7594533ba63bb5d"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=26438c#26438c77de5d4cad723370380da19763da536ac1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab",
|
||||
@ -1748,6 +1752,7 @@ dependencies = [
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
"unicode-segmentation",
|
||||
"uuid",
|
||||
|
@ -33,11 +33,11 @@ opt-level = 3
|
||||
incremental = false
|
||||
|
||||
[patch.crates-io]
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "173661" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "173661" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "173661" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "173661" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "173661" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "26438c" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "26438c" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "26438c" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "26438c" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "26438c" }
|
||||
|
||||
#collab = { path = "../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../AppFlowy-Collab/collab-folder" }
|
||||
|
@ -99,7 +99,7 @@ impl FolderOperationHandler for DocumentFolderOperation {
|
||||
let document = manager.get_document(view_id)?;
|
||||
let data: DocumentDataPB = DocumentDataWrapper(document.lock().get_document()?).into();
|
||||
let data_bytes = data.into_bytes().map_err(|_| FlowyError::invalid_data())?;
|
||||
Ok(Bytes::from(data_bytes))
|
||||
Ok(data_bytes)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -80,12 +80,16 @@ impl Default for AppFlowyServerProvider {
|
||||
}
|
||||
|
||||
impl UserCloudServiceProvider for AppFlowyServerProvider {
|
||||
/// When user login, the provider type is set by the [AuthType].
|
||||
/// When user login, the provider type is set by the [AuthType] and save to disk for next use.
|
||||
///
|
||||
/// Each [AuthType] has a corresponding [ServerProviderType]. The [ServerProviderType] is used
|
||||
/// to create a new [AppFlowyServer] if it doesn't exist. Once the [ServerProviderType] is set,
|
||||
/// it will be used when user open the app again.
|
||||
///
|
||||
fn set_auth_type(&self, auth_type: AuthType) {
|
||||
let provider_type: ServerProviderType = auth_type.into();
|
||||
*self.provider_type.write() = provider_type.clone();
|
||||
|
||||
match KV::set_object(SERVER_PROVIDER_TYPE_KEY, provider_type.clone()) {
|
||||
Ok(_) => tracing::trace!("Update server provider type to: {:?}", provider_type),
|
||||
Err(e) => {
|
||||
@ -96,9 +100,12 @@ impl UserCloudServiceProvider for AppFlowyServerProvider {
|
||||
|
||||
/// Returns the [UserAuthService] base on the current [ServerProviderType].
|
||||
/// Creates a new [AppFlowyServer] if it doesn't exist.
|
||||
fn get_auth_service(&self, auth_type: &AuthType) -> Result<Arc<dyn UserAuthService>, FlowyError> {
|
||||
let provider_type: ServerProviderType = auth_type.into();
|
||||
Ok(self.get_provider(&provider_type)?.user_service())
|
||||
fn get_auth_service(&self) -> Result<Arc<dyn UserAuthService>, FlowyError> {
|
||||
Ok(
|
||||
self
|
||||
.get_provider(&self.provider_type.read())?
|
||||
.user_service(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +136,6 @@ fn server_from_auth_type(
|
||||
Ok(server)
|
||||
},
|
||||
ServerProviderType::Supabase => {
|
||||
// init the SupabaseServerConfiguration from the environment variables.
|
||||
let config = SupabaseConfiguration::from_env()?;
|
||||
let server = Arc::new(SupabaseServer::new(config));
|
||||
Ok(server)
|
||||
|
@ -21,7 +21,7 @@ use flowy_sqlite::kv::KV;
|
||||
use flowy_task::{TaskDispatcher, TaskRunner};
|
||||
use flowy_user::entities::UserProfile;
|
||||
use flowy_user::event_map::{UserCloudServiceProvider, UserStatusCallback};
|
||||
use flowy_user::services::{UserSession, UserSessionConfig};
|
||||
use flowy_user::services::{AuthType, UserSession, UserSessionConfig};
|
||||
use lib_dispatch::prelude::*;
|
||||
use lib_dispatch::runtime::tokio_default_runtime;
|
||||
use lib_infra::future::{to_fut, Fut};
|
||||
@ -143,9 +143,9 @@ impl AppFlowyCore {
|
||||
let server_provider = Arc::new(AppFlowyServerProvider::new());
|
||||
/// The shared collab builder is used to build the [Collab] instance. The plugins will be loaded
|
||||
/// on demand based on the [CollabPluginConfig].
|
||||
let cloud_storage_type =
|
||||
collab_storage_type_from_server_provider_type(&server_provider.provider_type());
|
||||
let collab_builder = Arc::new(AppFlowyCollabBuilder::new(cloud_storage_type));
|
||||
let collab_builder = Arc::new(AppFlowyCollabBuilder::new(
|
||||
server_provider.provider_type().into(),
|
||||
));
|
||||
|
||||
let (user_session, folder_manager, server_provider, database_manager, document_manager2) =
|
||||
runtime.block_on(async {
|
||||
@ -181,19 +181,16 @@ impl AppFlowyCore {
|
||||
)
|
||||
});
|
||||
|
||||
let user_status_listener = UserStatusListener {
|
||||
let user_status_listener = UserStatusCallbackImpl {
|
||||
collab_builder,
|
||||
folder_manager: folder_manager.clone(),
|
||||
database_manager: database_manager.clone(),
|
||||
config: config.clone(),
|
||||
};
|
||||
|
||||
let user_status_callback = UserStatusCallbackImpl {
|
||||
listener: Arc::new(user_status_listener),
|
||||
};
|
||||
|
||||
let cloned_user_session = user_session.clone();
|
||||
runtime.block_on(async move {
|
||||
cloned_user_session.clone().init(user_status_callback).await;
|
||||
cloned_user_session.clone().init(user_status_listener).await;
|
||||
});
|
||||
|
||||
let event_dispatcher = Arc::new(AFPluginDispatcher::construct(runtime, || {
|
||||
@ -247,79 +244,71 @@ fn mk_user_session(
|
||||
Arc::new(UserSession::new(user_config, user_cloud_service_provider))
|
||||
}
|
||||
|
||||
struct UserStatusListener {
|
||||
struct UserStatusCallbackImpl {
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
folder_manager: Arc<Folder2Manager>,
|
||||
database_manager: Arc<DatabaseManager2>,
|
||||
#[allow(dead_code)]
|
||||
config: AppFlowyCoreConfig,
|
||||
}
|
||||
|
||||
impl UserStatusListener {
|
||||
async fn did_sign_in(&self, user_id: i64, workspace_id: &str) -> FlowyResult<()> {
|
||||
self
|
||||
.folder_manager
|
||||
.initialize(user_id, workspace_id)
|
||||
.await?;
|
||||
self.database_manager.initialize(user_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn did_sign_up(&self, user_profile: &UserProfile) -> FlowyResult<()> {
|
||||
self
|
||||
.folder_manager
|
||||
.initialize_with_new_user(
|
||||
user_profile.id,
|
||||
&user_profile.token,
|
||||
&user_profile.workspace_id,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self
|
||||
.database_manager
|
||||
.initialize_with_new_user(user_profile.id, &user_profile.token)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn did_expired(&self, _token: &str, user_id: i64) -> FlowyResult<()> {
|
||||
self.folder_manager.clear(user_id).await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct UserStatusCallbackImpl {
|
||||
listener: Arc<UserStatusListener>,
|
||||
}
|
||||
|
||||
impl UserStatusCallback for UserStatusCallbackImpl {
|
||||
fn auth_type_did_changed(&self, auth_type: AuthType) {
|
||||
let provider_type: ServerProviderType = auth_type.into();
|
||||
self
|
||||
.collab_builder
|
||||
.set_cloud_storage_type(provider_type.into());
|
||||
}
|
||||
|
||||
fn did_sign_in(&self, user_id: i64, workspace_id: &str) -> Fut<FlowyResult<()>> {
|
||||
let listener = self.listener.clone();
|
||||
let user_id = user_id.to_owned();
|
||||
let workspace_id = workspace_id.to_owned();
|
||||
to_fut(async move { listener.did_sign_in(user_id, &workspace_id).await })
|
||||
let folder_manager = self.folder_manager.clone();
|
||||
let database_manager = self.database_manager.clone();
|
||||
|
||||
to_fut(async move {
|
||||
folder_manager.initialize(user_id, &workspace_id).await?;
|
||||
database_manager.initialize(user_id).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn did_sign_up(&self, user_profile: &UserProfile) -> Fut<FlowyResult<()>> {
|
||||
let listener = self.listener.clone();
|
||||
let user_profile = user_profile.clone();
|
||||
to_fut(async move { listener.did_sign_up(&user_profile).await })
|
||||
let folder_manager = self.folder_manager.clone();
|
||||
let database_manager = self.database_manager.clone();
|
||||
to_fut(async move {
|
||||
folder_manager
|
||||
.initialize_with_new_user(
|
||||
user_profile.id,
|
||||
&user_profile.token,
|
||||
&user_profile.workspace_id,
|
||||
)
|
||||
.await?;
|
||||
|
||||
database_manager
|
||||
.initialize_with_new_user(user_profile.id, &user_profile.token)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn did_expired(&self, token: &str, user_id: i64) -> Fut<FlowyResult<()>> {
|
||||
let listener = self.listener.clone();
|
||||
let token = token.to_owned();
|
||||
let user_id = user_id.to_owned();
|
||||
to_fut(async move { listener.did_expired(&token, user_id).await })
|
||||
fn did_expired(&self, _token: &str, user_id: i64) -> Fut<FlowyResult<()>> {
|
||||
let folder_manager = self.folder_manager.clone();
|
||||
to_fut(async move {
|
||||
folder_manager.clear(user_id).await;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn collab_storage_type_from_server_provider_type(
|
||||
server_provider_type: &ServerProviderType,
|
||||
) -> CloudStorageType {
|
||||
match server_provider_type {
|
||||
ServerProviderType::Local => CloudStorageType::Local,
|
||||
ServerProviderType::SelfHosted => CloudStorageType::Local,
|
||||
ServerProviderType::Supabase => CloudStorageType::Supabase,
|
||||
impl From<ServerProviderType> for CloudStorageType {
|
||||
fn from(server_provider: ServerProviderType) -> Self {
|
||||
match server_provider {
|
||||
ServerProviderType::Local => CloudStorageType::Local,
|
||||
ServerProviderType::SelfHosted => CloudStorageType::Local,
|
||||
ServerProviderType::Supabase => CloudStorageType::Supabase,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use appflowy_integrate::{CollabPersistenceConfig, RocksCollabDB};
|
||||
use collab::core::collab::MutexCollab;
|
||||
use collab_database::database::DatabaseData;
|
||||
use collab_database::user::{UserDatabase as InnerUserDatabase, UserDatabaseCollabBuilder};
|
||||
use collab_database::user::{DatabaseCollabBuilder, UserDatabase as InnerUserDatabase};
|
||||
use collab_database::views::{CreateDatabaseParams, CreateViewParams};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::sync::RwLock;
|
||||
@ -183,7 +183,7 @@ impl DatabaseManager2 {
|
||||
match duplicated_view_id {
|
||||
None => {
|
||||
let params = CreateViewParams::new(database_id, target_view_id, name, layout.into());
|
||||
database.create_linked_view(params);
|
||||
database.create_linked_view(params)?;
|
||||
},
|
||||
Some(duplicated_view_id) => {
|
||||
database.duplicate_linked_view(&duplicated_view_id);
|
||||
@ -256,18 +256,27 @@ unsafe impl Send for UserDatabase {}
|
||||
|
||||
struct UserDatabaseCollabBuilderImpl(Arc<AppFlowyCollabBuilder>);
|
||||
|
||||
impl UserDatabaseCollabBuilder for UserDatabaseCollabBuilderImpl {
|
||||
fn build(&self, uid: i64, object_id: &str, db: Arc<RocksCollabDB>) -> Arc<MutexCollab> {
|
||||
self.0.build(uid, object_id, db)
|
||||
impl DatabaseCollabBuilder for UserDatabaseCollabBuilderImpl {
|
||||
fn build(
|
||||
&self,
|
||||
uid: i64,
|
||||
object_id: &str,
|
||||
object_name: &str,
|
||||
db: Arc<RocksCollabDB>,
|
||||
) -> Arc<MutexCollab> {
|
||||
self.0.build(uid, object_id, object_name, db)
|
||||
}
|
||||
|
||||
fn build_with_config(
|
||||
&self,
|
||||
uid: i64,
|
||||
object_id: &str,
|
||||
object_name: &str,
|
||||
db: Arc<RocksCollabDB>,
|
||||
config: &CollabPersistenceConfig,
|
||||
) -> Arc<MutexCollab> {
|
||||
self.0.build_with_config(uid, object_id, db, config)
|
||||
self
|
||||
.0
|
||||
.build_with_config(uid, object_id, object_name, db, config)
|
||||
}
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ impl<'a> CellBuilder<'a> {
|
||||
/// Build list of Cells from HashMap of cell string by field id.
|
||||
pub fn with_cells(cell_by_field_id: HashMap<String, String>, fields: &'a [Field]) -> Self {
|
||||
let field_maps = fields
|
||||
.into_iter()
|
||||
.iter()
|
||||
.map(|field| (field.id.clone(), field))
|
||||
.collect::<HashMap<String, &Field>>();
|
||||
|
||||
|
@ -574,9 +574,14 @@ impl DatabaseEditor {
|
||||
row_id: RowId,
|
||||
options: Vec<SelectOptionPB>,
|
||||
) -> FlowyResult<()> {
|
||||
let field = self.database.lock().fields.get_field(field_id).ok_or(
|
||||
FlowyError::record_not_found().context(format!("Field with id:{} not found", &field_id)),
|
||||
)?;
|
||||
let field = self
|
||||
.database
|
||||
.lock()
|
||||
.fields
|
||||
.get_field(field_id)
|
||||
.ok_or_else(|| {
|
||||
FlowyError::record_not_found().context(format!("Field with id:{} not found", &field_id))
|
||||
})?;
|
||||
debug_assert!(FieldType::from(field.field_type).is_select_option());
|
||||
|
||||
let mut type_option = select_type_option_from_field(&field)?;
|
||||
@ -670,9 +675,14 @@ impl DatabaseEditor {
|
||||
field_id: &str,
|
||||
changeset: ChecklistCellChangeset,
|
||||
) -> FlowyResult<()> {
|
||||
let field = self.database.lock().fields.get_field(field_id).ok_or(
|
||||
FlowyError::record_not_found().context(format!("Field with id:{} not found", &field_id)),
|
||||
)?;
|
||||
let field = self
|
||||
.database
|
||||
.lock()
|
||||
.fields
|
||||
.get_field(field_id)
|
||||
.ok_or_else(|| {
|
||||
FlowyError::record_not_found().context(format!("Field with id:{} not found", &field_id))
|
||||
})?;
|
||||
debug_assert!(FieldType::from(field.field_type).is_checklist());
|
||||
|
||||
self
|
||||
@ -684,7 +694,7 @@ impl DatabaseEditor {
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub async fn load_groups(&self, view_id: &str) -> FlowyResult<RepeatedGroupPB> {
|
||||
let view = self.database_views.get_view_editor(view_id).await?;
|
||||
let groups = view.v_load_groups().await?;
|
||||
let groups = view.v_load_groups().await.unwrap_or_default();
|
||||
Ok(RepeatedGroupPB { items: groups })
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ pub trait DatabaseViewData: Send + Sync + 'static {
|
||||
pub struct DatabaseViewEditor {
|
||||
pub view_id: String,
|
||||
delegate: Arc<dyn DatabaseViewData>,
|
||||
group_controller: Arc<RwLock<Box<dyn GroupController>>>,
|
||||
group_controller: Arc<RwLock<Option<Box<dyn GroupController>>>>,
|
||||
filter_controller: Arc<FilterController>,
|
||||
sort_controller: Arc<RwLock<SortController>>,
|
||||
pub notifier: DatabaseViewChangedNotifier,
|
||||
@ -192,10 +192,12 @@ impl DatabaseViewEditor {
|
||||
},
|
||||
Some(group_id) => {
|
||||
self
|
||||
.group_controller
|
||||
.write()
|
||||
.await
|
||||
.did_create_row(row, group_id);
|
||||
.mut_group_controller(|group_controller, _| {
|
||||
group_controller.did_create_row(row, group_id);
|
||||
Ok(())
|
||||
})
|
||||
.await;
|
||||
|
||||
let inserted_row = InsertedRowPB {
|
||||
row: RowPB::from(row),
|
||||
index: Some(index as i32),
|
||||
@ -347,22 +349,29 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
/// Only call once after database view editor initialized
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
pub async fn v_load_groups(&self) -> FlowyResult<Vec<GroupPB>> {
|
||||
pub async fn v_load_groups(&self) -> Option<Vec<GroupPB>> {
|
||||
let groups = self
|
||||
.group_controller
|
||||
.read()
|
||||
.await
|
||||
.as_ref()?
|
||||
.groups()
|
||||
.into_iter()
|
||||
.map(|group_data| GroupPB::from(group_data.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
tracing::trace!("Number of groups: {}", groups.len());
|
||||
Ok(groups)
|
||||
Some(groups)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
pub async fn v_get_group(&self, group_id: &str) -> FlowyResult<GroupPB> {
|
||||
match self.group_controller.read().await.get_group(group_id) {
|
||||
match self
|
||||
.group_controller
|
||||
.read()
|
||||
.await
|
||||
.as_ref()
|
||||
.and_then(|group| group.get_group(group_id))
|
||||
{
|
||||
None => Err(FlowyError::record_not_found().context("Can't find the group")),
|
||||
Some((_, group)) => Ok(GroupPB::from(group)),
|
||||
}
|
||||
@ -371,19 +380,22 @@ impl DatabaseViewEditor {
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub async fn v_move_group(&self, from_group: &str, to_group: &str) -> FlowyResult<()> {
|
||||
self
|
||||
.group_controller
|
||||
.write()
|
||||
.await
|
||||
.move_group(from_group, to_group)?;
|
||||
.mut_group_controller(|group_controller, _| group_controller.move_group(from_group, to_group))
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn group_id(&self) -> String {
|
||||
self.group_controller.read().await.field_id().to_string()
|
||||
pub async fn is_grouping_field(&self, field_id: &str) -> bool {
|
||||
match self.group_controller.read().await.as_ref() {
|
||||
Some(group_controller) => group_controller.field_id() == field_id,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when the user changes the grouping field
|
||||
pub async fn v_initialize_new_group(&self, field_id: &str) -> FlowyResult<()> {
|
||||
if self.group_controller.read().await.field_id() != field_id {
|
||||
let is_grouping_field = self.is_grouping_field(field_id).await;
|
||||
if !is_grouping_field {
|
||||
self.v_update_grouping_field(field_id).await?;
|
||||
|
||||
if let Some(view) = self.delegate.get_view_setting(&self.view_id).await {
|
||||
@ -400,10 +412,11 @@ impl DatabaseViewEditor {
|
||||
|
||||
pub async fn update_group_setting(&self, changeset: GroupSettingChangeset) -> FlowyResult<()> {
|
||||
self
|
||||
.group_controller
|
||||
.write()
|
||||
.await
|
||||
.apply_group_setting_changeset(changeset)
|
||||
.mut_group_controller(|group_controller, _| {
|
||||
group_controller.apply_group_setting_changeset(changeset)
|
||||
})
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn v_get_all_sorts(&self) -> Vec<Sort> {
|
||||
@ -631,10 +644,11 @@ impl DatabaseViewEditor {
|
||||
.await;
|
||||
|
||||
self
|
||||
.group_controller
|
||||
.write()
|
||||
.await
|
||||
.did_update_field_type_option(&field);
|
||||
.mut_group_controller(|group_controller, _| {
|
||||
group_controller.did_update_field_type_option(&field);
|
||||
Ok(())
|
||||
})
|
||||
.await;
|
||||
|
||||
if let Some(filter) = self
|
||||
.delegate
|
||||
@ -672,7 +686,7 @@ impl DatabaseViewEditor {
|
||||
.map(|group| GroupPB::from(group.clone()))
|
||||
.collect();
|
||||
|
||||
*self.group_controller.write().await = new_group_controller;
|
||||
*self.group_controller.write().await = Some(new_group_controller);
|
||||
let changeset = GroupChangesPB {
|
||||
view_id: self.view_id.clone(),
|
||||
initial_groups: new_groups,
|
||||
@ -804,13 +818,19 @@ impl DatabaseViewEditor {
|
||||
where
|
||||
F: FnOnce(&mut Box<dyn GroupController>, Arc<Field>) -> FlowyResult<T>,
|
||||
{
|
||||
let group_field_id = self.group_controller.read().await.field_id().to_owned();
|
||||
match self.delegate.get_field(&group_field_id).await {
|
||||
None => None,
|
||||
Some(field) => {
|
||||
let mut write_guard = self.group_controller.write().await;
|
||||
f(&mut write_guard, field).ok()
|
||||
},
|
||||
let group_field_id = self
|
||||
.group_controller
|
||||
.read()
|
||||
.await
|
||||
.as_ref()
|
||||
.map(|group| group.field_id().to_owned())?;
|
||||
let field = self.delegate.get_field(&group_field_id).await?;
|
||||
|
||||
let mut write_guard = self.group_controller.write().await;
|
||||
if let Some(group_controller) = &mut *write_guard {
|
||||
f(group_controller, field).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::RowId;
|
||||
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_error::FlowyResult;
|
||||
use lib_infra::future::{to_fut, Fut};
|
||||
|
||||
use crate::entities::FieldType;
|
||||
@ -35,13 +35,9 @@ pub async fn new_group_controller_with_field(
|
||||
pub async fn new_group_controller(
|
||||
view_id: String,
|
||||
delegate: Arc<dyn DatabaseViewData>,
|
||||
) -> FlowyResult<Box<dyn GroupController>> {
|
||||
let setting_reader = GroupSettingReaderImpl(delegate.clone());
|
||||
let setting_writer = GroupSettingWriterImpl(delegate.clone());
|
||||
|
||||
) -> FlowyResult<Option<Box<dyn GroupController>>> {
|
||||
let fields = delegate.get_fields(&view_id, None).await;
|
||||
let rows = delegate.get_rows(&view_id).await;
|
||||
let layout = delegate.get_layout_for_view(&view_id);
|
||||
let setting_reader = GroupSettingReaderImpl(delegate.clone());
|
||||
|
||||
// Read the grouping field or find a new grouping field
|
||||
let mut grouping_field = setting_reader
|
||||
@ -54,22 +50,29 @@ pub async fn new_group_controller(
|
||||
.cloned()
|
||||
});
|
||||
|
||||
if grouping_field.is_none() {
|
||||
grouping_field = find_new_grouping_field(&fields, &layout);
|
||||
let layout = delegate.get_layout_for_view(&view_id);
|
||||
// If the view is a board and the grouping field is empty, we need to find a new grouping field
|
||||
if layout.is_board() {
|
||||
if grouping_field.is_none() {
|
||||
grouping_field = find_new_grouping_field(&fields, &layout);
|
||||
}
|
||||
}
|
||||
|
||||
match grouping_field {
|
||||
None => Err(FlowyError::internal().context("No grouping field found".to_owned())),
|
||||
Some(_) => {
|
||||
if let Some(grouping_field) = grouping_field {
|
||||
let rows = delegate.get_rows(&view_id).await;
|
||||
let setting_writer = GroupSettingWriterImpl(delegate.clone());
|
||||
Ok(Some(
|
||||
make_group_controller(
|
||||
view_id,
|
||||
grouping_field.unwrap(),
|
||||
grouping_field,
|
||||
rows,
|
||||
setting_reader,
|
||||
setting_writer,
|
||||
)
|
||||
.await
|
||||
},
|
||||
.await?,
|
||||
))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ impl DatabaseViews {
|
||||
let view_editor = self.get_view_editor(view_id).await?;
|
||||
// If the id of the grouping field is equal to the updated field's id, then we need to
|
||||
// update the group setting
|
||||
if view_editor.group_id().await == field_id {
|
||||
if view_editor.is_grouping_field(field_id).await {
|
||||
view_editor.v_update_grouping_field(field_id).await?;
|
||||
}
|
||||
view_editor
|
||||
|
@ -108,7 +108,7 @@ fn update_cell_data_with_changeset(
|
||||
.into_iter()
|
||||
.for_each(|option_name| {
|
||||
let option = SelectOption::new(&option_name);
|
||||
cell_data.options.push(option.clone());
|
||||
cell_data.options.push(option);
|
||||
});
|
||||
|
||||
// Update options
|
||||
|
@ -134,7 +134,7 @@ async fn update_updated_at_field_on_other_cell_update() {
|
||||
.editor
|
||||
.get_cells_for_field(&test.view_id, &updated_at_field.id)
|
||||
.await;
|
||||
assert!(cells.len() > 0);
|
||||
assert!(!cells.is_empty());
|
||||
for (i, cell) in cells.into_iter().enumerate() {
|
||||
let timestamp = DateCellData::from(cell.as_ref()).timestamp.unwrap();
|
||||
println!(
|
||||
|
@ -11,7 +11,7 @@ async fn export_meta_csv_test() {
|
||||
let database = test.editor.clone();
|
||||
let s = database.export_csv(CSVFormat::META).await.unwrap();
|
||||
let mut reader = csv::Reader::from_reader(s.as_bytes());
|
||||
for header in reader.headers() {
|
||||
for header in reader.headers().unwrap() {
|
||||
dbg!(header);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ impl DocumentManager {
|
||||
tracing::debug!("create a document: {:?}", &doc_id);
|
||||
let uid = self.user.user_id()?;
|
||||
let db = self.user.collab_db()?;
|
||||
let collab = self.collab_builder.build(uid, &doc_id, db);
|
||||
let collab = self.collab_builder.build(uid, &doc_id, "document", db);
|
||||
let document = Arc::new(Document::create_with_data(collab, data.0)?);
|
||||
Ok(document)
|
||||
}
|
||||
@ -55,7 +55,7 @@ impl DocumentManager {
|
||||
tracing::debug!("open_document: {:?}", &doc_id);
|
||||
let uid = self.user.user_id()?;
|
||||
let db = self.user.collab_db()?;
|
||||
let collab = self.collab_builder.build(uid, &doc_id, db);
|
||||
let collab = self.collab_builder.build(uid, &doc_id, "document", db);
|
||||
// read the existing document from the disk.
|
||||
let document = Arc::new(Document::new(collab)?);
|
||||
// save the document to the memory and read it from the memory if we open the same document again.
|
||||
@ -84,7 +84,7 @@ impl DocumentManager {
|
||||
pub fn get_document(&self, doc_id: String) -> FlowyResult<Arc<Document>> {
|
||||
let uid = self.user.user_id()?;
|
||||
let db = self.user.collab_db()?;
|
||||
let collab = self.collab_builder.build(uid, &doc_id, db);
|
||||
let collab = self.collab_builder.build(uid, &doc_id, "document", db);
|
||||
// read the existing document from the disk.
|
||||
let document = Arc::new(Document::new(collab)?);
|
||||
Ok(document)
|
||||
|
@ -27,7 +27,7 @@ strum = "0.21"
|
||||
strum_macros = "0.21"
|
||||
protobuf = {version = "2.28.0"}
|
||||
uuid = { version = "1.3.3", features = ["v4"] }
|
||||
#flowy-document = { path = "../flowy-document" }
|
||||
tokio-stream = { version = "0.1.14", features = ["sync"] }
|
||||
|
||||
[dev-dependencies]
|
||||
flowy-folder2 = { path = "../flowy-folder2"}
|
||||
|
@ -1,13 +1,14 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use collab::core::collab_state::CollabState;
|
||||
|
||||
use collab_folder::core::{
|
||||
Folder as InnerFolder, FolderContext, TrashChange, TrashChangeReceiver, TrashInfo, TrashRecord,
|
||||
View, ViewChange, ViewChangeReceiver, ViewLayout, Workspace,
|
||||
Folder, FolderContext, TrashChange, TrashChangeReceiver, TrashInfo, TrashRecord, View,
|
||||
ViewChange, ViewChangeReceiver, ViewLayout, Workspace,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use tracing::{event, Level};
|
||||
@ -15,6 +16,8 @@ use tracing::{event, Level};
|
||||
use crate::deps::{FolderCloudService, FolderUser};
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use lib_infra::util::timestamp;
|
||||
use tokio_stream::wrappers::WatchStream;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::entities::{
|
||||
view_pb_with_child_views, CreateViewParams, CreateWorkspaceParams, RepeatedTrashPB,
|
||||
@ -29,7 +32,7 @@ use crate::user_default::DefaultFolderBuilder;
|
||||
use crate::view_ext::{create_view, gen_view_id, FolderOperationHandler, FolderOperationHandlers};
|
||||
|
||||
pub struct Folder2Manager {
|
||||
folder: Folder,
|
||||
mutex_folder: Arc<MutexFolder>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
user: Arc<dyn FolderUser>,
|
||||
operation_handlers: FolderOperationHandlers,
|
||||
@ -46,10 +49,10 @@ impl Folder2Manager {
|
||||
operation_handlers: FolderOperationHandlers,
|
||||
cloud_service: Arc<dyn FolderCloudService>,
|
||||
) -> FlowyResult<Self> {
|
||||
let folder = Folder::default();
|
||||
let mutex_folder = Arc::new(MutexFolder::default());
|
||||
let manager = Self {
|
||||
user,
|
||||
folder,
|
||||
mutex_folder,
|
||||
collab_builder,
|
||||
operation_handlers,
|
||||
cloud_service,
|
||||
@ -67,7 +70,7 @@ impl Folder2Manager {
|
||||
|
||||
pub async fn get_current_workspace_views(&self) -> FlowyResult<Vec<ViewPB>> {
|
||||
let workspace_id = self
|
||||
.folder
|
||||
.mutex_folder
|
||||
.lock()
|
||||
.as_ref()
|
||||
.map(|folder| folder.get_current_workspace_id());
|
||||
@ -90,17 +93,25 @@ impl Folder2Manager {
|
||||
/// Called immediately after the application launched fi the user already sign in/sign up.
|
||||
#[tracing::instrument(level = "debug", skip(self), err)]
|
||||
pub async fn initialize(&self, uid: i64, workspace_id: &str) -> FlowyResult<()> {
|
||||
let workspace_id = workspace_id.to_string();
|
||||
if let Ok(collab_db) = self.user.collab_db() {
|
||||
let collab = self.collab_builder.build(uid, workspace_id, collab_db);
|
||||
let collab = self
|
||||
.collab_builder
|
||||
.build(uid, &workspace_id, "workspace", collab_db);
|
||||
let (view_tx, view_rx) = tokio::sync::broadcast::channel(100);
|
||||
let (trash_tx, trash_rx) = tokio::sync::broadcast::channel(100);
|
||||
let folder_context = FolderContext {
|
||||
view_change_tx: Some(view_tx),
|
||||
trash_change_tx: Some(trash_tx),
|
||||
view_change_tx: view_tx,
|
||||
trash_change_tx: trash_tx,
|
||||
};
|
||||
*self.folder.lock() = Some(InnerFolder::get_or_create(collab, folder_context));
|
||||
listen_on_trash_change(trash_rx, self.folder.clone());
|
||||
listen_on_view_change(view_rx, self.folder.clone());
|
||||
let folder = Folder::get_or_create(collab, folder_context);
|
||||
let folder_state_rx = folder.subscribe_state_change();
|
||||
*self.mutex_folder.lock() = Some(folder);
|
||||
|
||||
let weak_mutex_folder = Arc::downgrade(&self.mutex_folder);
|
||||
listen_on_folder_state_change(workspace_id, folder_state_rx, &weak_mutex_folder);
|
||||
listen_on_trash_change(trash_rx, &weak_mutex_folder);
|
||||
listen_on_view_change(view_rx, &weak_mutex_folder);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -172,9 +183,9 @@ impl Folder2Manager {
|
||||
|
||||
fn with_folder<F, Output>(&self, default_value: Output, f: F) -> Output
|
||||
where
|
||||
F: FnOnce(&InnerFolder) -> Output,
|
||||
F: FnOnce(&Folder) -> Output,
|
||||
{
|
||||
let folder = self.folder.lock();
|
||||
let folder = self.mutex_folder.lock();
|
||||
match &*folder {
|
||||
None => default_value,
|
||||
Some(folder) => f(folder),
|
||||
@ -222,7 +233,7 @@ impl Folder2Manager {
|
||||
folder.insert_view(view.clone());
|
||||
});
|
||||
|
||||
notify_parent_view_did_change(self.folder.clone(), vec![view.bid.clone()]);
|
||||
notify_parent_view_did_change(self.mutex_folder.clone(), vec![view.bid.clone()]);
|
||||
Ok(view)
|
||||
}
|
||||
|
||||
@ -263,7 +274,7 @@ impl Folder2Manager {
|
||||
#[tracing::instrument(level = "debug", skip(self, view_id), err)]
|
||||
pub async fn get_view(&self, view_id: &str) -> FlowyResult<ViewPB> {
|
||||
let view_id = view_id.to_string();
|
||||
let folder = self.folder.lock();
|
||||
let folder = self.mutex_folder.lock();
|
||||
let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
|
||||
let trash_ids = folder
|
||||
.trash
|
||||
@ -279,7 +290,7 @@ impl Folder2Manager {
|
||||
match folder.views.get_view(&view_id) {
|
||||
None => Err(FlowyError::record_not_found()),
|
||||
Some(mut view) => {
|
||||
view.belongings.retain(|b| !trash_ids.contains(&b.id));
|
||||
view.children.retain(|b| !trash_ids.contains(&b.id));
|
||||
let child_views = folder
|
||||
.views
|
||||
.get_views_belong_to(&view.id)
|
||||
@ -325,7 +336,7 @@ impl Folder2Manager {
|
||||
match view {
|
||||
None => tracing::error!("Couldn't find the view. It should not be empty"),
|
||||
Some(view) => {
|
||||
notify_parent_view_did_change(self.folder.clone(), vec![view.bid]);
|
||||
notify_parent_view_did_change(self.mutex_folder.clone(), vec![view.bid]);
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
@ -340,7 +351,7 @@ impl Folder2Manager {
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub async fn update_view_with_params(&self, params: UpdateViewParams) -> FlowyResult<()> {
|
||||
let _ = self
|
||||
.folder
|
||||
.mutex_folder
|
||||
.lock()
|
||||
.as_ref()
|
||||
.ok_or_else(folder_not_init_error)?
|
||||
@ -353,7 +364,10 @@ impl Folder2Manager {
|
||||
});
|
||||
|
||||
if let Ok(view_pb) = self.get_view(¶ms.view_id).await {
|
||||
notify_parent_view_did_change(self.folder.clone(), vec![view_pb.parent_view_id.clone()]);
|
||||
notify_parent_view_did_change(
|
||||
self.mutex_folder.clone(),
|
||||
vec![view_pb.parent_view_id.clone()],
|
||||
);
|
||||
send_notification(&view_pb.id, FolderNotification::DidUpdateView)
|
||||
.payload(view_pb)
|
||||
.send();
|
||||
@ -369,10 +383,10 @@ impl Folder2Manager {
|
||||
|
||||
let handler = self.get_handler(&view.layout)?;
|
||||
let view_data = handler.duplicate_view(&view.id).await?;
|
||||
let mut ext = HashMap::new();
|
||||
if let Some(database_id) = view.database_id {
|
||||
ext.insert("database_id".to_string(), database_id);
|
||||
}
|
||||
let meta = HashMap::new();
|
||||
// if let Some(database_id) = view.database_id {
|
||||
// meta.insert("database_id".to_string(), database_id);
|
||||
// }
|
||||
let duplicate_params = CreateViewParams {
|
||||
parent_view_id: view.bid.clone(),
|
||||
name: format!("{} (copy)", &view.name),
|
||||
@ -380,7 +394,7 @@ impl Folder2Manager {
|
||||
layout: view.layout.into(),
|
||||
initial_data: view_data.to_vec(),
|
||||
view_id: gen_view_id(),
|
||||
meta: ext,
|
||||
meta,
|
||||
};
|
||||
|
||||
let _ = self.create_view_with_params(duplicate_params).await?;
|
||||
@ -389,7 +403,7 @@ impl Folder2Manager {
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub(crate) async fn set_current_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
let folder = self.folder.lock();
|
||||
let folder = self.mutex_folder.lock();
|
||||
let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
|
||||
folder.set_current_view(view_id);
|
||||
|
||||
@ -487,7 +501,7 @@ impl Folder2Manager {
|
||||
self.with_folder((), |folder| {
|
||||
folder.insert_view(view.clone());
|
||||
});
|
||||
notify_parent_view_did_change(self.folder.clone(), vec![view.bid.clone()]);
|
||||
notify_parent_view_did_change(self.mutex_folder.clone(), vec![view.bid.clone()]);
|
||||
Ok(view)
|
||||
}
|
||||
|
||||
@ -507,52 +521,82 @@ impl Folder2Manager {
|
||||
}
|
||||
|
||||
/// Listen on the [ViewChange] after create/delete/update events happened
|
||||
fn listen_on_view_change(mut rx: ViewChangeReceiver, folder: Folder) {
|
||||
fn listen_on_view_change(mut rx: ViewChangeReceiver, weak_mutex_folder: &Weak<MutexFolder>) {
|
||||
let weak_mutex_folder = weak_mutex_folder.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(value) = rx.recv().await {
|
||||
match value {
|
||||
ViewChange::DidCreateView { view } => {
|
||||
notify_parent_view_did_change(folder.clone(), vec![view.bid]);
|
||||
},
|
||||
ViewChange::DidDeleteView { views: _ } => {},
|
||||
ViewChange::DidUpdate { view } => {
|
||||
notify_parent_view_did_change(folder.clone(), vec![view.bid]);
|
||||
},
|
||||
};
|
||||
if let Some(folder) = weak_mutex_folder.upgrade() {
|
||||
tracing::trace!("Did receive view change: {:?}", value);
|
||||
match value {
|
||||
ViewChange::DidCreateView { view } => {
|
||||
notify_parent_view_did_change(folder.clone(), vec![view.bid]);
|
||||
},
|
||||
ViewChange::DidDeleteView { views: _ } => {},
|
||||
ViewChange::DidUpdate { view } => {
|
||||
notify_parent_view_did_change(folder.clone(), vec![view.bid]);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn listen_on_folder_state_change(
|
||||
workspace_id: String,
|
||||
mut folder_state_rx: WatchStream<CollabState>,
|
||||
weak_mutex_folder: &Weak<MutexFolder>,
|
||||
) {
|
||||
let weak_mutex_folder = weak_mutex_folder.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Some(state) = folder_state_rx.next().await {
|
||||
if state.is_root_changed() {
|
||||
if let Some(mutex_folder) = weak_mutex_folder.upgrade() {
|
||||
let folder = mutex_folder.lock().take();
|
||||
if let Some(folder) = folder {
|
||||
tracing::trace!("🔥Reload folder");
|
||||
let reload_folder = folder.reload();
|
||||
notify_did_update_workspace(&workspace_id, &reload_folder);
|
||||
*mutex_folder.lock() = Some(reload_folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Listen on the [TrashChange]s and notify the frontend some views were changed.
|
||||
fn listen_on_trash_change(mut rx: TrashChangeReceiver, folder: Folder) {
|
||||
fn listen_on_trash_change(mut rx: TrashChangeReceiver, weak_mutex_folder: &Weak<MutexFolder>) {
|
||||
let weak_mutex_folder = weak_mutex_folder.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(value) = rx.recv().await {
|
||||
let mut unique_ids = HashSet::new();
|
||||
tracing::trace!("Did receive trash change: {:?}", value);
|
||||
let ids = match value {
|
||||
TrashChange::DidCreateTrash { ids } => ids,
|
||||
TrashChange::DidDeleteTrash { ids } => ids,
|
||||
};
|
||||
if let Some(folder) = weak_mutex_folder.upgrade() {
|
||||
let mut unique_ids = HashSet::new();
|
||||
tracing::trace!("Did receive trash change: {:?}", value);
|
||||
let ids = match value {
|
||||
TrashChange::DidCreateTrash { ids } => ids,
|
||||
TrashChange::DidDeleteTrash { ids } => ids,
|
||||
};
|
||||
|
||||
if let Some(folder) = folder.lock().as_ref() {
|
||||
let views = folder.views.get_views(&ids);
|
||||
for view in views {
|
||||
unique_ids.insert(view.bid);
|
||||
if let Some(folder) = folder.lock().as_ref() {
|
||||
let views = folder.views.get_views(&ids);
|
||||
for view in views {
|
||||
unique_ids.insert(view.bid);
|
||||
}
|
||||
|
||||
let repeated_trash: RepeatedTrashPB = folder.trash.get_all_trash().into();
|
||||
send_notification("trash", FolderNotification::DidUpdateTrash)
|
||||
.payload(repeated_trash)
|
||||
.send();
|
||||
}
|
||||
|
||||
let repeated_trash: RepeatedTrashPB = folder.trash.get_all_trash().into();
|
||||
send_notification("trash", FolderNotification::DidUpdateTrash)
|
||||
.payload(repeated_trash)
|
||||
.send();
|
||||
let parent_view_ids = unique_ids.into_iter().collect();
|
||||
notify_parent_view_did_change(folder.clone(), parent_view_ids);
|
||||
}
|
||||
|
||||
let parent_view_ids = unique_ids.into_iter().collect();
|
||||
notify_parent_view_did_change(folder.clone(), parent_view_ids);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn get_workspace_view_pbs(workspace_id: &str, folder: &InnerFolder) -> Vec<ViewPB> {
|
||||
fn get_workspace_view_pbs(workspace_id: &str, folder: &Folder) -> Vec<ViewPB> {
|
||||
let trash_ids = folder
|
||||
.trash
|
||||
.get_all_trash()
|
||||
@ -577,10 +621,18 @@ fn get_workspace_view_pbs(workspace_id: &str, folder: &InnerFolder) -> Vec<ViewP
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn notify_did_update_workspace(workspace_id: &str, folder: &Folder) {
|
||||
let repeated_view: RepeatedViewPB = get_workspace_view_pbs(workspace_id, folder).into();
|
||||
tracing::trace!("Did update workspace views: {:?}", repeated_view);
|
||||
send_notification(workspace_id, FolderNotification::DidUpdateWorkspaceViews)
|
||||
.payload(repeated_view)
|
||||
.send();
|
||||
}
|
||||
|
||||
/// Notify the the list of parent view ids that its child views were changed.
|
||||
#[tracing::instrument(level = "debug", skip(folder, parent_view_ids))]
|
||||
fn notify_parent_view_did_change<T: AsRef<str>>(
|
||||
folder: Folder,
|
||||
folder: Arc<MutexFolder>,
|
||||
parent_view_ids: Vec<T>,
|
||||
) -> Option<()> {
|
||||
let folder = folder.lock();
|
||||
@ -599,10 +651,7 @@ fn notify_parent_view_did_change<T: AsRef<str>>(
|
||||
// if the view's parent id equal to workspace id. Then it will fetch the current
|
||||
// workspace views. Because the the workspace is not a view stored in the views map.
|
||||
if parent_view_id == workspace_id {
|
||||
let repeated_view: RepeatedViewPB = get_workspace_view_pbs(&workspace_id, folder).into();
|
||||
send_notification(&workspace_id, FolderNotification::DidUpdateWorkspaceViews)
|
||||
.payload(repeated_view)
|
||||
.send();
|
||||
notify_did_update_workspace(&workspace_id, folder)
|
||||
} else {
|
||||
// Parent view can contain a list of child views. Currently, only get the first level
|
||||
// child views.
|
||||
@ -627,15 +676,12 @@ fn folder_not_init_error() -> FlowyError {
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Folder(Arc<Mutex<Option<InnerFolder>>>);
|
||||
|
||||
impl Deref for Folder {
|
||||
type Target = Arc<Mutex<Option<InnerFolder>>>;
|
||||
pub struct MutexFolder(Arc<Mutex<Option<Folder>>>);
|
||||
impl Deref for MutexFolder {
|
||||
type Target = Arc<Mutex<Option<Folder>>>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for Folder {}
|
||||
|
||||
unsafe impl Send for Folder {}
|
||||
unsafe impl Sync for MutexFolder {}
|
||||
unsafe impl Send for MutexFolder {}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use chrono::Utc;
|
||||
use collab_folder::core::{Belonging, Belongings, FolderData, View, ViewLayout, Workspace};
|
||||
use collab_folder::core::{FolderData, RepeatedView, View, ViewIdentifier, ViewLayout, Workspace};
|
||||
use nanoid::nanoid;
|
||||
|
||||
use crate::entities::{view_pb_with_child_views, WorkspacePB};
|
||||
@ -24,10 +24,9 @@ impl DefaultFolderBuilder {
|
||||
bid: view_id.clone(),
|
||||
name: "Read me".to_string(),
|
||||
desc: "".to_string(),
|
||||
belongings: Default::default(),
|
||||
created_at: time,
|
||||
layout: child_view_layout.clone(),
|
||||
database_id: None,
|
||||
children: Default::default(),
|
||||
};
|
||||
|
||||
// create the document
|
||||
@ -50,21 +49,18 @@ impl DefaultFolderBuilder {
|
||||
bid: workspace_id.clone(),
|
||||
name: "⭐️ Getting started".to_string(),
|
||||
desc: "".to_string(),
|
||||
belongings: Belongings::new(vec![Belonging {
|
||||
children: RepeatedView::new(vec![ViewIdentifier {
|
||||
id: child_view.id.clone(),
|
||||
name: child_view.name.clone(),
|
||||
}]),
|
||||
created_at: time,
|
||||
layout: ViewLayout::Document,
|
||||
database_id: None,
|
||||
};
|
||||
|
||||
let workspace = Workspace {
|
||||
id: workspace_id,
|
||||
name: "Workspace".to_string(),
|
||||
belongings: Belongings::new(vec![Belonging {
|
||||
child_views: RepeatedView::new(vec![ViewIdentifier {
|
||||
id: view.id.clone(),
|
||||
name: view.name.clone(),
|
||||
}]),
|
||||
created_at: time,
|
||||
};
|
||||
|
@ -83,10 +83,9 @@ pub(crate) fn create_view(params: CreateViewParams, layout: ViewLayout) -> View
|
||||
bid: params.parent_view_id,
|
||||
name: params.name,
|
||||
desc: params.desc,
|
||||
belongings: Default::default(),
|
||||
children: Default::default(),
|
||||
created_at: time,
|
||||
layout,
|
||||
database_id: None,
|
||||
}
|
||||
}
|
||||
pub fn gen_view_id() -> String {
|
||||
|
@ -13,7 +13,7 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl {
|
||||
Ok(Workspace {
|
||||
id: gen_workspace_id(),
|
||||
name: name.to_string(),
|
||||
belongings: Default::default(),
|
||||
child_views: Default::default(),
|
||||
created_at: timestamp(),
|
||||
})
|
||||
})
|
||||
|
@ -13,7 +13,7 @@ impl FolderCloudService for SelfHostedServerFolderCloudServiceImpl {
|
||||
Ok(Workspace {
|
||||
id: gen_workspace_id(),
|
||||
name: name.to_string(),
|
||||
belongings: Default::default(),
|
||||
child_views: Default::default(),
|
||||
created_at: timestamp(),
|
||||
})
|
||||
})
|
||||
|
@ -187,7 +187,7 @@ pub(crate) async fn create_workspace_with_uid(
|
||||
Ok(Workspace {
|
||||
id: user_workspace.workspace_id,
|
||||
name: user_workspace.workspace_name,
|
||||
belongings: Default::default(),
|
||||
child_views: Default::default(),
|
||||
created_at: user_workspace.created_at.timestamp(),
|
||||
})
|
||||
}
|
||||
@ -218,7 +218,7 @@ pub(crate) async fn get_user_workspace_with_uid(
|
||||
.map(|user_workspace| Workspace {
|
||||
id: user_workspace.workspace_id,
|
||||
name: user_workspace.workspace_name,
|
||||
belongings: Default::default(),
|
||||
child_views: Default::default(),
|
||||
created_at: user_workspace.created_at.timestamp(),
|
||||
})
|
||||
.collect(),
|
||||
|
@ -7,7 +7,7 @@ use flowy_error::FlowyResult;
|
||||
|
||||
use lib_dispatch::prelude::*;
|
||||
use lib_infra::box_any::BoxAny;
|
||||
use lib_infra::future::{Fut, FutureResult};
|
||||
use lib_infra::future::{to_fut, Fut, FutureResult};
|
||||
|
||||
use crate::entities::{SignInResponse, SignUpResponse, UpdateUserProfileParams, UserProfile};
|
||||
use crate::event_handler::*;
|
||||
@ -31,7 +31,25 @@ pub fn init(user_session: Arc<UserSession>) -> AFPlugin {
|
||||
.event(UserEvent::ThirdPartyAuth, third_party_auth_handler)
|
||||
}
|
||||
|
||||
pub(crate) struct DefaultUserStatusCallback;
|
||||
impl UserStatusCallback for DefaultUserStatusCallback {
|
||||
fn auth_type_did_changed(&self, _auth_type: AuthType) {}
|
||||
|
||||
fn did_sign_in(&self, _user_id: i64, _workspace_id: &str) -> Fut<FlowyResult<()>> {
|
||||
to_fut(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn did_sign_up(&self, _user_profile: &UserProfile) -> Fut<FlowyResult<()>> {
|
||||
to_fut(async { Ok(()) })
|
||||
}
|
||||
|
||||
fn did_expired(&self, _token: &str, _user_id: i64) -> Fut<FlowyResult<()>> {
|
||||
to_fut(async { Ok(()) })
|
||||
}
|
||||
}
|
||||
|
||||
pub trait UserStatusCallback: Send + Sync + 'static {
|
||||
fn auth_type_did_changed(&self, auth_type: AuthType);
|
||||
fn did_sign_in(&self, user_id: i64, workspace_id: &str) -> Fut<FlowyResult<()>>;
|
||||
fn did_sign_up(&self, user_profile: &UserProfile) -> Fut<FlowyResult<()>>;
|
||||
fn did_expired(&self, token: &str, user_id: i64) -> Fut<FlowyResult<()>>;
|
||||
@ -41,7 +59,7 @@ pub trait UserStatusCallback: Send + Sync + 'static {
|
||||
/// The provider can be supabase, firebase, aws, or any other cloud service.
|
||||
pub trait UserCloudServiceProvider: Send + Sync + 'static {
|
||||
fn set_auth_type(&self, auth_type: AuthType);
|
||||
fn get_auth_service(&self, auth_type: &AuthType) -> Result<Arc<dyn UserAuthService>, FlowyError>;
|
||||
fn get_auth_service(&self) -> Result<Arc<dyn UserAuthService>, FlowyError>;
|
||||
}
|
||||
|
||||
impl<T> UserCloudServiceProvider for Arc<T>
|
||||
@ -52,8 +70,8 @@ where
|
||||
(**self).set_auth_type(auth_type)
|
||||
}
|
||||
|
||||
fn get_auth_service(&self, auth_type: &AuthType) -> Result<Arc<dyn UserAuthService>, FlowyError> {
|
||||
(**self).get_auth_service(auth_type)
|
||||
fn get_auth_service(&self) -> Result<Arc<dyn UserAuthService>, FlowyError> {
|
||||
(**self).get_auth_service()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ use crate::entities::{
|
||||
AuthTypePB, SignInResponse, SignUpResponse, UpdateUserProfileParams, UserProfile,
|
||||
};
|
||||
use crate::entities::{UserProfilePB, UserSettingPB};
|
||||
use crate::event_map::{UserCloudServiceProvider, UserStatusCallback};
|
||||
use crate::event_map::{DefaultUserStatusCallback, UserCloudServiceProvider, UserStatusCallback};
|
||||
use crate::{
|
||||
errors::FlowyError,
|
||||
event_map::UserAuthService,
|
||||
@ -50,7 +50,7 @@ pub struct UserSession {
|
||||
database: UserDB,
|
||||
session_config: UserSessionConfig,
|
||||
cloud_services: Arc<dyn UserCloudServiceProvider>,
|
||||
user_status_callback: RwLock<Option<Arc<dyn UserStatusCallback>>>,
|
||||
user_status_callback: RwLock<Arc<dyn UserStatusCallback>>,
|
||||
}
|
||||
|
||||
impl UserSession {
|
||||
@ -59,7 +59,8 @@ impl UserSession {
|
||||
cloud_services: Arc<dyn UserCloudServiceProvider>,
|
||||
) -> Self {
|
||||
let db = UserDB::new(&session_config.root_dir);
|
||||
let user_status_callback = RwLock::new(None);
|
||||
let user_status_callback: RwLock<Arc<dyn UserStatusCallback>> =
|
||||
RwLock::new(Arc::new(DefaultUserStatusCallback));
|
||||
Self {
|
||||
database: db,
|
||||
session_config,
|
||||
@ -74,7 +75,7 @@ impl UserSession {
|
||||
.did_sign_in(session.user_id, &session.workspace_id)
|
||||
.await;
|
||||
}
|
||||
*self.user_status_callback.write().await = Some(Arc::new(user_status_callback));
|
||||
*self.user_status_callback.write().await = Arc::new(user_status_callback);
|
||||
}
|
||||
|
||||
pub fn db_connection(&self) -> Result<DBConnection, FlowyError> {
|
||||
@ -104,10 +105,16 @@ impl UserSession {
|
||||
auth_type: &AuthType,
|
||||
params: BoxAny,
|
||||
) -> Result<UserProfile, FlowyError> {
|
||||
self
|
||||
.user_status_callback
|
||||
.read()
|
||||
.await
|
||||
.auth_type_did_changed(auth_type.clone());
|
||||
|
||||
self.cloud_services.set_auth_type(auth_type.clone());
|
||||
let resp = self
|
||||
.cloud_services
|
||||
.get_auth_service(auth_type)?
|
||||
.get_auth_service()?
|
||||
.sign_in(params)
|
||||
.await?;
|
||||
|
||||
@ -118,8 +125,6 @@ impl UserSession {
|
||||
.user_status_callback
|
||||
.read()
|
||||
.await
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.did_sign_in(user_profile.id, &user_profile.workspace_id)
|
||||
.await;
|
||||
send_sign_in_notification()
|
||||
@ -135,10 +140,16 @@ impl UserSession {
|
||||
auth_type: &AuthType,
|
||||
params: BoxAny,
|
||||
) -> Result<UserProfile, FlowyError> {
|
||||
self
|
||||
.user_status_callback
|
||||
.read()
|
||||
.await
|
||||
.auth_type_did_changed(auth_type.clone());
|
||||
|
||||
self.cloud_services.set_auth_type(auth_type.clone());
|
||||
let resp = self
|
||||
.cloud_services
|
||||
.get_auth_service(auth_type)?
|
||||
.get_auth_service()?
|
||||
.sign_up(params)
|
||||
.await?;
|
||||
|
||||
@ -150,8 +161,6 @@ impl UserSession {
|
||||
.user_status_callback
|
||||
.read()
|
||||
.await
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.did_sign_up(&user_profile)
|
||||
.await;
|
||||
Ok(user_profile)
|
||||
@ -166,7 +175,7 @@ impl UserSession {
|
||||
self.database.close_user_db(session.user_id)?;
|
||||
self.set_session(None)?;
|
||||
|
||||
let server = self.cloud_services.get_auth_service(auth_type)?;
|
||||
let server = self.cloud_services.get_auth_service()?;
|
||||
let token = session.token;
|
||||
let _ = tokio::spawn(async move {
|
||||
match server.sign_out(token).await {
|
||||
@ -256,12 +265,12 @@ impl UserSession {
|
||||
impl UserSession {
|
||||
async fn update_user(
|
||||
&self,
|
||||
auth_type: &AuthType,
|
||||
_auth_type: &AuthType,
|
||||
uid: i64,
|
||||
token: &Option<String>,
|
||||
params: UpdateUserProfileParams,
|
||||
) -> Result<(), FlowyError> {
|
||||
let server = self.cloud_services.get_auth_service(auth_type)?;
|
||||
let server = self.cloud_services.get_auth_service()?;
|
||||
let token = token.to_owned();
|
||||
let _ = tokio::spawn(async move {
|
||||
match server.update_user(uid, &token, params).await {
|
||||
|
Loading…
Reference in New Issue
Block a user