264 lines
9.2 KiB
Rust
Raw Normal View History

use crate::entities::workspace::*;
2022-05-05 10:45:53 +08:00
use crate::manager::FolderManager;
2021-07-20 14:03:21 +08:00
use crate::{
errors::*,
2022-01-30 10:33:21 +08:00
event_map::{FolderCouldServiceV1, WorkspaceUser},
notification::*,
2021-12-06 15:49:21 +08:00
services::{
2022-01-17 11:55:36 +08:00
persistence::{FolderPersistence, FolderPersistenceTransaction, WorkspaceChangeset},
read_workspace_apps, TrashController,
2021-12-06 15:49:21 +08:00
},
2021-09-07 23:30:43 +08:00
};
use flowy_sqlite::kv::KV;
2023-01-30 11:11:19 +08:00
use folder_model::{AppRevision, WorkspaceRevision};
2021-12-06 15:49:21 +08:00
use std::sync::Arc;
2021-07-13 23:08:20 +08:00
2021-10-05 14:37:45 +08:00
pub struct WorkspaceController {
pub user: Arc<dyn WorkspaceUser>,
2022-01-17 11:55:36 +08:00
persistence: Arc<FolderPersistence>,
2021-12-06 15:49:21 +08:00
pub(crate) trash_controller: Arc<TrashController>,
2022-01-17 11:55:36 +08:00
cloud_service: Arc<dyn FolderCouldServiceV1>,
2021-07-13 23:08:20 +08:00
}
impl WorkspaceController {
2021-09-01 22:50:22 +08:00
pub(crate) fn new(
2021-07-20 14:03:21 +08:00
user: Arc<dyn WorkspaceUser>,
2022-01-17 11:55:36 +08:00
persistence: Arc<FolderPersistence>,
2021-12-06 15:49:21 +08:00
trash_can: Arc<TrashController>,
2022-01-17 11:55:36 +08:00
cloud_service: Arc<dyn FolderCouldServiceV1>,
2021-07-20 14:03:21 +08:00
) -> Self {
Self {
user,
2022-01-14 09:09:25 +08:00
persistence,
2021-12-06 15:49:21 +08:00
trash_controller: trash_can,
2022-01-10 23:45:59 +08:00
cloud_service,
2021-07-20 14:03:21 +08:00
}
}
2021-07-13 23:08:20 +08:00
2021-11-08 19:19:02 +08:00
pub(crate) async fn create_workspace_from_params(
&self,
params: CreateWorkspaceParams,
) -> Result<WorkspaceRevision, FlowyError> {
2021-09-02 19:57:19 +08:00
let workspace = self.create_workspace_on_server(params.clone()).await?;
let user_id = self.user.user_id()?;
2021-09-08 18:25:32 +08:00
let token = self.user.token()?;
2022-01-20 23:51:11 +08:00
let workspaces = self
.persistence
.begin_transaction(|transaction| {
transaction.create_workspace(&user_id, workspace.clone())?;
2022-01-20 23:51:11 +08:00
transaction.read_workspaces(&user_id, None)
})
.await?
.into_iter()
.map(|workspace_rev| workspace_rev.into())
.collect();
2022-07-19 14:11:29 +08:00
let repeated_workspace = RepeatedWorkspacePB { items: workspaces };
send_notification(&token, FolderNotification::DidCreateWorkspace)
2022-01-14 09:09:25 +08:00
.payload(repeated_workspace)
.send();
feat: Customize the storage folder path (#1538) * feat: support customize folder path * feat: add l10n and optimize the logic * chore: code refactor * feat: add file read/write permission for macOS * fix: add toast for restoring path * feat: fetch apps and show them * feat: fetch apps and show them * feat: implement select document logic * feat: l10n and add select item callback * feat: add space between tile * chore: move file exporter to settings * chore: update UI * feat: support customizing folder when launching the app * feat: auto register after customizing folder * feat: l10n * feat: l10n * chore: reinitialize flowy sdk when calling init_sdk * chore: remove flowysdk const keyword to make sure it can be rebuild * chore: clear kv values when user logout * chore: replace current workspace id key in kv.db * feat: add config.name as a part of seesion_cache_key * feat: support open folder when launching * chore: fix some bugs * chore: dart fix & flutter analyze * chore: wrap 'sign up with ramdom user' as interface * feat: dismiss settings view after changing the folder * fix: read kv value after initializaing with new path * chore: remove user_id prefix from current workspace key * fix: move open latest view action to bloc * test: add test utils for integration tests * chore: move integration_test to its parent directory * test: add integration_test ci * test: switch to B from A, then switch to A again * chore: fix warings and format code and fix tests * chore: remove comment out codes * chore: rename some properties name and optimize the logic * chore: abstract logic of settings file exporter widget to cubit * chore: abstract location customizer view from file system view * chore: abstract settings page index to enum type * chore: remove the redundant underscore * test: fix integration test error * chore: enable integration test for windows and ubuntu * feat: abstract file picker as service and mock it under integration test * chore: fix bloc test Co-authored-by: nathan <nathan@appflowy.io>
2022-12-20 11:14:42 +08:00
set_current_workspace(&user_id, &workspace.id);
Ok(workspace)
2021-07-13 23:08:20 +08:00
}
2021-09-22 14:42:14 +08:00
#[allow(dead_code)]
2021-12-14 18:04:51 +08:00
pub(crate) async fn update_workspace(&self, params: UpdateWorkspaceParams) -> Result<(), FlowyError> {
2022-01-14 09:09:25 +08:00
let changeset = WorkspaceChangeset::new(params.clone());
2021-07-21 22:41:44 +08:00
let workspace_id = changeset.id.clone();
2022-01-20 23:51:11 +08:00
let workspace = self
.persistence
.begin_transaction(|transaction| {
transaction.update_workspace(changeset)?;
2022-01-20 23:51:11 +08:00
let user_id = self.user.user_id()?;
self.read_workspace(workspace_id.clone(), &user_id, &transaction)
2022-01-20 23:51:11 +08:00
})
.await?;
2021-09-07 17:12:03 +08:00
send_notification(&workspace_id, FolderNotification::DidUpdateWorkspace)
2022-01-14 09:09:25 +08:00
.payload(workspace)
.send();
self.update_workspace_on_server(params)?;
2021-07-20 14:03:21 +08:00
Ok(())
}
2021-09-22 14:42:14 +08:00
#[allow(dead_code)]
2021-12-14 18:04:51 +08:00
pub(crate) async fn delete_workspace(&self, workspace_id: &str) -> Result<(), FlowyError> {
let user_id = self.user.user_id()?;
2021-09-08 18:25:32 +08:00
let token = self.user.token()?;
2022-01-20 23:51:11 +08:00
let repeated_workspace = self
.persistence
.begin_transaction(|transaction| {
transaction.delete_workspace(workspace_id)?;
self.read_workspaces(None, &user_id, &transaction)
2022-01-20 23:51:11 +08:00
})
.await?;
send_notification(&token, FolderNotification::DidDeleteWorkspace)
2022-01-14 09:09:25 +08:00
.payload(repeated_workspace)
.send();
self.delete_workspace_on_server(workspace_id)?;
Ok(())
2021-07-20 14:03:21 +08:00
}
2022-07-19 14:11:29 +08:00
pub(crate) async fn open_workspace(&self, params: WorkspaceIdPB) -> Result<WorkspacePB, FlowyError> {
2021-08-27 23:53:53 +08:00
let user_id = self.user.user_id()?;
2022-02-24 21:49:18 +08:00
if let Some(workspace_id) = params.value {
2022-01-14 09:09:25 +08:00
let workspace = self
.persistence
.begin_transaction(|transaction| self.read_workspace(workspace_id, &user_id, &transaction))
2022-01-20 23:51:11 +08:00
.await?;
feat: Customize the storage folder path (#1538) * feat: support customize folder path * feat: add l10n and optimize the logic * chore: code refactor * feat: add file read/write permission for macOS * fix: add toast for restoring path * feat: fetch apps and show them * feat: fetch apps and show them * feat: implement select document logic * feat: l10n and add select item callback * feat: add space between tile * chore: move file exporter to settings * chore: update UI * feat: support customizing folder when launching the app * feat: auto register after customizing folder * feat: l10n * feat: l10n * chore: reinitialize flowy sdk when calling init_sdk * chore: remove flowysdk const keyword to make sure it can be rebuild * chore: clear kv values when user logout * chore: replace current workspace id key in kv.db * feat: add config.name as a part of seesion_cache_key * feat: support open folder when launching * chore: fix some bugs * chore: dart fix & flutter analyze * chore: wrap 'sign up with ramdom user' as interface * feat: dismiss settings view after changing the folder * fix: read kv value after initializaing with new path * chore: remove user_id prefix from current workspace key * fix: move open latest view action to bloc * test: add test utils for integration tests * chore: move integration_test to its parent directory * test: add integration_test ci * test: switch to B from A, then switch to A again * chore: fix warings and format code and fix tests * chore: remove comment out codes * chore: rename some properties name and optimize the logic * chore: abstract logic of settings file exporter widget to cubit * chore: abstract location customizer view from file system view * chore: abstract settings page index to enum type * chore: remove the redundant underscore * test: fix integration test error * chore: enable integration test for windows and ubuntu * feat: abstract file picker as service and mock it under integration test * chore: fix bloc test Co-authored-by: nathan <nathan@appflowy.io>
2022-12-20 11:14:42 +08:00
set_current_workspace(&user_id, &workspace.id);
2021-09-07 17:12:03 +08:00
Ok(workspace)
2021-09-04 09:00:15 +08:00
} else {
2022-01-24 17:35:58 +08:00
Err(FlowyError::workspace_id().context("Opened workspace id should not be empty"))
2021-08-27 23:53:53 +08:00
}
}
pub(crate) async fn read_current_workspace_apps(&self) -> Result<Vec<AppRevision>, FlowyError> {
feat: Customize the storage folder path (#1538) * feat: support customize folder path * feat: add l10n and optimize the logic * chore: code refactor * feat: add file read/write permission for macOS * fix: add toast for restoring path * feat: fetch apps and show them * feat: fetch apps and show them * feat: implement select document logic * feat: l10n and add select item callback * feat: add space between tile * chore: move file exporter to settings * chore: update UI * feat: support customizing folder when launching the app * feat: auto register after customizing folder * feat: l10n * feat: l10n * chore: reinitialize flowy sdk when calling init_sdk * chore: remove flowysdk const keyword to make sure it can be rebuild * chore: clear kv values when user logout * chore: replace current workspace id key in kv.db * feat: add config.name as a part of seesion_cache_key * feat: support open folder when launching * chore: fix some bugs * chore: dart fix & flutter analyze * chore: wrap 'sign up with ramdom user' as interface * feat: dismiss settings view after changing the folder * fix: read kv value after initializaing with new path * chore: remove user_id prefix from current workspace key * fix: move open latest view action to bloc * test: add test utils for integration tests * chore: move integration_test to its parent directory * test: add integration_test ci * test: switch to B from A, then switch to A again * chore: fix warings and format code and fix tests * chore: remove comment out codes * chore: rename some properties name and optimize the logic * chore: abstract logic of settings file exporter widget to cubit * chore: abstract location customizer view from file system view * chore: abstract settings page index to enum type * chore: remove the redundant underscore * test: fix integration test error * chore: enable integration test for windows and ubuntu * feat: abstract file picker as service and mock it under integration test * chore: fix bloc test Co-authored-by: nathan <nathan@appflowy.io>
2022-12-20 11:14:42 +08:00
let user_id = self.user.user_id()?;
let workspace_id = get_current_workspace(&user_id)?;
let app_revs = self
2022-01-20 23:51:11 +08:00
.persistence
.begin_transaction(|transaction| {
read_workspace_apps(&workspace_id, self.trash_controller.clone(), &transaction)
2022-01-20 23:51:11 +08:00
})
.await?;
2021-09-07 17:12:03 +08:00
// TODO: read from server
Ok(app_revs)
2021-09-07 17:12:03 +08:00
}
2022-01-14 09:09:25 +08:00
#[tracing::instrument(level = "debug", skip(self, transaction), err)]
pub(crate) fn read_workspaces<'a>(
&self,
workspace_id: Option<String>,
user_id: &str,
2022-01-17 11:55:36 +08:00
transaction: &'a (dyn FolderPersistenceTransaction + 'a),
2022-07-19 14:11:29 +08:00
) -> Result<RepeatedWorkspacePB, FlowyError> {
2021-09-07 17:12:03 +08:00
let workspace_id = workspace_id.to_owned();
let trash_ids = self.trash_controller.read_trash_ids(transaction)?;
let workspaces = transaction
.read_workspaces(user_id, workspace_id)?
.into_iter()
.map(|mut workspace_rev| {
workspace_rev.apps.retain(|app_rev| !trash_ids.contains(&app_rev.id));
workspace_rev.into()
})
.collect();
2022-07-19 14:11:29 +08:00
Ok(RepeatedWorkspacePB { items: workspaces })
2021-07-20 14:03:21 +08:00
}
pub(crate) fn read_workspace<'a>(
&self,
workspace_id: String,
user_id: &str,
2022-01-17 11:55:36 +08:00
transaction: &'a (dyn FolderPersistenceTransaction + 'a),
2022-07-19 14:11:29 +08:00
) -> Result<WorkspacePB, FlowyError> {
let mut workspaces = self
.read_workspaces(Some(workspace_id.clone()), user_id, transaction)?
.items;
if workspaces.is_empty() {
2021-12-14 18:04:51 +08:00
return Err(FlowyError::record_not_found().context(format!("{} workspace not found", workspace_id)));
2021-08-28 23:08:12 +08:00
}
debug_assert_eq!(workspaces.len(), 1);
let workspace = workspaces.drain(..1).collect::<Vec<WorkspacePB>>().pop().unwrap();
2021-08-28 23:08:12 +08:00
Ok(workspace)
}
2021-07-13 23:08:20 +08:00
}
2021-08-24 21:38:53 +08:00
impl WorkspaceController {
2022-01-23 22:33:47 +08:00
#[tracing::instrument(level = "trace", skip(self), err)]
async fn create_workspace_on_server(&self, params: CreateWorkspaceParams) -> Result<WorkspaceRevision, FlowyError> {
let token = self.user.token()?;
self.cloud_service.create_workspace(&token, params).await
2021-08-28 23:08:12 +08:00
}
2022-01-23 22:33:47 +08:00
#[tracing::instrument(level = "trace", skip(self), err)]
2021-12-14 18:04:51 +08:00
fn update_workspace_on_server(&self, params: UpdateWorkspaceParams) -> Result<(), FlowyError> {
2022-01-10 23:45:59 +08:00
let (token, server) = (self.user.token()?, self.cloud_service.clone());
2021-11-09 15:32:57 +08:00
tokio::spawn(async move {
match server.update_workspace(&token, params).await {
2022-01-24 17:35:58 +08:00
Ok(_) => {}
Err(e) => {
// TODO: retry?
log::error!("Update workspace failed: {:?}", e);
2022-01-24 17:35:58 +08:00
}
}
});
Ok(())
}
2021-08-24 21:38:53 +08:00
2022-01-23 22:33:47 +08:00
#[tracing::instrument(level = "trace", skip(self), err)]
2021-12-14 18:04:51 +08:00
fn delete_workspace_on_server(&self, workspace_id: &str) -> Result<(), FlowyError> {
2022-07-19 14:11:29 +08:00
let params = WorkspaceIdPB {
2022-02-24 21:49:18 +08:00
value: Some(workspace_id.to_string()),
2021-09-02 19:57:19 +08:00
};
2022-01-10 23:45:59 +08:00
let (token, server) = (self.user.token()?, self.cloud_service.clone());
2021-11-09 15:32:57 +08:00
tokio::spawn(async move {
match server.delete_workspace(&token, params).await {
2022-01-24 17:35:58 +08:00
Ok(_) => {}
Err(e) => {
// TODO: retry?
log::error!("Delete workspace failed: {:?}", e);
2022-01-24 17:35:58 +08:00
}
}
});
Ok(())
}
2021-08-25 17:34:20 +08:00
}
2022-05-05 10:45:53 +08:00
pub async fn notify_workspace_setting_did_change(
folder_manager: &Arc<FolderManager>,
view_id: &str,
) -> FlowyResult<()> {
let user_id = folder_manager.user.user_id()?;
let token = folder_manager.user.token()?;
feat: Customize the storage folder path (#1538) * feat: support customize folder path * feat: add l10n and optimize the logic * chore: code refactor * feat: add file read/write permission for macOS * fix: add toast for restoring path * feat: fetch apps and show them * feat: fetch apps and show them * feat: implement select document logic * feat: l10n and add select item callback * feat: add space between tile * chore: move file exporter to settings * chore: update UI * feat: support customizing folder when launching the app * feat: auto register after customizing folder * feat: l10n * feat: l10n * chore: reinitialize flowy sdk when calling init_sdk * chore: remove flowysdk const keyword to make sure it can be rebuild * chore: clear kv values when user logout * chore: replace current workspace id key in kv.db * feat: add config.name as a part of seesion_cache_key * feat: support open folder when launching * chore: fix some bugs * chore: dart fix & flutter analyze * chore: wrap 'sign up with ramdom user' as interface * feat: dismiss settings view after changing the folder * fix: read kv value after initializaing with new path * chore: remove user_id prefix from current workspace key * fix: move open latest view action to bloc * test: add test utils for integration tests * chore: move integration_test to its parent directory * test: add integration_test ci * test: switch to B from A, then switch to A again * chore: fix warings and format code and fix tests * chore: remove comment out codes * chore: rename some properties name and optimize the logic * chore: abstract logic of settings file exporter widget to cubit * chore: abstract location customizer view from file system view * chore: abstract settings page index to enum type * chore: remove the redundant underscore * test: fix integration test error * chore: enable integration test for windows and ubuntu * feat: abstract file picker as service and mock it under integration test * chore: fix bloc test Co-authored-by: nathan <nathan@appflowy.io>
2022-12-20 11:14:42 +08:00
let workspace_id = get_current_workspace(&user_id)?;
2022-05-05 10:45:53 +08:00
let workspace_setting = folder_manager
.persistence
.begin_transaction(|transaction| {
let workspace =
folder_manager
.workspace_controller
.read_workspace(workspace_id.clone(), &user_id, &transaction)?;
2022-05-05 10:45:53 +08:00
let setting = match transaction.read_view(view_id) {
2022-10-26 10:38:57 +08:00
Ok(latest_view) => WorkspaceSettingPB {
2022-05-05 10:45:53 +08:00
workspace,
latest_view: Some(latest_view.into()),
2022-05-05 10:45:53 +08:00
},
2022-10-26 10:38:57 +08:00
Err(_) => WorkspaceSettingPB {
2022-05-05 10:45:53 +08:00
workspace,
latest_view: None,
},
};
Ok(setting)
})
.await?;
send_notification(&token, FolderNotification::DidUpdateWorkspaceSetting)
2022-05-05 10:45:53 +08:00
.payload(workspace_setting)
.send();
Ok(())
}
const CURRENT_WORKSPACE_ID: &str = "current_workspace_id";
2021-08-25 17:34:20 +08:00
feat: Customize the storage folder path (#1538) * feat: support customize folder path * feat: add l10n and optimize the logic * chore: code refactor * feat: add file read/write permission for macOS * fix: add toast for restoring path * feat: fetch apps and show them * feat: fetch apps and show them * feat: implement select document logic * feat: l10n and add select item callback * feat: add space between tile * chore: move file exporter to settings * chore: update UI * feat: support customizing folder when launching the app * feat: auto register after customizing folder * feat: l10n * feat: l10n * chore: reinitialize flowy sdk when calling init_sdk * chore: remove flowysdk const keyword to make sure it can be rebuild * chore: clear kv values when user logout * chore: replace current workspace id key in kv.db * feat: add config.name as a part of seesion_cache_key * feat: support open folder when launching * chore: fix some bugs * chore: dart fix & flutter analyze * chore: wrap 'sign up with ramdom user' as interface * feat: dismiss settings view after changing the folder * fix: read kv value after initializaing with new path * chore: remove user_id prefix from current workspace key * fix: move open latest view action to bloc * test: add test utils for integration tests * chore: move integration_test to its parent directory * test: add integration_test ci * test: switch to B from A, then switch to A again * chore: fix warings and format code and fix tests * chore: remove comment out codes * chore: rename some properties name and optimize the logic * chore: abstract logic of settings file exporter widget to cubit * chore: abstract location customizer view from file system view * chore: abstract settings page index to enum type * chore: remove the redundant underscore * test: fix integration test error * chore: enable integration test for windows and ubuntu * feat: abstract file picker as service and mock it under integration test * chore: fix bloc test Co-authored-by: nathan <nathan@appflowy.io>
2022-12-20 11:14:42 +08:00
pub fn set_current_workspace(_user_id: &str, workspace_id: &str) {
2022-01-24 17:35:58 +08:00
KV::set_str(CURRENT_WORKSPACE_ID, workspace_id.to_owned());
}
2021-08-26 17:58:59 +08:00
feat: Customize the storage folder path (#1538) * feat: support customize folder path * feat: add l10n and optimize the logic * chore: code refactor * feat: add file read/write permission for macOS * fix: add toast for restoring path * feat: fetch apps and show them * feat: fetch apps and show them * feat: implement select document logic * feat: l10n and add select item callback * feat: add space between tile * chore: move file exporter to settings * chore: update UI * feat: support customizing folder when launching the app * feat: auto register after customizing folder * feat: l10n * feat: l10n * chore: reinitialize flowy sdk when calling init_sdk * chore: remove flowysdk const keyword to make sure it can be rebuild * chore: clear kv values when user logout * chore: replace current workspace id key in kv.db * feat: add config.name as a part of seesion_cache_key * feat: support open folder when launching * chore: fix some bugs * chore: dart fix & flutter analyze * chore: wrap 'sign up with ramdom user' as interface * feat: dismiss settings view after changing the folder * fix: read kv value after initializaing with new path * chore: remove user_id prefix from current workspace key * fix: move open latest view action to bloc * test: add test utils for integration tests * chore: move integration_test to its parent directory * test: add integration_test ci * test: switch to B from A, then switch to A again * chore: fix warings and format code and fix tests * chore: remove comment out codes * chore: rename some properties name and optimize the logic * chore: abstract logic of settings file exporter widget to cubit * chore: abstract location customizer view from file system view * chore: abstract settings page index to enum type * chore: remove the redundant underscore * test: fix integration test error * chore: enable integration test for windows and ubuntu * feat: abstract file picker as service and mock it under integration test * chore: fix bloc test Co-authored-by: nathan <nathan@appflowy.io>
2022-12-20 11:14:42 +08:00
pub fn clear_current_workspace(_user_id: &str) {
let _ = KV::remove(CURRENT_WORKSPACE_ID);
}
pub fn get_current_workspace(_user_id: &str) -> Result<String, FlowyError> {
2021-09-03 12:44:48 +08:00
match KV::get_str(CURRENT_WORKSPACE_ID) {
2021-12-14 18:04:51 +08:00
None => {
Err(FlowyError::record_not_found()
.context("Current workspace not found or should call open workspace first"))
2022-01-24 17:35:58 +08:00
}
Some(workspace_id) => Ok(workspace_id),
}
2021-08-26 17:58:59 +08:00
}