diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/home/mobile_home_page_header.dart b/frontend/appflowy_flutter/lib/mobile/presentation/home/mobile_home_page_header.dart index 4a1df63740..113f12e543 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/home/mobile_home_page_header.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/home/mobile_home_page_header.dart @@ -194,7 +194,7 @@ class _MobileWorkspace extends StatelessWidget { context.read().add( UserWorkspaceEvent.openWorkspace( workspace.workspaceId, - workspace.authType, + workspace.workspaceAuthType, ), ); }, diff --git a/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart index 5ed56b890e..0e0b912a08 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart @@ -54,7 +54,7 @@ class UserWorkspaceBloc extends Bloc { Log.info('init open workspace: ${currentWorkspace.workspaceId}'); await _userService.openWorkspace( currentWorkspace.workspaceId, - currentWorkspace.authType, + currentWorkspace.workspaceAuthType, ); } @@ -92,7 +92,7 @@ class UserWorkspaceBloc extends Bloc { add( OpenWorkspace( currentWorkspace.workspaceId, - currentWorkspace.authType, + currentWorkspace.workspaceAuthType, ), ); } @@ -132,7 +132,7 @@ class UserWorkspaceBloc extends Bloc { add( OpenWorkspace( s.workspaceId, - s.authType, + s.workspaceAuthType, ), ); }) @@ -190,7 +190,7 @@ class UserWorkspaceBloc extends Bloc { add( OpenWorkspace( workspaces.first.workspaceId, - workspaces.first.authType, + workspaces.first.workspaceAuthType, ), ); } @@ -203,7 +203,7 @@ class UserWorkspaceBloc extends Bloc { add( OpenWorkspace( workspaces.first.workspaceId, - workspaces.first.authType, + workspaces.first.workspaceAuthType, ), ); } @@ -369,7 +369,7 @@ class UserWorkspaceBloc extends Bloc { add( OpenWorkspace( workspaces.first.workspaceId, - workspaces.first.authType, + workspaces.first.workspaceAuthType, ), ); } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart index 097da2c2ae..4ff5ccbf67 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart @@ -309,7 +309,7 @@ class _WorkspaceInfo extends StatelessWidget { context.read().add( UserWorkspaceEvent.openWorkspace( workspace.workspaceId, - workspace.authType, + workspace.workspaceAuthType, ), ); diff --git a/frontend/rust-lib/event-integration-test/tests/user/af_cloud_test/workspace_test.rs b/frontend/rust-lib/event-integration-test/tests/user/af_cloud_test/workspace_test.rs index ea04d922fc..3bb71ea0dc 100644 --- a/frontend/rust-lib/event-integration-test/tests/user/af_cloud_test/workspace_test.rs +++ b/frontend/rust-lib/event-integration-test/tests/user/af_cloud_test/workspace_test.rs @@ -90,7 +90,10 @@ async fn af_cloud_create_workspace_test() { { // after opening new workspace test - .open_workspace(&created_workspace.workspace_id, created_workspace.auth_type) + .open_workspace( + &created_workspace.workspace_id, + created_workspace.workspace_auth_type, + ) .await; let folder_ws = test.folder_read_current_workspace().await; assert_eq!(folder_ws.id, created_workspace.workspace_id); @@ -124,7 +127,10 @@ async fn af_cloud_open_workspace_test() { .create_workspace("second workspace", AuthType::AppFlowyCloud) .await; test - .open_workspace(&user_workspace.workspace_id, user_workspace.auth_type) + .open_workspace( + &user_workspace.workspace_id, + user_workspace.workspace_auth_type, + ) .await; let second_workspace = test.get_current_workspace().await; let second_workspace = test.get_user_workspace(&second_workspace.id).await; @@ -144,7 +150,7 @@ async fn af_cloud_open_workspace_test() { test .open_workspace( &first_workspace.workspace_id, - first_workspace.auth_type.clone(), + first_workspace.workspace_auth_type.clone(), ) .await; sleep(Duration::from_millis(300)).await; @@ -155,7 +161,7 @@ async fn af_cloud_open_workspace_test() { test .open_workspace( &second_workspace.workspace_id, - second_workspace.auth_type.clone(), + second_workspace.workspace_auth_type.clone(), ) .await; sleep(Duration::from_millis(200)).await; @@ -168,7 +174,7 @@ async fn af_cloud_open_workspace_test() { test .open_workspace( &first_workspace.workspace_id, - first_workspace.auth_type.clone(), + first_workspace.workspace_auth_type.clone(), ) .await; let views_1 = test.get_all_workspace_views().await; @@ -180,7 +186,7 @@ async fn af_cloud_open_workspace_test() { test .open_workspace( &second_workspace.workspace_id, - second_workspace.auth_type.clone(), + second_workspace.workspace_auth_type.clone(), ) .await; let views_2 = test.get_all_workspace_views().await; @@ -239,7 +245,10 @@ async fn af_cloud_different_open_same_workspace_test() { let index = i % 2; let iter_workspace_id = &all_workspaces[index].workspace_id; client - .open_workspace(iter_workspace_id, all_workspaces[index].auth_type.clone()) + .open_workspace( + iter_workspace_id, + all_workspaces[index].workspace_auth_type.clone(), + ) .await; if iter_workspace_id == &cloned_shared_workspace_id { let views = client.get_all_workspace_views().await; 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 e73943bbbe..512ad90a22 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 @@ -133,9 +133,9 @@ impl UserCloudService for LocalServerUserServiceImpl { async fn open_workspace(&self, workspace_id: &Uuid) -> Result { let uid = self.user.user_id()?; - let conn = self.user.get_sqlite_db(uid)?; + let mut conn = self.user.get_sqlite_db(uid)?; - let workspace = select_user_workspace(&workspace_id.to_string(), conn)?; + let workspace = select_user_workspace(&workspace_id.to_string(), &mut conn)?; Ok(UserWorkspace::from(workspace)) } diff --git a/frontend/rust-lib/flowy-sqlite/migrations/2025-04-18-132232_user_workspace_auth_type/up.sql b/frontend/rust-lib/flowy-sqlite/migrations/2025-04-18-132232_user_workspace_auth_type/up.sql index b77372ad63..7d986e3e57 100644 --- a/frontend/rust-lib/flowy-sqlite/migrations/2025-04-18-132232_user_workspace_auth_type/up.sql +++ b/frontend/rust-lib/flowy-sqlite/migrations/2025-04-18-132232_user_workspace_auth_type/up.sql @@ -1,10 +1,10 @@ -- Your SQL goes here ALTER TABLE user_workspace_table - ADD COLUMN auth_type INTEGER NOT NULL DEFAULT 1; + ADD COLUMN workspace_type INTEGER NOT NULL DEFAULT 1; -- 2. Back‑fill from user_table.auth_type UPDATE user_workspace_table -SET auth_type = (SELECT ut.auth_type +SET workspace_type = (SELECT ut.auth_type FROM user_table ut WHERE ut.id = CAST(user_workspace_table.uid AS TEXT)) WHERE EXISTS (SELECT 1 diff --git a/frontend/rust-lib/flowy-sqlite/src/schema.rs b/frontend/rust-lib/flowy-sqlite/src/schema.rs index 28a83ed449..eb6b248ea6 100644 --- a/frontend/rust-lib/flowy-sqlite/src/schema.rs +++ b/frontend/rust-lib/flowy-sqlite/src/schema.rs @@ -107,7 +107,7 @@ diesel::table! { icon -> Text, member_count -> BigInt, role -> Nullable, - auth_type -> Integer, + workspace_type -> Integer, } } @@ -132,16 +132,16 @@ diesel::table! { } diesel::allow_tables_to_appear_in_same_query!( - af_collab_metadata, - chat_local_setting_table, - chat_message_table, - chat_table, - collab_snapshot, - upload_file_part, - upload_file_table, - user_data_migration_records, - user_table, - user_workspace_table, - workspace_members_table, - workspace_setting_table, + af_collab_metadata, + chat_local_setting_table, + chat_message_table, + chat_table, + collab_snapshot, + upload_file_part, + upload_file_table, + user_data_migration_records, + user_table, + user_workspace_table, + workspace_members_table, + workspace_setting_table, ); diff --git a/frontend/rust-lib/flowy-user-pub/src/sql/workspace_sql.rs b/frontend/rust-lib/flowy-user-pub/src/sql/workspace_sql.rs index cb6d299039..709e218514 100644 --- a/frontend/rust-lib/flowy-user-pub/src/sql/workspace_sql.rs +++ b/frontend/rust-lib/flowy-user-pub/src/sql/workspace_sql.rs @@ -17,7 +17,7 @@ pub struct UserWorkspaceTable { pub icon: String, pub member_count: i64, pub role: Option, - pub auth_type: i32, + pub workspace_type: i32, } #[derive(AsChangeset, Identifiable, Default, Debug)] @@ -50,18 +50,18 @@ impl UserWorkspaceTable { icon: workspace.icon.clone(), member_count: workspace.member_count, role: workspace.role.clone().map(|v| v as i32), - auth_type: auth_type as i32, + workspace_type: auth_type as i32, }) } } pub fn select_user_workspace( workspace_id: &str, - mut conn: DBConnection, + conn: &mut SqliteConnection, ) -> FlowyResult { let row = user_workspace_table::dsl::user_workspace_table .filter(user_workspace_table::id.eq(workspace_id)) - .first::(&mut *conn)?; + .first::(conn)?; Ok(row) } @@ -106,7 +106,7 @@ pub fn upsert_user_workspace( user_workspace_table::icon.eq(row.icon), user_workspace_table::member_count.eq(row.member_count), user_workspace_table::role.eq(row.role), - user_workspace_table::auth_type.eq(row.auth_type), + user_workspace_table::workspace_type.eq(row.workspace_type), )) .execute(conn)?; @@ -153,7 +153,7 @@ pub fn delete_user_all_workspace( let n = diesel::delete( user_workspace_table::dsl::user_workspace_table .filter(user_workspace_table::uid.eq(uid)) - .filter(user_workspace_table::auth_type.eq(auth_type as i32)), + .filter(user_workspace_table::workspace_type.eq(auth_type as i32)), ) .execute(conn)?; info!( 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 5afc93850a..6a95a89041 100644 --- a/frontend/rust-lib/flowy-user/src/entities/user_profile.rs +++ b/frontend/rust-lib/flowy-user/src/entities/user_profile.rs @@ -186,7 +186,7 @@ pub struct UserWorkspacePB { pub role: Option, #[pb(index = 7)] - pub auth_type: AuthTypePB, + pub workspace_auth_type: AuthTypePB, } impl From<(AuthType, UserWorkspace)> for UserWorkspacePB { @@ -198,7 +198,7 @@ impl From<(AuthType, UserWorkspace)> for UserWorkspacePB { icon: value.1.icon, member_count: value.1.member_count, role: value.1.role.map(AFRolePB::from), - auth_type: AuthTypePB::from(value.0), + workspace_auth_type: AuthTypePB::from(value.0), } } } @@ -212,7 +212,7 @@ impl From for UserWorkspacePB { icon: value.icon, member_count: value.member_count, role: value.role.map(AFRolePB::from), - auth_type: AuthTypePB::from(value.auth_type), + workspace_auth_type: AuthTypePB::from(value.workspace_type), } } } diff --git a/frontend/rust-lib/flowy-user/src/migrations/anon_user_workspace.rs b/frontend/rust-lib/flowy-user/src/migrations/anon_user_workspace.rs new file mode 100644 index 0000000000..7c806d3aaf --- /dev/null +++ b/frontend/rust-lib/flowy-user/src/migrations/anon_user_workspace.rs @@ -0,0 +1,58 @@ +use diesel::SqliteConnection; +use semver::Version; +use std::sync::Arc; +use tracing::{info, instrument}; + +use collab_integrate::CollabKVDB; +use flowy_error::FlowyResult; +use flowy_user_pub::entities::AuthType; + +use crate::migrations::migration::UserDataMigration; +use flowy_user_pub::session::Session; +use flowy_user_pub::sql::{select_user_workspace, upsert_user_workspace}; + +pub struct AnonUserWorkspaceTableMigration; + +impl UserDataMigration for AnonUserWorkspaceTableMigration { + fn name(&self) -> &str { + "anon_user_workspace_table_migration" + } + + fn run_when( + &self, + first_installed_version: &Option, + _current_version: &Version, + ) -> bool { + match first_installed_version { + None => true, + Some(version) => version <= &Version::new(0, 8, 10), + } + } + + #[instrument(name = "AnonUserWorkspaceTableMigration", skip_all, err)] + fn run( + &self, + session: &Session, + _collab_db: &Arc, + auth_type: &AuthType, + db: &mut SqliteConnection, + ) -> FlowyResult<()> { + // For historical reason, anon user doesn't have a workspace in user_workspace_table. + // So we need to create a new entry for the anon user in the user_workspace_table. + if matches!(auth_type, AuthType::Local) { + let user_workspace = &session.user_workspace; + let result = select_user_workspace(&user_workspace.id, db); + if let Err(e) = result { + if e.is_record_not_found() { + info!( + "Anon user workspace not found in the database, creating a new entry for user_id: {}", + session.user_id + ); + upsert_user_workspace(session.user_id, *auth_type, user_workspace.clone(), db)?; + } + } + } + + Ok(()) + } +} diff --git a/frontend/rust-lib/flowy-user/src/migrations/doc_key_with_workspace.rs b/frontend/rust-lib/flowy-user/src/migrations/doc_key_with_workspace.rs index 5a8bb4d516..84acc0b56a 100644 --- a/frontend/rust-lib/flowy-user/src/migrations/doc_key_with_workspace.rs +++ b/frontend/rust-lib/flowy-user/src/migrations/doc_key_with_workspace.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use collab_plugins::local_storage::kv::doc::migrate_old_keys; use collab_plugins::local_storage::kv::KVTransactionDB; +use diesel::SqliteConnection; use semver::Version; use tracing::{instrument, trace}; @@ -40,6 +41,7 @@ impl UserDataMigration for CollabDocKeyWithWorkspaceIdMigration { session: &Session, collab_db: &Arc, _authenticator: &AuthType, + _db: &mut SqliteConnection, ) -> FlowyResult<()> { trace!( "migrate key with workspace id:{}", diff --git a/frontend/rust-lib/flowy-user/src/migrations/document_empty_content.rs b/frontend/rust-lib/flowy-user/src/migrations/document_empty_content.rs index ab828e18d8..2e4581f7ec 100644 --- a/frontend/rust-lib/flowy-user/src/migrations/document_empty_content.rs +++ b/frontend/rust-lib/flowy-user/src/migrations/document_empty_content.rs @@ -6,6 +6,7 @@ use collab_document::document::Document; use collab_document::document_data::default_document_data; use collab_folder::{Folder, View}; use collab_plugins::local_storage::kv::KVTransactionDB; +use diesel::SqliteConnection; use semver::Version; use tracing::{event, instrument}; @@ -42,6 +43,7 @@ impl UserDataMigration for HistoricalEmptyDocumentMigration { session: &Session, collab_db: &Arc, authenticator: &AuthType, + _db: &mut SqliteConnection, ) -> FlowyResult<()> { // - The `empty document` struct has already undergone refactoring prior to the launch of the AppFlowy cloud version. // - Consequently, if a user is utilizing the AppFlowy cloud version, there is no need to perform any migration for the `empty document` struct. diff --git a/frontend/rust-lib/flowy-user/src/migrations/migration.rs b/frontend/rust-lib/flowy-user/src/migrations/migration.rs index 1330d1995b..0f5c2c2624 100644 --- a/frontend/rust-lib/flowy-user/src/migrations/migration.rs +++ b/frontend/rust-lib/flowy-user/src/migrations/migration.rs @@ -54,7 +54,7 @@ impl UserLocalDataMigration { pub fn run( self, migrations: Vec>, - authenticator: &AuthType, + auth_type: &AuthType, app_version: &Version, ) -> FlowyResult> { let mut applied_migrations = vec![]; @@ -75,7 +75,7 @@ impl UserLocalDataMigration { let migration_name = migration.name().to_string(); if !duplicated_names.contains(&migration_name) { - migration.run(&self.session, &self.collab_db, authenticator)?; + migration.run(&self.session, &self.collab_db, auth_type, &mut conn)?; applied_migrations.push(migration.name().to_string()); save_migration_record(&mut conn, &migration_name); duplicated_names.push(migration_name); @@ -99,6 +99,7 @@ pub trait UserDataMigration { user: &Session, collab_db: &Arc, authenticator: &AuthType, + db: &mut SqliteConnection, ) -> FlowyResult<()>; } diff --git a/frontend/rust-lib/flowy-user/src/migrations/mod.rs b/frontend/rust-lib/flowy-user/src/migrations/mod.rs index c8d04edf66..3d87dc595f 100644 --- a/frontend/rust-lib/flowy-user/src/migrations/mod.rs +++ b/frontend/rust-lib/flowy-user/src/migrations/mod.rs @@ -1,6 +1,7 @@ use flowy_user_pub::session::Session; use std::sync::Arc; +pub mod anon_user_workspace; pub mod doc_key_with_workspace; pub mod document_empty_content; pub mod migration; diff --git a/frontend/rust-lib/flowy-user/src/migrations/workspace_and_favorite_v1.rs b/frontend/rust-lib/flowy-user/src/migrations/workspace_and_favorite_v1.rs index 51894f9a04..5f14051e26 100644 --- a/frontend/rust-lib/flowy-user/src/migrations/workspace_and_favorite_v1.rs +++ b/frontend/rust-lib/flowy-user/src/migrations/workspace_and_favorite_v1.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use collab_folder::Folder; use collab_plugins::local_storage::kv::{KVTransactionDB, PersistenceError}; +use diesel::SqliteConnection; use semver::Version; use tracing::instrument; @@ -40,6 +41,7 @@ impl UserDataMigration for FavoriteV1AndWorkspaceArrayMigration { session: &Session, collab_db: &Arc, _authenticator: &AuthType, + _db: &mut SqliteConnection, ) -> FlowyResult<()> { collab_db.with_write_txn(|write_txn| { if let Ok(collab) = load_collab( diff --git a/frontend/rust-lib/flowy-user/src/migrations/workspace_trash_v1.rs b/frontend/rust-lib/flowy-user/src/migrations/workspace_trash_v1.rs index 70123edb2c..b5eeead8c6 100644 --- a/frontend/rust-lib/flowy-user/src/migrations/workspace_trash_v1.rs +++ b/frontend/rust-lib/flowy-user/src/migrations/workspace_trash_v1.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use collab_folder::Folder; use collab_plugins::local_storage::kv::{KVTransactionDB, PersistenceError}; +use diesel::SqliteConnection; use semver::Version; use tracing::instrument; @@ -38,6 +39,7 @@ impl UserDataMigration for WorkspaceTrashMapToSectionMigration { session: &Session, collab_db: &Arc, _authenticator: &AuthType, + _db: &mut SqliteConnection, ) -> FlowyResult<()> { collab_db.with_write_txn(|write_txn| { if let Ok(collab) = load_collab( diff --git a/frontend/rust-lib/flowy-user/src/user_manager/manager.rs b/frontend/rust-lib/flowy-user/src/user_manager/manager.rs index f4c09d0af8..4299f0823b 100644 --- a/frontend/rust-lib/flowy-user/src/user_manager/manager.rs +++ b/frontend/rust-lib/flowy-user/src/user_manager/manager.rs @@ -38,6 +38,7 @@ use crate::services::authenticate_user::AuthenticateUser; use crate::services::cloud_config::get_cloud_config; use crate::services::collab_interact::{DefaultCollabInteract, UserReminder}; +use crate::migrations::anon_user_workspace::AnonUserWorkspaceTableMigration; use crate::migrations::doc_key_with_workspace::CollabDocKeyWithWorkspaceIdMigration; use crate::{errors::FlowyError, notification::*}; use flowy_user_pub::session::Session; @@ -849,6 +850,7 @@ fn collab_migration_list() -> Vec> { Box::new(FavoriteV1AndWorkspaceArrayMigration), Box::new(WorkspaceTrashMapToSectionMigration), Box::new(CollabDocKeyWithWorkspaceIdMigration), + Box::new(AnonUserWorkspaceTableMigration), ] } diff --git a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs index 20acb9866f..b68643c83b 100644 --- a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs +++ b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs @@ -157,8 +157,8 @@ impl UserManager { self.cloud_service.set_server_auth_type(&auth_type); let uid = self.user_id()?; - let conn = self.db_connection(self.user_id()?)?; - let user_workspace = match select_user_workspace(&workspace_id.to_string(), conn) { + let mut conn = self.db_connection(self.user_id()?)?; + let user_workspace = match select_user_workspace(&workspace_id.to_string(), &mut conn) { Err(err) => { if err.is_record_not_found() { sync_workspace( @@ -401,8 +401,8 @@ impl UserManager { uid: i64, workspace_id: &Uuid, ) -> FlowyResult { - let conn = self.db_connection(uid)?; - select_user_workspace(workspace_id.to_string().as_str(), conn) + let mut conn = self.db_connection(uid)?; + select_user_workspace(workspace_id.to_string().as_str(), &mut conn) } pub async fn get_all_user_workspaces(