chore: fix test

This commit is contained in:
Nathan 2025-04-22 23:20:15 +08:00
parent 7e88a3897c
commit db5e4766af
21 changed files with 297 additions and 278 deletions

View file

@ -144,34 +144,34 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
SPEC CHECKSUMS: SPEC CHECKSUMS:
app_links: 9028728e32c83a0831d9db8cf91c526d16cc5468 app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a
appflowy_backend: 464aeb3e5c6966a41641a2111e5ead72ce2695f7 appflowy_backend: 865496343de667fc8c600e04b9fd05234e130cf9
auto_updater_macos: 3a42f1a06be6981f1a18be37e6e7bf86aa732118 auto_updater_macos: 3e3462c418fe4e731917eacd8d28eef7af84086d
bitsdojo_window_macos: 7959fb0ca65a3ccda30095c181ecb856fae48ea9 bitsdojo_window_macos: 44e3b8fe3dd463820e0321f6256c5b1c16bb6a00
connectivity_plus: e74b9f74717d2d99d45751750e266e55912baeb5 connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747
desktop_drop: e0b672a7d84c0a6cbc378595e82cdb15f2970a43 desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 device_info_plus: 1b14eed9bf95428983aed283a8d51cce3d8c4215
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31 file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
flowy_infra_ui: 8760ff42a789de40bf5007a5f176b454722a341e flowy_infra_ui: 03301a39ad118771adbf051a664265c61c507f38
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
HotKey: 400beb7caa29054ea8d864c96f5ba7e5b4852277 HotKey: 400beb7caa29054ea8d864c96f5ba7e5b4852277
hotkey_manager: b443f35f4d772162937aa73fd8995e579f8ac4e2 hotkey_manager: c32bf0bfe8f934b7bc17ab4ad5c4c142960b023c
irondash_engine_context: 893c7d96d20ce361d7e996f39d360c4c2f9869ba irondash_engine_context: da62996ee25616d2f01bbeb85dc115d813359478
local_notifier: ebf072651e35ae5e47280ad52e2707375cb2ae4e local_notifier: e9506bc66fc70311e8bc7291fb70f743c081e4ff
package_info_plus: f0052d280d17aa382b932f399edf32507174e870 package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
Sentry: 1fe34e9c2cbba1e347623610d26db121dcb569f1 Sentry: 1fe34e9c2cbba1e347623610d26db121dcb569f1
sentry_flutter: e24b397f9a61fa5bbefd8279c3b2242ca86faa90 sentry_flutter: a39c2a2d67d5e5b9cb0b94a4985c76dd5b3fc737
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc share_plus: 1fa619de8392a4398bfaf176d441853922614e89
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
Sparkle: 5f8960a7a119aa7d45dacc0d5837017170bc5675 Sparkle: 5f8960a7a119aa7d45dacc0d5837017170bc5675
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
super_native_extensions: c2795d6d9aedf4a79fae25cb6160b71b50549189 super_native_extensions: 85efee3a7495b46b04befcfc86ed12069264ebf3
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404
webview_flutter_wkwebview: 44d4dee7d7056d5ad185d25b38404436d56c547c webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4
window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
PODFILE CHECKSUM: 0532f3f001ca3110b8be345d6491fff690e95823 PODFILE CHECKSUM: 0532f3f001ca3110b8be345d6491fff690e95823

View file

@ -11,7 +11,6 @@ async fn migrate_historical_empty_document_test() {
"historical_empty_document", "historical_empty_document",
) )
.unwrap(); .unwrap();
let s = user_db_path.to_str().unwrap().to_string();
let test = let test =
EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await; EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await;

View file

@ -104,7 +104,7 @@ impl AIManager {
} }
} }
async fn reload_with_workspace_id(&self, workspace_id: &str) { async fn reload_with_workspace_id(&self, workspace_id: &Uuid) {
// Check if local AI is enabled for this workspace and if we're in local mode // Check if local AI is enabled for this workspace and if we're in local mode
let result = self.user_service.is_local_model().await; let result = self.user_service.is_local_model().await;
if let Err(err) = &result { if let Err(err) = &result {
@ -115,7 +115,9 @@ impl AIManager {
} }
let is_local = result.unwrap_or(false); let is_local = result.unwrap_or(false);
let is_enabled = self.local_ai.is_enabled_on_workspace(workspace_id); let is_enabled = self
.local_ai
.is_enabled_on_workspace(&workspace_id.to_string());
let is_running = self.local_ai.is_running(); let is_running = self.local_ai.is_running();
info!( info!(
"[AI Manager] Reloading workspace: {}, is_local: {}, is_enabled: {}, is_running: {}", "[AI Manager] Reloading workspace: {}, is_local: {}, is_enabled: {}, is_running: {}",
@ -161,17 +163,17 @@ impl AIManager {
} }
#[instrument(skip_all, err)] #[instrument(skip_all, err)]
pub async fn on_launch_if_authenticated(&self, workspace_id: &str) -> Result<(), FlowyError> { pub async fn on_launch_if_authenticated(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
self.reload_with_workspace_id(workspace_id).await; self.reload_with_workspace_id(workspace_id).await;
Ok(()) Ok(())
} }
pub async fn initialize_after_sign_in(&self, workspace_id: &str) -> Result<(), FlowyError> { pub async fn initialize_after_sign_in(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
self.reload_with_workspace_id(workspace_id).await; self.reload_with_workspace_id(workspace_id).await;
Ok(()) Ok(())
} }
pub async fn initialize_after_sign_up(&self, workspace_id: &str) -> Result<(), FlowyError> { pub async fn initialize_after_sign_up(&self, workspace_id: &Uuid) -> Result<(), FlowyError> {
self.reload_with_workspace_id(workspace_id).await; self.reload_with_workspace_id(workspace_id).await;
Ok(()) Ok(())
} }
@ -181,9 +183,7 @@ impl AIManager {
&self, &self,
workspace_id: &Uuid, workspace_id: &Uuid,
) -> Result<(), FlowyError> { ) -> Result<(), FlowyError> {
self self.reload_with_workspace_id(workspace_id).await;
.reload_with_workspace_id(&workspace_id.to_string())
.await;
Ok(()) Ok(())
} }

View file

@ -81,11 +81,10 @@ impl UserStatusCallback for UserStatusCallbackImpl {
&self, &self,
user_id: i64, user_id: i64,
cloud_config: &Option<UserCloudConfig>, cloud_config: &Option<UserCloudConfig>,
user_workspace: &UserWorkspace, workspace_id: &Uuid,
_device_id: &str, _device_id: &str,
auth_type: &AuthType, auth_type: &AuthType,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
let workspace_id = user_workspace.workspace_id()?;
if let Some(cloud_config) = cloud_config { if let Some(cloud_config) = cloud_config {
self self
.server_provider .server_provider
@ -101,7 +100,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
.folder_manager .folder_manager
.initialize( .initialize(
user_id, user_id,
&workspace_id, workspace_id,
FolderInitDataSource::LocalDisk { FolderInitDataSource::LocalDisk {
create_if_not_exist: false, create_if_not_exist: false,
}, },
@ -113,8 +112,8 @@ impl UserStatusCallback for UserStatusCallbackImpl {
.await?; .await?;
self.document_manager.initialize(user_id).await?; self.document_manager.initialize(user_id).await?;
let workspace_id = user_workspace.id.clone();
let cloned_ai_manager = self.ai_manager.clone(); let cloned_ai_manager = self.ai_manager.clone();
let workspace_id = *workspace_id;
self.runtime.spawn(async move { self.runtime.spawn(async move {
if let Err(err) = cloned_ai_manager if let Err(err) = cloned_ai_manager
.on_launch_if_authenticated(&workspace_id) .on_launch_if_authenticated(&workspace_id)
@ -129,19 +128,18 @@ impl UserStatusCallback for UserStatusCallbackImpl {
async fn on_sign_in( async fn on_sign_in(
&self, &self,
user_id: i64, user_id: i64,
user_workspace: &UserWorkspace, workspace_id: &Uuid,
device_id: &str, device_id: &str,
auth_type: &AuthType, auth_type: &AuthType,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
event!( event!(
tracing::Level::TRACE, tracing::Level::TRACE,
"Notify did sign in: latest_workspace: {:?}, device_id: {}", "Notify did sign in: latest_workspace: {:?}, device_id: {}",
user_workspace, workspace_id,
device_id device_id
); );
let workspace_id = user_workspace.workspace_id()?;
let data_source = self let data_source = self
.folder_init_data_source(user_id, &workspace_id, auth_type) .folder_init_data_source(user_id, workspace_id, auth_type)
.await?; .await?;
self self
.folder_manager .folder_manager
@ -158,7 +156,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
self self
.ai_manager .ai_manager
.initialize_after_sign_in(&user_workspace.id) .initialize_after_sign_in(workspace_id)
.await?; .await?;
Ok(()) Ok(())
@ -168,7 +166,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
&self, &self,
is_new_user: bool, is_new_user: bool,
user_profile: &UserProfile, user_profile: &UserProfile,
user_workspace: &UserWorkspace, workspace_id: &Uuid,
device_id: &str, device_id: &str,
auth_type: &AuthType, auth_type: &AuthType,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
@ -176,12 +174,11 @@ impl UserStatusCallback for UserStatusCallbackImpl {
tracing::Level::TRACE, tracing::Level::TRACE,
"Notify did sign up: is new: {} user_workspace: {:?}, device_id: {}", "Notify did sign up: is new: {} user_workspace: {:?}, device_id: {}",
is_new_user, is_new_user,
user_workspace, workspace_id,
device_id device_id
); );
let workspace_id = user_workspace.workspace_id()?;
let data_source = self let data_source = self
.folder_init_data_source(user_profile.uid, &workspace_id, auth_type) .folder_init_data_source(user_profile.uid, workspace_id, auth_type)
.await?; .await?;
self self
@ -191,7 +188,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
&user_profile.token, &user_profile.token,
is_new_user, is_new_user,
data_source, data_source,
&workspace_id, workspace_id,
) )
.await .await
.context("FolderManager error")?; .context("FolderManager error")?;
@ -210,7 +207,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
self self
.ai_manager .ai_manager
.initialize_after_sign_up(&user_workspace.id) .initialize_after_sign_up(workspace_id)
.await?; .await?;
Ok(()) Ok(())
} }

View file

@ -1,106 +1,26 @@
use crate::entities::{AuthType, UserAuthResponse, UserWorkspace}; use crate::entities::UserAuthResponse;
use base64::engine::general_purpose::STANDARD; use serde::{Deserialize, Serialize};
use base64::Engine;
use chrono::Utc;
use serde::de::{MapAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value;
use std::fmt; use std::fmt;
use std::fmt::Display; use std::fmt::Display;
use uuid::Uuid; use uuid::Uuid;
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Session { pub struct Session {
pub user_id: i64, pub user_id: i64,
pub user_uuid: Uuid, pub user_uuid: Uuid,
pub user_workspace: UserWorkspace, pub workspace_id: String,
} }
impl Display for Session { impl Display for Session {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"user_id: {}, user_workspace: {}:{}", "user_id: {}, user_workspace: {}",
self.user_id, self.user_workspace.name, self.user_workspace.id, self.user_id, self.workspace_id,
) )
} }
} }
struct SessionVisitor;
impl<'de> Visitor<'de> for SessionVisitor {
type Value = Session;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Session")
}
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut user_id = None;
let mut user_uuid = None;
// For historical reasons, the session used to contain a workspace_id field.
// This field is no longer used, and is replaced by user_workspace.
let mut workspace_id = None;
let mut user_workspace = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"user_id" => {
user_id = Some(map.next_value()?);
},
"user_uuid" => {
user_uuid = Some(map.next_value()?);
},
"workspace_id" => {
workspace_id = Some(map.next_value()?);
},
"user_workspace" => {
user_workspace = Some(map.next_value()?);
},
_ => {
let _ = map.next_value::<Value>();
},
}
}
let user_id = user_id.ok_or(serde::de::Error::missing_field("user_id"))?;
let user_uuid = user_uuid.ok_or(serde::de::Error::missing_field("user_uuid"))?;
if user_workspace.is_none() {
if let Some(workspace_id) = workspace_id {
user_workspace = Some(UserWorkspace {
id: workspace_id,
name: "My Workspace".to_string(),
created_at: Utc::now(),
// For historical reasons, the database_storage_id is constructed by the user_id.
workspace_database_id: STANDARD.encode(format!("{}:user:database", user_id)),
icon: "".to_owned(),
member_count: 1,
role: None,
workspace_type: AuthType::Local,
})
}
}
let session = Session {
user_id,
user_uuid,
user_workspace: user_workspace.ok_or(serde::de::Error::missing_field("user_workspace"))?,
};
Ok(session)
}
}
impl<'de> Deserialize<'de> for Session {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(SessionVisitor)
}
}
impl<T> From<&T> for Session impl<T> From<&T> for Session
where where
T: UserAuthResponse, T: UserAuthResponse,
@ -109,7 +29,7 @@ where
Self { Self {
user_id: value.user_id(), user_id: value.user_id(),
user_uuid: *value.user_uuid(), user_uuid: *value.user_uuid(),
user_workspace: value.latest_workspace().clone(), workspace_id: value.latest_workspace().clone().id,
} }
} }
} }

View file

@ -99,6 +99,17 @@ pub fn select_user_workspace(
Ok(row) Ok(row)
} }
pub fn select_user_workspace_type(
workspace_id: &str,
conn: &mut SqliteConnection,
) -> FlowyResult<AuthType> {
let row = dsl::user_workspace_table
.filter(user_workspace_table::id.eq(workspace_id))
.select(user_workspace_table::workspace_type)
.first::<i32>(conn)?;
Ok(AuthType::from(row))
}
pub fn select_all_user_workspace( pub fn select_all_user_workspace(
uid: i64, uid: i64,
conn: &mut SqliteConnection, conn: &mut SqliteConnection,

View file

@ -94,12 +94,12 @@ pub async fn get_user_profile_handler(
let session = manager.get_session()?; let session = manager.get_session()?;
let mut user_profile = manager let mut user_profile = manager
.get_user_profile_from_disk(session.user_id, &session.user_workspace.id) .get_user_profile_from_disk(session.user_id, &session.workspace_id)
.await?; .await?;
let weak_manager = Arc::downgrade(&manager); let weak_manager = Arc::downgrade(&manager);
let cloned_user_profile = user_profile.clone(); let cloned_user_profile = user_profile.clone();
let workspace_id = session.user_workspace.id.clone(); let workspace_id = session.workspace_id.clone();
// Refresh the user profile in the background // Refresh the user profile in the background
tokio::spawn(async move { tokio::spawn(async move {
@ -433,7 +433,7 @@ pub async fn get_all_workspace_handler(
let manager = upgrade_manager(manager)?; let manager = upgrade_manager(manager)?;
let session = manager.get_session()?; let session = manager.get_session()?;
let profile = manager let profile = manager
.get_user_profile_from_disk(session.user_id, &session.user_workspace.id) .get_user_profile_from_disk(session.user_id, &session.workspace_id)
.await?; .await?;
let user_workspaces = manager let user_workspaces = manager
.get_all_user_workspaces(profile.uid, profile.auth_type) .get_all_user_workspaces(profile.uid, profile.auth_type)
@ -822,7 +822,7 @@ pub async fn get_workspace_member_info(
manager: AFPluginState<Weak<UserManager>>, manager: AFPluginState<Weak<UserManager>>,
) -> DataResult<WorkspaceMemberPB, FlowyError> { ) -> DataResult<WorkspaceMemberPB, FlowyError> {
let manager = upgrade_manager(manager)?; let manager = upgrade_manager(manager)?;
let workspace_id = manager.get_session()?.user_workspace.workspace_id()?; let workspace_id = Uuid::parse_str(&manager.get_session()?.workspace_id)?;
let member = manager let member = manager
.get_workspace_member_info(param.uid, &workspace_id) .get_workspace_member_info(param.uid, &workspace_id)
.await?; .await?;

View file

@ -285,7 +285,7 @@ pub trait UserStatusCallback: Send + Sync + 'static {
&self, &self,
_user_id: i64, _user_id: i64,
_cloud_config: &Option<UserCloudConfig>, _cloud_config: &Option<UserCloudConfig>,
_user_workspace: &UserWorkspace, _workspace_id: &Uuid,
_device_id: &str, _device_id: &str,
_auth_type: &AuthType, _auth_type: &AuthType,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
@ -300,7 +300,7 @@ pub trait UserStatusCallback: Send + Sync + 'static {
async fn on_sign_in( async fn on_sign_in(
&self, &self,
_user_id: i64, _user_id: i64,
_user_workspace: &UserWorkspace, _workspace_id: &Uuid,
_device_id: &str, _device_id: &str,
_auth_type: &AuthType, _auth_type: &AuthType,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
@ -312,7 +312,7 @@ pub trait UserStatusCallback: Send + Sync + 'static {
&self, &self,
_is_new_user: bool, _is_new_user: bool,
_user_profile: &UserProfile, _user_profile: &UserProfile,
_user_workspace: &UserWorkspace, _workspace_id: &Uuid,
_device_id: &str, _device_id: &str,
_auth_type: &AuthType, _auth_type: &AuthType,
) -> FlowyResult<()> { ) -> FlowyResult<()> {

View file

@ -5,11 +5,13 @@ use tracing::instrument;
use collab_integrate::CollabKVDB; use collab_integrate::CollabKVDB;
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use flowy_sqlite::kv::KVStorePreferences;
use flowy_user_pub::entities::AuthType; use flowy_user_pub::entities::AuthType;
use crate::migrations::migration::UserDataMigration; use crate::migrations::migration::UserDataMigration;
use crate::migrations::session_migration::get_session_workspace;
use flowy_user_pub::session::Session; use flowy_user_pub::session::Session;
use flowy_user_pub::sql::upsert_user_workspace; use flowy_user_pub::sql::{select_user_workspace, upsert_user_workspace};
pub struct AnonUserWorkspaceTableMigration; pub struct AnonUserWorkspaceTableMigration;
@ -32,17 +34,21 @@ impl UserDataMigration for AnonUserWorkspaceTableMigration {
#[instrument(name = "AnonUserWorkspaceTableMigration", skip_all, err)] #[instrument(name = "AnonUserWorkspaceTableMigration", skip_all, err)]
fn run( fn run(
&self, &self,
session: &Session, user: &Session,
_collab_db: &Arc<CollabKVDB>, _collab_db: &Arc<CollabKVDB>,
user_auth_type: &AuthType, user_auth_type: &AuthType,
db: &mut SqliteConnection, db: &mut SqliteConnection,
store_preferences: &Arc<KVStorePreferences>,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
// For historical reason, anon user doesn't have a workspace in user_workspace_table. // 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. // So we need to create a new entry for the anon user in the user_workspace_table.
if matches!(user_auth_type, AuthType::Local) { if matches!(user_auth_type, AuthType::Local) {
let mut user_workspace = session.user_workspace.clone(); if let Some(mut user_workspace) = get_session_workspace(store_preferences) {
if select_user_workspace(&user_workspace.id, db).ok().is_none() {
user_workspace.workspace_type = AuthType::Local; user_workspace.workspace_type = AuthType::Local;
upsert_user_workspace(session.user_id, *user_auth_type, user_workspace, db)?; upsert_user_workspace(user.user_id, *user_auth_type, user_workspace, db)?;
}
}
} }
Ok(()) Ok(())

View file

@ -8,6 +8,7 @@ use tracing::{instrument, trace};
use collab_integrate::CollabKVDB; use collab_integrate::CollabKVDB;
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use flowy_sqlite::kv::KVStorePreferences;
use flowy_user_pub::entities::AuthType; use flowy_user_pub::entities::AuthType;
use crate::migrations::migration::UserDataMigration; use crate::migrations::migration::UserDataMigration;
@ -38,17 +39,15 @@ impl UserDataMigration for CollabDocKeyWithWorkspaceIdMigration {
#[instrument(name = "CollabDocKeyWithWorkspaceIdMigration", skip_all, err)] #[instrument(name = "CollabDocKeyWithWorkspaceIdMigration", skip_all, err)]
fn run( fn run(
&self, &self,
session: &Session, user: &Session,
collab_db: &Arc<CollabKVDB>, collab_db: &Arc<CollabKVDB>,
_user_auth_type: &AuthType, _user_auth_type: &AuthType,
_db: &mut SqliteConnection, _db: &mut SqliteConnection,
_store_preferences: &Arc<KVStorePreferences>,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
trace!( trace!("migrate key with workspace id:{}", user.workspace_id);
"migrate key with workspace id:{}",
session.user_workspace.id
);
collab_db.with_write_txn(|txn| { collab_db.with_write_txn(|txn| {
migrate_old_keys(txn, &session.user_workspace.id)?; migrate_old_keys(txn, &user.workspace_id)?;
Ok(()) Ok(())
})?; })?;
Ok(()) Ok(())

View file

@ -12,6 +12,7 @@ use tracing::{event, instrument};
use collab_integrate::{CollabKVAction, CollabKVDB, PersistenceError}; use collab_integrate::{CollabKVAction, CollabKVDB, PersistenceError};
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use flowy_sqlite::kv::KVStorePreferences;
use flowy_user_pub::entities::AuthType; use flowy_user_pub::entities::AuthType;
use crate::migrations::migration::UserDataMigration; use crate::migrations::migration::UserDataMigration;
@ -40,10 +41,11 @@ impl UserDataMigration for HistoricalEmptyDocumentMigration {
#[instrument(name = "HistoricalEmptyDocumentMigration", skip_all, err)] #[instrument(name = "HistoricalEmptyDocumentMigration", skip_all, err)]
fn run( fn run(
&self, &self,
session: &Session, user: &Session,
collab_db: &Arc<CollabKVDB>, collab_db: &Arc<CollabKVDB>,
user_auth_type: &AuthType, user_auth_type: &AuthType,
_db: &mut SqliteConnection, _db: &mut SqliteConnection,
_store_preferences: &Arc<KVStorePreferences>,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
// - The `empty document` struct has already undergone refactoring prior to the launch of the AppFlowy cloud version. // - 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. // - Consequently, if a user is utilizing the AppFlowy cloud version, there is no need to perform any migration for the `empty document` struct.
@ -52,31 +54,25 @@ impl UserDataMigration for HistoricalEmptyDocumentMigration {
return Ok(()); return Ok(());
} }
collab_db.with_write_txn(|write_txn| { collab_db.with_write_txn(|write_txn| {
let origin = CollabOrigin::Client(CollabClient::new(session.user_id, "phantom")); let origin = CollabOrigin::Client(CollabClient::new(user.user_id, "phantom"));
let folder_collab = match load_collab( let folder_collab = match load_collab(
session.user_id, user.user_id,
write_txn, write_txn,
&session.user_workspace.id, &user.workspace_id,
&session.user_workspace.id, &user.workspace_id,
) { ) {
Ok(fc) => fc, Ok(fc) => fc,
Err(_) => return Ok(()), Err(_) => return Ok(()),
}; };
let folder = Folder::open(session.user_id, folder_collab, None) let folder = Folder::open(user.user_id, folder_collab, None)
.map_err(|err| PersistenceError::Internal(err.into()))?; .map_err(|err| PersistenceError::Internal(err.into()))?;
if let Some(workspace_id) = folder.get_workspace_id() { if let Some(workspace_id) = folder.get_workspace_id() {
let migration_views = folder.get_views_belong_to(&workspace_id); let migration_views = folder.get_views_belong_to(&workspace_id);
// For historical reasons, the first level documents are empty. So migrate them by inserting // For historical reasons, the first level documents are empty. So migrate them by inserting
// the default document data. // the default document data.
for view in migration_views { for view in migration_views {
if migrate_empty_document( if migrate_empty_document(write_txn, &origin, &view, user.user_id, &user.workspace_id)
write_txn,
&origin,
&view,
session.user_id,
&session.user_workspace.id,
)
.is_err() .is_err()
{ {
event!( event!(

View file

@ -75,7 +75,13 @@ impl UserLocalDataMigration {
let migration_name = migration.name().to_string(); let migration_name = migration.name().to_string();
if !duplicated_names.contains(&migration_name) { if !duplicated_names.contains(&migration_name) {
migration.run(&self.session, &self.collab_db, user_auth_type, &mut conn)?; migration.run(
&self.session,
&self.collab_db,
user_auth_type,
&mut conn,
&self.kv,
)?;
applied_migrations.push(migration.name().to_string()); applied_migrations.push(migration.name().to_string());
save_migration_record(&mut conn, &migration_name); save_migration_record(&mut conn, &migration_name);
duplicated_names.push(migration_name); duplicated_names.push(migration_name);
@ -100,6 +106,7 @@ pub trait UserDataMigration {
collab_db: &Arc<CollabKVDB>, collab_db: &Arc<CollabKVDB>,
user_auth_type: &AuthType, user_auth_type: &AuthType,
db: &mut SqliteConnection, db: &mut SqliteConnection,
store_preferences: &Arc<KVStorePreferences>,
) -> FlowyResult<()>; ) -> FlowyResult<()>;
} }

View file

@ -1,45 +1,120 @@
use crate::user_manager::manager_history_user::ANON_USER; use chrono::Utc;
use flowy_sqlite::kv::KVStorePreferences; use flowy_sqlite::kv::KVStorePreferences;
use flowy_user_pub::entities::AuthType; use flowy_user_pub::entities::{AuthType, Role, UserWorkspace};
use flowy_user_pub::session::Session; use flowy_user_pub::session::Session;
use serde_json::{json, Value}; use serde::de::{MapAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value;
use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use uuid::Uuid; use uuid::Uuid;
const MIGRATION_USER_NO_USER_UUID: &str = "migration_user_no_user_uuid"; const MIGRATION_SESSION: &str = "migration_session_key";
pub const SESSION_CACHE_KEY_BACKUP: &str = "session_cache_key_backup";
pub fn migrate_session( pub fn migrate_session(
session_cache_key: &str, session_cache_key: &str,
store_preferences: &Arc<KVStorePreferences>, store_preferences: &Arc<KVStorePreferences>,
) -> Option<Session> { ) -> Option<Session> {
if !store_preferences.get_bool_or_default(MIGRATION_USER_NO_USER_UUID) if !store_preferences.get_bool_or_default(MIGRATION_SESSION)
&& store_preferences && store_preferences.set_bool(MIGRATION_SESSION, true).is_ok()
.set_bool(MIGRATION_USER_NO_USER_UUID, true)
.is_ok()
{ {
if let Some(mut value) = store_preferences.get_object::<Value>(session_cache_key) { if let Some(session) = store_preferences.get_object::<SessionBackup>(session_cache_key) {
if value.get("user_uuid").is_none() { let _ = store_preferences.set_object(SESSION_CACHE_KEY_BACKUP, &session);
if let Some(map) = value.as_object_mut() { let new_session = Session {
map.insert("user_uuid".to_string(), json!(Uuid::new_v4())); user_id: session.user_id,
} user_uuid: session.user_uuid,
} workspace_id: session.user_workspace.id,
};
if let Ok(new_session) = serde_json::from_value::<Session>(value) {
let _ = store_preferences.set_object(session_cache_key, &new_session); let _ = store_preferences.set_object(session_cache_key, &new_session);
} }
} }
}
if let Some(mut session) = store_preferences.get_object::<Session>(session_cache_key) {
if let Some(anon_session) = store_preferences.get_object::<Session>(ANON_USER) {
if session.user_id == anon_session.user_id
&& session.user_workspace.workspace_type != AuthType::Local
{
session.user_workspace.workspace_type = AuthType::Local;
let _ = store_preferences.set_object(session_cache_key, &session);
}
}
}
store_preferences.get_object::<Session>(session_cache_key) store_preferences.get_object::<Session>(session_cache_key)
} }
#[derive(Debug, Clone, Serialize)]
struct SessionBackup {
user_id: i64,
user_uuid: Uuid,
user_workspace: UserWorkspace,
}
pub fn get_session_workspace(store_preferences: &Arc<KVStorePreferences>) -> Option<UserWorkspace> {
store_preferences
.get_object::<SessionBackup>(SESSION_CACHE_KEY_BACKUP)
.map(|v| v.user_workspace)
}
struct SessionVisitor;
impl<'de> Visitor<'de> for SessionVisitor {
type Value = SessionBackup;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("SessionBackup")
}
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut user_id = None;
let mut user_uuid = None;
// For historical reasons, the session used to contain a workspace_id field.
// This field is no longer used, and is replaced by user_workspace.
let mut workspace_id = None;
let mut user_workspace = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"user_id" => {
user_id = Some(map.next_value()?);
},
"user_uuid" => {
user_uuid = Some(map.next_value()?);
},
"workspace_id" => {
workspace_id = Some(map.next_value()?);
},
"user_workspace" => {
user_workspace = Some(map.next_value()?);
},
_ => {
let _ = map.next_value::<Value>();
},
}
}
let user_id = user_id.ok_or(serde::de::Error::missing_field("user_id"))?;
let user_uuid = user_uuid.unwrap_or_else(Uuid::new_v4);
if user_workspace.is_none() {
if let Some(workspace_id) = workspace_id {
user_workspace = Some(UserWorkspace {
id: workspace_id,
name: "My Workspace".to_string(),
created_at: Utc::now(),
workspace_database_id: Uuid::new_v4().to_string(),
icon: "".to_owned(),
member_count: 1,
role: Some(Role::Owner),
workspace_type: AuthType::Local,
})
}
}
let session = SessionBackup {
user_id,
user_uuid,
user_workspace: user_workspace.ok_or(serde::de::Error::missing_field("user_workspace"))?,
};
Ok(session)
}
}
impl<'de> Deserialize<'de> for SessionBackup {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(SessionVisitor)
}
}

View file

@ -8,6 +8,7 @@ use tracing::instrument;
use collab_integrate::{CollabKVAction, CollabKVDB}; use collab_integrate::{CollabKVAction, CollabKVDB};
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use flowy_sqlite::kv::KVStorePreferences;
use flowy_user_pub::entities::AuthType; use flowy_user_pub::entities::AuthType;
use crate::migrations::migration::UserDataMigration; use crate::migrations::migration::UserDataMigration;
@ -38,19 +39,20 @@ impl UserDataMigration for FavoriteV1AndWorkspaceArrayMigration {
#[instrument(name = "FavoriteV1AndWorkspaceArrayMigration", skip_all, err)] #[instrument(name = "FavoriteV1AndWorkspaceArrayMigration", skip_all, err)]
fn run( fn run(
&self, &self,
session: &Session, user: &Session,
collab_db: &Arc<CollabKVDB>, collab_db: &Arc<CollabKVDB>,
_user_auth_type: &AuthType, _user_auth_type: &AuthType,
_db: &mut SqliteConnection, _db: &mut SqliteConnection,
_store_preferences: &Arc<KVStorePreferences>,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
collab_db.with_write_txn(|write_txn| { collab_db.with_write_txn(|write_txn| {
if let Ok(collab) = load_collab( if let Ok(collab) = load_collab(
session.user_id, user.user_id,
write_txn, write_txn,
&session.user_workspace.id, &user.workspace_id,
&session.user_workspace.id, &user.workspace_id,
) { ) {
let mut folder = Folder::open(session.user_id, collab, None) let mut folder = Folder::open(user.user_id, collab, None)
.map_err(|err| PersistenceError::Internal(err.into()))?; .map_err(|err| PersistenceError::Internal(err.into()))?;
folder folder
.body .body
@ -70,9 +72,9 @@ impl UserDataMigration for FavoriteV1AndWorkspaceArrayMigration {
.encode_collab() .encode_collab()
.map_err(|err| PersistenceError::Internal(err.into()))?; .map_err(|err| PersistenceError::Internal(err.into()))?;
write_txn.flush_doc( write_txn.flush_doc(
session.user_id, user.user_id,
&session.user_workspace.id, &user.workspace_id,
&session.user_workspace.id, &user.workspace_id,
encode.state_vector.to_vec(), encode.state_vector.to_vec(),
encode.doc_state.to_vec(), encode.doc_state.to_vec(),
)?; )?;

View file

@ -8,6 +8,7 @@ use tracing::instrument;
use collab_integrate::{CollabKVAction, CollabKVDB}; use collab_integrate::{CollabKVAction, CollabKVDB};
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use flowy_sqlite::kv::KVStorePreferences;
use flowy_user_pub::entities::AuthType; use flowy_user_pub::entities::AuthType;
use crate::migrations::migration::UserDataMigration; use crate::migrations::migration::UserDataMigration;
@ -36,19 +37,20 @@ impl UserDataMigration for WorkspaceTrashMapToSectionMigration {
#[instrument(name = "WorkspaceTrashMapToSectionMigration", skip_all, err)] #[instrument(name = "WorkspaceTrashMapToSectionMigration", skip_all, err)]
fn run( fn run(
&self, &self,
session: &Session, user: &Session,
collab_db: &Arc<CollabKVDB>, collab_db: &Arc<CollabKVDB>,
_user_auth_type: &AuthType, _user_auth_type: &AuthType,
_db: &mut SqliteConnection, _db: &mut SqliteConnection,
_store_preferences: &Arc<KVStorePreferences>,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
collab_db.with_write_txn(|write_txn| { collab_db.with_write_txn(|write_txn| {
if let Ok(collab) = load_collab( if let Ok(collab) = load_collab(
session.user_id, user.user_id,
write_txn, write_txn,
&session.user_workspace.id, &user.workspace_id,
&session.user_workspace.id, &user.workspace_id,
) { ) {
let mut folder = Folder::open(session.user_id, collab, None) let mut folder = Folder::open(user.user_id, collab, None)
.map_err(|err| PersistenceError::Internal(err.into()))?; .map_err(|err| PersistenceError::Internal(err.into()))?;
let trash_ids = folder let trash_ids = folder
.get_trash_v1() .get_trash_v1()
@ -64,9 +66,9 @@ impl UserDataMigration for WorkspaceTrashMapToSectionMigration {
.encode_collab() .encode_collab()
.map_err(|err| PersistenceError::Internal(err.into()))?; .map_err(|err| PersistenceError::Internal(err.into()))?;
write_txn.flush_doc( write_txn.flush_doc(
session.user_id, user.user_id,
&session.user_workspace.id, &user.workspace_id,
&session.user_workspace.id, &user.workspace_id,
encode.state_vector.to_vec(), encode.state_vector.to_vec(),
encode.doc_state.to_vec(), encode.doc_state.to_vec(),
)?; )?;

View file

@ -11,6 +11,7 @@ use flowy_sqlite::kv::KVStorePreferences;
use flowy_sqlite::DBConnection; use flowy_sqlite::DBConnection;
use flowy_user_pub::entities::{AuthType, UserWorkspace}; use flowy_user_pub::entities::{AuthType, UserWorkspace};
use flowy_user_pub::session::Session; use flowy_user_pub::session::Session;
use flowy_user_pub::sql::{select_user_workspace, select_user_workspace_type};
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
@ -46,10 +47,9 @@ impl AuthenticateUser {
pub async fn is_local_mode(&self) -> FlowyResult<bool> { pub async fn is_local_mode(&self) -> FlowyResult<bool> {
let session = self.get_session()?; let session = self.get_session()?;
Ok(matches!( let mut conn = self.get_sqlite_connection(session.user_id)?;
session.user_workspace.workspace_type, let workspace_type = select_user_workspace_type(&session.workspace_id, &mut conn)?;
AuthType::Local Ok(matches!(workspace_type, AuthType::Local))
))
} }
pub fn device_id(&self) -> FlowyResult<String> { pub fn device_id(&self) -> FlowyResult<String> {
@ -58,13 +58,15 @@ impl AuthenticateUser {
pub fn workspace_id(&self) -> FlowyResult<Uuid> { pub fn workspace_id(&self) -> FlowyResult<Uuid> {
let session = self.get_session()?; let session = self.get_session()?;
let workspace_uuid = Uuid::from_str(&session.user_workspace.id)?; let workspace_uuid = Uuid::from_str(&session.workspace_id)?;
Ok(workspace_uuid) Ok(workspace_uuid)
} }
pub fn workspace_database_object_id(&self) -> FlowyResult<Uuid> { pub fn workspace_database_object_id(&self) -> FlowyResult<Uuid> {
let session = self.get_session()?; let session = self.get_session()?;
let id = Uuid::from_str(&session.user_workspace.workspace_database_id)?; let mut conn = self.get_sqlite_connection(session.user_id)?;
let workspace = select_user_workspace(&session.workspace_id, &mut conn)?;
let id = Uuid::from_str(&workspace.database_storage_id)?;
Ok(id) Ok(id)
} }
@ -104,7 +106,7 @@ impl AuthenticateUser {
let session = self.get_session()?; let session = self.get_session()?;
let collab_db = self.database.get_collab_db(uid)?; let collab_db = self.database.get_collab_db(uid)?;
let read_txn = collab_db.read_txn(); let read_txn = collab_db.read_txn();
Ok(read_txn.is_exist(uid, session.user_workspace.id.as_str(), object_id)) Ok(read_txn.is_exist(uid, session.workspace_id.as_str(), object_id))
} }
pub fn set_session(&self, session: Option<Arc<Session>>) -> Result<(), FlowyError> { pub fn set_session(&self, session: Option<Arc<Session>>) -> Result<(), FlowyError> {
@ -133,7 +135,7 @@ impl AuthenticateUser {
self.set_session(Some(Arc::new(Session { self.set_session(Some(Arc::new(Session {
user_id: session.user_id, user_id: session.user_id,
user_uuid: session.user_uuid, user_uuid: session.user_uuid,
user_workspace, workspace_id: user_workspace.id,
}))) })))
} }

View file

@ -1,4 +1,4 @@
use crate::migrations::session_migration::migrate_session; use crate::migrations::session_migration::{get_session_workspace, migrate_session};
use crate::services::data_import::importer::load_collab_by_object_ids; use crate::services::data_import::importer::load_collab_by_object_ids;
use crate::services::db::UserDBPath; use crate::services::db::UserDBPath;
@ -51,6 +51,7 @@ pub(crate) struct ImportedFolder {
pub container_name: Option<String>, pub container_name: Option<String>,
pub parent_view_id: Option<String>, pub parent_view_id: Option<String>,
pub source: ImportedSource, pub source: ImportedSource,
pub workspace_database_id: String,
} }
#[derive(Clone)] #[derive(Clone)]
@ -81,6 +82,11 @@ pub(crate) fn prepare_import(
let user_paths = UserPaths::new(path.to_string()); let user_paths = UserPaths::new(path.to_string());
let other_store_preferences = Arc::new(KVStorePreferences::new(path)?); let other_store_preferences = Arc::new(KVStorePreferences::new(path)?);
migrate_session("appflowy_session_cache", &other_store_preferences); migrate_session("appflowy_session_cache", &other_store_preferences);
let session_workspace = get_session_workspace(&other_store_preferences)
.ok_or(anyhow!("Can't find the session workspace"))?;
let workspace_database_id = session_workspace.workspace_database_id;
let imported_session = other_store_preferences let imported_session = other_store_preferences
.get_object::<Session>("appflowy_session_cache") .get_object::<Session>("appflowy_session_cache")
.ok_or(anyhow!( .ok_or(anyhow!(
@ -105,7 +111,7 @@ pub(crate) fn prepare_import(
let mut conn = imported_sqlite_db.get_connection()?; let mut conn = imported_sqlite_db.get_connection()?;
let imported_user_auth_type = select_user_profile( let imported_user_auth_type = select_user_profile(
imported_session.user_id, imported_session.user_id,
&imported_session.user_workspace.id, &imported_session.workspace_id,
&mut conn, &mut conn,
) )
.map(|v| v.auth_type) .map(|v| v.auth_type)
@ -126,6 +132,7 @@ pub(crate) fn prepare_import(
container_name: None, container_name: None,
parent_view_id, parent_view_id,
source: ImportedSource::ExternalFolder, source: ImportedSource::ExternalFolder,
workspace_database_id,
}) })
} }
@ -154,13 +161,13 @@ pub(crate) fn generate_import_data(
imported_folder: ImportedFolder, imported_folder: ImportedFolder,
) -> anyhow::Result<ImportedAppFlowyData> { ) -> anyhow::Result<ImportedAppFlowyData> {
info!( info!(
"[AppflowyData]:importing workspace: {}:{}", "[AppflowyData]:importing workspace: {}",
imported_folder.imported_session.user_workspace.name, imported_folder.imported_session.workspace_id,
imported_folder.imported_session.user_workspace.id,
); );
let workspace_id = current_session.user_workspace.id.clone(); let workspace_id = current_session.workspace_id.clone();
let imported_workspace_id = imported_folder.imported_session.user_workspace.id.clone(); let imported_workspace_id = imported_folder.imported_session.workspace_id.clone();
let imported_session = imported_folder.imported_session.clone(); let imported_session = imported_folder.imported_session.clone();
let imported_workspace_database_id = imported_folder.workspace_database_id.clone();
let imported_collab_db = imported_folder.imported_collab_db.clone(); let imported_collab_db = imported_folder.imported_collab_db.clone();
let imported_container_view_name = imported_folder.container_name.clone(); let imported_container_view_name = imported_folder.container_name.clone();
@ -202,18 +209,18 @@ pub(crate) fn generate_import_data(
// 2. workspace database views // 2. workspace database views
// 3. user awareness // 3. user awareness
// So we remove these object ids from the list // So we remove these object ids from the list
let user_workspace_id = &imported_session.user_workspace.id; let user_workspace_id = &imported_session.workspace_id;
let workspace_database_id = &imported_session.user_workspace.workspace_database_id;
let user_awareness_id = let user_awareness_id =
user_awareness_object_id(&imported_session.user_uuid, user_workspace_id).to_string(); user_awareness_object_id(&imported_session.user_uuid, user_workspace_id).to_string();
all_imported_object_ids.retain(|id| { all_imported_object_ids.retain(|id| {
id != user_workspace_id && id != workspace_database_id && id != &user_awareness_id id != user_workspace_id && id != &imported_workspace_database_id && id != &user_awareness_id
}); });
// 2. mapping the workspace database ids // 2. mapping the workspace database ids
if let Err(err) = mapping_workspace_database_ids( if let Err(err) = mapping_workspace_database_ids(
&mut old_to_new_id_map, &mut old_to_new_id_map,
&imported_session, &imported_session,
&imported_workspace_database_id,
&imported_collab_db_read_txn, &imported_collab_db_read_txn,
&mut database_view_ids_by_database_id, &mut database_view_ids_by_database_id,
&mut database_object_ids, &mut database_object_ids,
@ -293,7 +300,7 @@ pub(crate) fn generate_import_data(
for view_id in not_exist_parent_view_ids { for view_id in not_exist_parent_view_ids {
if let Err(err) = create_empty_document_for_view( if let Err(err) = create_empty_document_for_view(
current_session.user_id, current_session.user_id,
&current_session.user_workspace.id, &current_session.workspace_id,
&view_id, &view_id,
current_collab_db_write_txn, current_collab_db_write_txn,
) { ) {
@ -489,7 +496,7 @@ where
write_collab_object( write_collab_object(
&collab, &collab,
current_session.user_id, current_session.user_id,
current_session.user_workspace.id.as_str(), current_session.workspace_id.as_str(),
import_container_view_id, import_container_view_id,
collab_write_txn, collab_write_txn,
CollabType::Document, CollabType::Document,
@ -499,7 +506,7 @@ where
let import_container_views = NestedChildViewBuilder::new( let import_container_views = NestedChildViewBuilder::new(
current_session.user_id, current_session.user_id,
current_session.user_workspace.id.clone(), current_session.workspace_id.clone(),
) )
.with_view_id(import_container_view_id) .with_view_id(import_container_view_id)
.with_layout(ViewLayout::Document) .with_layout(ViewLayout::Document)
@ -514,6 +521,7 @@ where
fn mapping_workspace_database_ids<'a, W>( fn mapping_workspace_database_ids<'a, W>(
old_to_new_id_map: &mut OldToNewIdMap, old_to_new_id_map: &mut OldToNewIdMap,
imported_session: &Session, imported_session: &Session,
imported_session_workspace_database_id: &str,
imported_collab_db_read_txn: &W, imported_collab_db_read_txn: &W,
database_view_ids_by_database_id: &mut HashMap<String, Vec<String>>, database_view_ids_by_database_id: &mut HashMap<String, Vec<String>>,
database_object_ids: &mut HashSet<String>, database_object_ids: &mut HashSet<String>,
@ -524,20 +532,20 @@ where
{ {
let mut workspace_database_collab = Collab::new( let mut workspace_database_collab = Collab::new(
imported_session.user_id, imported_session.user_id,
&imported_session.user_workspace.workspace_database_id, imported_session_workspace_database_id,
"import_device", "import_device",
vec![], vec![],
false, false,
); );
imported_collab_db_read_txn.load_doc_with_txn( imported_collab_db_read_txn.load_doc_with_txn(
imported_session.user_id, imported_session.user_id,
&imported_session.user_workspace.id, &imported_session.workspace_id,
&imported_session.user_workspace.workspace_database_id, imported_session_workspace_database_id,
&mut workspace_database_collab.transact_mut(), &mut workspace_database_collab.transact_mut(),
)?; )?;
let workspace_database = init_workspace_database( let workspace_database = init_workspace_database(
&imported_session.user_workspace.workspace_database_id, imported_session_workspace_database_id,
workspace_database_collab, workspace_database_collab,
); );
for database_meta_list in workspace_database.get_all_database_meta() { for database_meta_list in workspace_database.get_all_database_meta() {
@ -661,7 +669,7 @@ where
write_collab_object( write_collab_object(
database_collab, database_collab,
session.user_id, session.user_id,
session.user_workspace.id.as_str(), &session.workspace_id,
&new_database_object_id, &new_database_object_id,
collab_write_txn, collab_write_txn,
CollabType::Database, CollabType::Database,
@ -684,7 +692,7 @@ where
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for gen_collab in gen_database_row_document_collabs { for gen_collab in gen_database_row_document_collabs {
write_gen_collab(&session.user_workspace.id, gen_collab, collab_write_txn); write_gen_collab(&session.workspace_id, gen_collab, collab_write_txn);
} }
// remove the database object ids from the object ids // remove the database object ids from the object ids
@ -771,7 +779,7 @@ where
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for gen_collab in gen_database_row_collabs { for gen_collab in gen_database_row_collabs {
write_gen_collab(&session.user_workspace.id, gen_collab, collab_write_txn); write_gen_collab(&session.workspace_id, gen_collab, collab_write_txn);
} }
} }
@ -936,7 +944,7 @@ where
{ {
let mut imported_folder_collab = Collab::new( let mut imported_folder_collab = Collab::new(
imported_session.user_id, imported_session.user_id,
&imported_session.user_workspace.id, &imported_session.workspace_id,
"migrate_device", "migrate_device",
vec![], vec![],
false, false,
@ -945,15 +953,15 @@ where
imported_collab_db_read_txn imported_collab_db_read_txn
.load_doc_with_txn( .load_doc_with_txn(
imported_session.user_id, imported_session.user_id,
&imported_session.user_workspace.id, &imported_session.workspace_id,
&imported_session.user_workspace.id, &imported_session.workspace_id,
&mut imported_folder_collab.transact_mut(), &mut imported_folder_collab.transact_mut(),
) )
.map_err(|err| { .map_err(|err| {
PersistenceError::Internal(anyhow!( PersistenceError::Internal(anyhow!(
"[AppflowyData]: Can't load the user:{} folder:{}. {}", "[AppflowyData]: Can't load the user:{} folder:{}. {}",
imported_session.user_id, imported_session.user_id,
imported_session.user_workspace.id, imported_session.workspace_id,
err err
)) ))
})?; })?;
@ -964,7 +972,7 @@ where
})?; })?;
let mut imported_folder_data = imported_folder let mut imported_folder_data = imported_folder
.get_folder_data(&imported_session.user_workspace.id) .get_folder_data(&imported_session.workspace_id)
.ok_or(PersistenceError::Internal(anyhow!( .ok_or(PersistenceError::Internal(anyhow!(
"[AppflowyData]: Can't read the folder data" "[AppflowyData]: Can't read the folder data"
)))?; )))?;
@ -1005,7 +1013,7 @@ where
// replace the old parent view id of the workspace // replace the old parent view id of the workspace
old_to_new_id_map.0.insert( old_to_new_id_map.0.insert(
imported_session.user_workspace.id.clone(), imported_session.workspace_id.clone(),
root_view_id.to_string(), root_view_id.to_string(),
); );

View file

@ -128,11 +128,13 @@ impl UserManager {
if let Ok(session) = self.get_session() { if let Ok(session) = self.get_session() {
info!( info!(
"Init user session: {}:{}, workspace: {}", "Init user session: {}, workspace: {}",
session.user_id, session.user_workspace.name, session.user_workspace.id session.user_id, session.workspace_id
); );
let workspace_uuid = Uuid::parse_str(&session.workspace_id)?;
let mut conn = self.db_connection(session.user_id)?;
let auth_type = select_user_workspace_type(&session.workspace_id, &mut conn)?;
let auth_type = session.user_workspace.workspace_type;
let uid = session.user_id; let uid = session.user_id;
let token = self.token_from_auth_type(&auth_type)?; let token = self.token_from_auth_type(&auth_type)?;
self self
@ -158,11 +160,11 @@ impl UserManager {
let weak_cloud_services = Arc::downgrade(&self.cloud_service); let weak_cloud_services = Arc::downgrade(&self.cloud_service);
let weak_authenticate_user = Arc::downgrade(&self.authenticate_user); let weak_authenticate_user = Arc::downgrade(&self.authenticate_user);
let weak_pool = Arc::downgrade(&self.db_pool(uid)?); let weak_pool = Arc::downgrade(&self.db_pool(uid)?);
let workspace_id = session.workspace_id.clone();
let cloned_session = session.clone(); let cloned_session = session.clone();
if let Some(mut token_state_rx) = self.cloud_service.subscribe_token_state() { if let Some(mut token_state_rx) = self.cloud_service.subscribe_token_state() {
event!(tracing::Level::DEBUG, "Listen token state change"); event!(tracing::Level::DEBUG, "Listen token state change");
let user_uid = uid; let user_uid = uid;
let workspace_id = session.user_workspace.id.clone();
tokio::spawn(async move { tokio::spawn(async move {
while let Some(token_state) = token_state_rx.next().await { while let Some(token_state) = token_state_rx.next().await {
debug!("Token state changed: {:?}", token_state); debug!("Token state changed: {:?}", token_state);
@ -260,7 +262,7 @@ impl UserManager {
.on_launch_if_authenticated( .on_launch_if_authenticated(
uid, uid,
&cloud_config, &cloud_config,
&session.user_workspace, &workspace_uuid,
&self.authenticate_user.user_config.device_id, &self.authenticate_user.user_config.device_id,
&auth_type, &auth_type,
) )
@ -340,6 +342,7 @@ impl UserManager {
self.prepare_user(&session).await; self.prepare_user(&session).await;
let latest_workspace = response.latest_workspace.clone(); let latest_workspace = response.latest_workspace.clone();
let workspace_id = Uuid::parse_str(&latest_workspace.id)?;
let user_profile = UserProfile::from((&response, &auth_type)); let user_profile = UserProfile::from((&response, &auth_type));
self.save_auth_data(&response, auth_type, &session).await?; self.save_auth_data(&response, auth_type, &session).await?;
@ -352,7 +355,7 @@ impl UserManager {
.await .await
.on_sign_in( .on_sign_in(
user_profile.uid, user_profile.uid,
&latest_workspace, &workspace_id,
&self.authenticate_user.user_config.device_id, &self.authenticate_user.user_config.device_id,
&auth_type, &auth_type,
) )
@ -404,6 +407,7 @@ impl UserManager {
.save_auth_data(&response, *auth_type, &new_session) .save_auth_data(&response, *auth_type, &new_session)
.await?; .await?;
let _ = self.initial_user_awareness(&new_session, auth_type).await; let _ = self.initial_user_awareness(&new_session, auth_type).await;
let workspace_id = Uuid::parse_str(&new_session.workspace_id)?;
self self
.user_status_callback .user_status_callback
.read() .read()
@ -411,7 +415,7 @@ impl UserManager {
.on_sign_up( .on_sign_up(
response.is_new_user, response.is_new_user,
new_user_profile, new_user_profile,
&new_session.user_workspace, &workspace_id,
&self.authenticate_user.user_config.device_id, &self.authenticate_user.user_config.device_id,
auth_type, auth_type,
) )
@ -493,7 +497,7 @@ impl UserManager {
let session = self.get_session()?; let session = self.get_session()?;
upsert_user_profile_change( upsert_user_profile_change(
session.user_id, session.user_id,
&session.user_workspace.id, &session.workspace_id,
self.db_connection(session.user_id)?, self.db_connection(session.user_id)?,
changeset, changeset,
)?; )?;
@ -523,7 +527,7 @@ impl UserManager {
self self
.authenticate_user .authenticate_user
.database .database
.backup(session.user_id, &session.user_workspace.id); .backup(session.user_id, &session.workspace_id);
} }
/// Fetches the user profile for the given user ID. /// Fetches the user profile for the given user ID.
@ -627,7 +631,7 @@ impl UserManager {
pub fn workspace_id(&self) -> Result<String, FlowyError> { pub fn workspace_id(&self) -> Result<String, FlowyError> {
let session = self.get_session()?; let session = self.get_session()?;
Ok(session.user_workspace.id.clone()) Ok(session.workspace_id.clone())
} }
pub fn token(&self) -> Result<Option<String>, FlowyError> { pub fn token(&self) -> Result<Option<String>, FlowyError> {
@ -758,7 +762,7 @@ impl UserManager {
// Save the user profile change // Save the user profile change
upsert_user_profile_change( upsert_user_profile_change(
user_update.uid, user_update.uid,
&session.user_workspace.id, &session.workspace_id,
self.db_connection(user_update.uid)?, self.db_connection(user_update.uid)?,
UserTableChangeset::from(user_update), UserTableChangeset::from(user_update),
)?; )?;
@ -784,17 +788,6 @@ impl UserManager {
.await?; .await?;
} }
// Save the old user workspace setting.
let mut conn = self
.authenticate_user
.database
.get_connection(old_user.session.user_id)?;
upsert_user_workspace(
old_user.session.user_id,
*auth_type,
old_user.session.user_workspace.clone(),
&mut conn,
)?;
Ok(()) Ok(())
} }
} }

View file

@ -20,7 +20,7 @@ impl UserManager {
let session = self.get_session().ok()?; let session = self.get_session().ok()?;
let user_profile = self let user_profile = self
.get_user_profile_from_disk(session.user_id, &session.user_workspace.id) .get_user_profile_from_disk(session.user_id, &session.workspace_id)
.await .await
.ok()?; .ok()?;
@ -48,7 +48,7 @@ impl UserManager {
"Anon user not found", "Anon user not found",
))?; ))?;
let profile = self let profile = self
.get_user_profile_from_disk(anon_session.user_id, &anon_session.user_workspace.id) .get_user_profile_from_disk(anon_session.user_id, &anon_session.workspace_id)
.await?; .await?;
Ok(UserProfilePB::from(profile)) Ok(UserProfilePB::from(profile))
} }

View file

@ -121,7 +121,7 @@ impl UserManager {
session: &Session, session: &Session,
auth_type: &AuthType, auth_type: &AuthType,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
let object_id = user_awareness_object_id(&session.user_uuid, &session.user_workspace.id); let object_id = user_awareness_object_id(&session.user_uuid, &session.workspace_id);
// Try to acquire mutable access to `is_loading_awareness`. // Try to acquire mutable access to `is_loading_awareness`.
// Thread-safety is ensured by DashMap // Thread-safety is ensured by DashMap
@ -162,7 +162,7 @@ impl UserManager {
auth_type auth_type
); );
let collab_db = self.get_collab_db(session.user_id)?; let collab_db = self.get_collab_db(session.user_id)?;
let workspace_id = session.user_workspace.workspace_id()?; let workspace_id = Uuid::parse_str(&session.workspace_id)?;
let doc_state = let doc_state =
CollabPersistenceImpl::new(collab_db.clone(), session.user_id, workspace_id) CollabPersistenceImpl::new(collab_db.clone(), session.user_id, workspace_id)
.into_data_source(); .into_data_source();
@ -227,7 +227,7 @@ impl UserManager {
} }
}; };
let workspace_id = session.user_workspace.workspace_id()?; let workspace_id = Uuid::parse_str(&session.workspace_id)?;
let create_awareness = if authenticator.is_local() { let create_awareness = if authenticator.is_local() {
let doc_state = let doc_state =
CollabPersistenceImpl::new(collab_db.clone(), session.user_id, workspace_id) CollabPersistenceImpl::new(collab_db.clone(), session.user_id, workspace_id)
@ -289,7 +289,7 @@ impl UserManager {
Ok(new_user_awareness) => { Ok(new_user_awareness) => {
// Validate session before storing the awareness // Validate session before storing the awareness
if let Ok(current_session) = authenticate_user.get_session() { if let Ok(current_session) = authenticate_user.get_session() {
if current_session.user_workspace.id == session.user_workspace.id { if current_session.workspace_id == session.workspace_id {
if let Some(user_awareness) = user_awareness.upgrade() { if let Some(user_awareness) = user_awareness.upgrade() {
info!("User awareness initialized successfully"); info!("User awareness initialized successfully");
user_awareness.store(Some(new_user_awareness)); user_awareness.store(Some(new_user_awareness));
@ -366,7 +366,7 @@ impl UserManager {
info!("User awareness is not loaded when trying to access it"); info!("User awareness is not loaded when trying to access it");
let session = self.get_session()?; let session = self.get_session()?;
let object_id = user_awareness_object_id(&session.user_uuid, &session.user_workspace.id); let object_id = user_awareness_object_id(&session.user_uuid, &session.workspace_id);
let is_loading = self let is_loading = self
.is_loading_awareness .is_loading_awareness
.get(&object_id) .get(&object_id)
@ -375,7 +375,7 @@ impl UserManager {
if !is_loading { if !is_loading {
let user_profile = self let user_profile = self
.get_user_profile_from_disk(session.user_id, &session.user_workspace.id) .get_user_profile_from_disk(session.user_id, &session.workspace_id)
.await?; .await?;
self self
.initial_user_awareness(&session, &user_profile.workspace_auth_type) .initial_user_awareness(&session, &user_profile.workspace_auth_type)

View file

@ -101,7 +101,7 @@ impl UserManager {
collab_data: ImportedCollabData, collab_data: ImportedCollabData,
) -> Result<(), FlowyError> { ) -> Result<(), FlowyError> {
let user = self let user = self
.get_user_profile_from_disk(current_session.user_id, &current_session.user_workspace.id) .get_user_profile_from_disk(current_session.user_id, &current_session.workspace_id)
.await?; .await?;
let user_collab_db = self let user_collab_db = self
.get_collab_db(current_session.user_id)? .get_collab_db(current_session.user_id)?
@ -109,12 +109,13 @@ impl UserManager {
.ok_or_else(|| FlowyError::internal().with_context("Collab db not found"))?; .ok_or_else(|| FlowyError::internal().with_context("Collab db not found"))?;
let user_id = current_session.user_id; let user_id = current_session.user_id;
let workspace_id = Uuid::parse_str(&current_session.workspace_id)?;
let weak_user_collab_db = Arc::downgrade(&user_collab_db); let weak_user_collab_db = Arc::downgrade(&user_collab_db);
let weak_user_cloud_service = self.cloud_service.get_user_service()?; let weak_user_cloud_service = self.cloud_service.get_user_service()?;
match upload_collab_objects_data( match upload_collab_objects_data(
user_id, user_id,
weak_user_collab_db, weak_user_collab_db,
&current_session.user_workspace.workspace_id()?, &workspace_id,
&user.workspace_auth_type, &user.workspace_auth_type,
collab_data, collab_data,
weak_user_cloud_service, weak_user_cloud_service,
@ -146,6 +147,7 @@ impl UserManager {
container_name: None, container_name: None,
parent_view_id: None, parent_view_id: None,
source: ImportedSource::AnonUser, source: ImportedSource::AnonUser,
workspace_database_id: "".to_string(),
}; };
self.perform_import(import_context).await?; self.perform_import(import_context).await?;
Ok(()) Ok(())