fix: auto patch workspace folder without space (#1107)
This commit is contained in:
parent
424796ef36
commit
a61a5c58cc
|
|
@ -2145,7 +2145,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c45a2120361f94bbedb787cdd2192a38c94c7f5f#c45a2120361f94bbedb787cdd2192a38c94c7f5f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d51fecb64762855f9e54648c78ab1ee0d5404f97#d51fecb64762855f9e54648c78ab1ee0d5404f97"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
|
|
@ -2170,7 +2170,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c45a2120361f94bbedb787cdd2192a38c94c7f5f#c45a2120361f94bbedb787cdd2192a38c94c7f5f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d51fecb64762855f9e54648c78ab1ee0d5404f97#d51fecb64762855f9e54648c78ab1ee0d5404f97"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -2210,7 +2210,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c45a2120361f94bbedb787cdd2192a38c94c7f5f#c45a2120361f94bbedb787cdd2192a38c94c7f5f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d51fecb64762855f9e54648c78ab1ee0d5404f97#d51fecb64762855f9e54648c78ab1ee0d5404f97"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
|
|
@ -2231,7 +2231,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c45a2120361f94bbedb787cdd2192a38c94c7f5f#c45a2120361f94bbedb787cdd2192a38c94c7f5f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d51fecb64762855f9e54648c78ab1ee0d5404f97#d51fecb64762855f9e54648c78ab1ee0d5404f97"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
|
|
@ -2251,7 +2251,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c45a2120361f94bbedb787cdd2192a38c94c7f5f#c45a2120361f94bbedb787cdd2192a38c94c7f5f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d51fecb64762855f9e54648c78ab1ee0d5404f97#d51fecb64762855f9e54648c78ab1ee0d5404f97"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
|
|
@ -2273,7 +2273,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-importer"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c45a2120361f94bbedb787cdd2192a38c94c7f5f#c45a2120361f94bbedb787cdd2192a38c94c7f5f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d51fecb64762855f9e54648c78ab1ee0d5404f97#d51fecb64762855f9e54648c78ab1ee0d5404f97"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
|
|
@ -2382,7 +2382,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c45a2120361f94bbedb787cdd2192a38c94c7f5f#c45a2120361f94bbedb787cdd2192a38c94c7f5f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d51fecb64762855f9e54648c78ab1ee0d5404f97#d51fecb64762855f9e54648c78ab1ee0d5404f97"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
|
|
|
|||
14
Cargo.toml
14
Cargo.toml
|
|
@ -320,13 +320,13 @@ lto = false
|
|||
[patch.crates-io]
|
||||
# It's diffcult to resovle different version with the same crate used in AppFlowy Frontend and the Client-API crate.
|
||||
# So using patch to workaround this issue.
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c45a2120361f94bbedb787cdd2192a38c94c7f5f" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c45a2120361f94bbedb787cdd2192a38c94c7f5f" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c45a2120361f94bbedb787cdd2192a38c94c7f5f" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c45a2120361f94bbedb787cdd2192a38c94c7f5f" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c45a2120361f94bbedb787cdd2192a38c94c7f5f" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c45a2120361f94bbedb787cdd2192a38c94c7f5f" }
|
||||
collab-importer = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c45a2120361f94bbedb787cdd2192a38c94c7f5f" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d51fecb64762855f9e54648c78ab1ee0d5404f97" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d51fecb64762855f9e54648c78ab1ee0d5404f97" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d51fecb64762855f9e54648c78ab1ee0d5404f97" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d51fecb64762855f9e54648c78ab1ee0d5404f97" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d51fecb64762855f9e54648c78ab1ee0d5404f97" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d51fecb64762855f9e54648c78ab1ee0d5404f97" }
|
||||
collab-importer = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d51fecb64762855f9e54648c78ab1ee0d5404f97" }
|
||||
|
||||
[features]
|
||||
history = []
|
||||
|
|
|
|||
|
|
@ -2024,10 +2024,13 @@ async fn get_workspace_folder_handler(
|
|||
user_uuid: UserUuid,
|
||||
workspace_id: web::Path<Uuid>,
|
||||
state: Data<AppState>,
|
||||
server: Data<RealtimeServerAddr>,
|
||||
query: web::Query<QueryWorkspaceFolder>,
|
||||
req: HttpRequest,
|
||||
) -> Result<Json<AppResponse<FolderView>>> {
|
||||
let depth = query.depth.unwrap_or(1);
|
||||
let uid = state.user_cache.get_user_uid(&user_uuid).await?;
|
||||
let user = realtime_user_for_web_request(req.headers(), uid)?;
|
||||
let workspace_id = workspace_id.into_inner();
|
||||
state
|
||||
.workspace_access_control
|
||||
|
|
@ -2039,9 +2042,11 @@ async fn get_workspace_folder_handler(
|
|||
workspace_id.to_string()
|
||||
};
|
||||
let folder_view = biz::collab::ops::get_user_workspace_structure(
|
||||
&state.metrics.appflowy_web_metrics,
|
||||
server,
|
||||
&state.collab_access_control_storage,
|
||||
&state.pg_pool,
|
||||
uid,
|
||||
user,
|
||||
workspace_id,
|
||||
depth,
|
||||
&root_view_id,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ use std::collections::HashSet;
|
|||
|
||||
use app_error::AppError;
|
||||
use chrono::DateTime;
|
||||
use collab_folder::{
|
||||
hierarchy_builder::SpacePermission, Folder, SectionItem, ViewLayout as CollabFolderViewLayout,
|
||||
};
|
||||
use collab_folder::{Folder, SectionItem, SpacePermission, ViewLayout as CollabFolderViewLayout};
|
||||
use shared_entity::dto::workspace_dto::{
|
||||
self, FavoriteFolderView, FolderView, FolderViewMinimal, RecentFolderView, TrashFolderView,
|
||||
ViewLayout,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::web::Data;
|
||||
use app_error::AppError;
|
||||
use appflowy_collaborate::collab::storage::CollabAccessControlStorage;
|
||||
use chrono::DateTime;
|
||||
|
|
@ -24,8 +25,12 @@ use collab_database::workspace_database::WorkspaceDatabaseBody;
|
|||
use collab_document::document::Document;
|
||||
use collab_entity::CollabType;
|
||||
use collab_entity::EncodedCollab;
|
||||
use collab_folder::hierarchy_builder::NestedChildViewBuilder;
|
||||
use collab_folder::CollabOrigin;
|
||||
use collab_folder::Folder;
|
||||
use collab_folder::SectionItem;
|
||||
use collab_folder::SpaceInfo;
|
||||
use collab_rt_entity::user::RealtimeUser;
|
||||
use database::collab::select_last_updated_database_row_ids;
|
||||
use database::collab::select_workspace_database_oid;
|
||||
use database::collab::{CollabStorage, GetCollabOrigin};
|
||||
|
|
@ -48,8 +53,12 @@ use sqlx::PgPool;
|
|||
use std::ops::DerefMut;
|
||||
use yrs::Map;
|
||||
|
||||
use crate::api::metrics::AppFlowyWebMetrics;
|
||||
use crate::api::ws::RealtimeServerAddr;
|
||||
use crate::biz::collab::folder_view::check_if_view_is_space;
|
||||
use crate::biz::collab::utils::get_database_row_doc_changes;
|
||||
use crate::biz::workspace::ops::broadcast_update_with_timeout;
|
||||
use crate::biz::workspace::page_view::update_workspace_folder_data;
|
||||
use access_control::collab::CollabAccessControl;
|
||||
use anyhow::Context;
|
||||
use database_entity::dto::{
|
||||
|
|
@ -82,6 +91,8 @@ use super::utils::type_options_serde;
|
|||
use super::utils::write_to_database_row;
|
||||
use super::utils::CreatedRowDocument;
|
||||
use super::utils::DocChanges;
|
||||
use super::utils::DEFAULT_SPACE_ICON;
|
||||
use super::utils::DEFAULT_SPACE_ICON_COLOR;
|
||||
|
||||
/// Create a new collab member
|
||||
/// If the collab member already exists, return [AppError::RecordAlreadyExists]
|
||||
|
|
@ -293,10 +304,95 @@ pub async fn get_user_trash_folder_views(
|
|||
Ok(section_items_to_trash_folder_view(§ion_items, &folder))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn patch_old_workspace_folder(
|
||||
user: RealtimeUser,
|
||||
workspace_id: &str,
|
||||
folder: &mut Folder,
|
||||
child_view_id_without_space: &[String],
|
||||
) -> Result<Vec<u8>, AppError> {
|
||||
let encoded_update = {
|
||||
let space_id = Uuid::new_v4().to_string();
|
||||
|
||||
let space_view = NestedChildViewBuilder::new(user.uid, workspace_id.to_string())
|
||||
.with_view_id(space_id.clone())
|
||||
.with_name("General")
|
||||
.with_extra(|extra| {
|
||||
extra
|
||||
.with_space_info(SpaceInfo {
|
||||
space_icon: Some(DEFAULT_SPACE_ICON.to_string()),
|
||||
space_icon_color: Some(DEFAULT_SPACE_ICON_COLOR.to_string()),
|
||||
..Default::default()
|
||||
})
|
||||
.build()
|
||||
})
|
||||
.build()
|
||||
.view;
|
||||
let mut txn = folder.collab.transact_mut();
|
||||
folder.body.views.insert(&mut txn, space_view, None);
|
||||
for (i, current_view_id) in child_view_id_without_space.iter().enumerate() {
|
||||
let previous_view_id = if i == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(child_view_id_without_space[i - 1].clone())
|
||||
};
|
||||
folder
|
||||
.body
|
||||
.move_nested_view(&mut txn, current_view_id, &space_id, previous_view_id);
|
||||
}
|
||||
txn.encode_update_v1()
|
||||
};
|
||||
Ok(encoded_update)
|
||||
}
|
||||
|
||||
async fn fix_old_workspace_folder(
|
||||
appflowy_web_metrics: &AppFlowyWebMetrics,
|
||||
server: Data<RealtimeServerAddr>,
|
||||
user: RealtimeUser,
|
||||
mut folder: Folder,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<Folder, AppError> {
|
||||
let root_view = folder.get_view(&workspace_id.to_string()).ok_or_else(|| {
|
||||
AppError::InvalidRequest(format!(
|
||||
"Failed to get view for workspace_id: {}",
|
||||
workspace_id
|
||||
))
|
||||
})?;
|
||||
let direct_workspace_children: Vec<String> = root_view
|
||||
.children
|
||||
.iter()
|
||||
.map(|view_id| view_id.to_string())
|
||||
.collect();
|
||||
let has_at_least_one_space = direct_workspace_children
|
||||
.iter()
|
||||
.filter_map(|view_id| folder.get_view(view_id))
|
||||
.any(|view| check_if_view_is_space(&view));
|
||||
if !has_at_least_one_space {
|
||||
let folder_update = patch_old_workspace_folder(
|
||||
user.clone(),
|
||||
&workspace_id.to_string(),
|
||||
&mut folder,
|
||||
&direct_workspace_children,
|
||||
)?;
|
||||
update_workspace_folder_data(
|
||||
appflowy_web_metrics,
|
||||
server,
|
||||
user,
|
||||
workspace_id,
|
||||
folder_update,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Ok(folder)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn get_user_workspace_structure(
|
||||
appflowy_web_metrics: &AppFlowyWebMetrics,
|
||||
server: Data<RealtimeServerAddr>,
|
||||
collab_storage: &CollabAccessControlStorage,
|
||||
pg_pool: &PgPool,
|
||||
uid: i64,
|
||||
user: RealtimeUser,
|
||||
workspace_id: Uuid,
|
||||
depth: u32,
|
||||
root_view_id: &str,
|
||||
|
|
@ -310,10 +406,13 @@ pub async fn get_user_workspace_structure(
|
|||
}
|
||||
let folder = get_latest_collab_folder(
|
||||
collab_storage,
|
||||
GetCollabOrigin::User { uid },
|
||||
GetCollabOrigin::User { uid: user.uid },
|
||||
&workspace_id.to_string(),
|
||||
)
|
||||
.await?;
|
||||
let patched_folder =
|
||||
fix_old_workspace_folder(appflowy_web_metrics, server, user, folder, workspace_id).await?;
|
||||
|
||||
let publish_view_ids = select_published_view_ids_for_workspace(pg_pool, workspace_id).await?;
|
||||
let publish_view_ids: HashSet<String> = publish_view_ids
|
||||
.into_iter()
|
||||
|
|
@ -322,7 +421,7 @@ pub async fn get_user_workspace_structure(
|
|||
collab_folder_to_folder_view(
|
||||
workspace_id,
|
||||
root_view_id,
|
||||
&folder,
|
||||
&patched_folder,
|
||||
depth,
|
||||
&publish_view_ids,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ use std::collections::HashSet;
|
|||
use std::sync::Arc;
|
||||
use yrs::Map;
|
||||
|
||||
pub const DEFAULT_SPACE_ICON: &str = "interface_essential/home-3";
|
||||
pub const DEFAULT_SPACE_ICON_COLOR: &str = "0xFFA34AFD";
|
||||
|
||||
pub fn get_row_details_serde(
|
||||
row_detail: RowDetail,
|
||||
field_by_id_name_uniq: &HashMap<String, Field>,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ use collab_document::document::Document;
|
|||
use collab_document::document_data::default_document_data;
|
||||
use collab_entity::{CollabType, EncodedCollab};
|
||||
use collab_folder::hierarchy_builder::NestedChildViewBuilder;
|
||||
use collab_folder::{timestamp, CollabOrigin, Folder};
|
||||
use collab_folder::{timestamp, CollabOrigin, Folder, SpaceInfo};
|
||||
use collab_rt_entity::user::RealtimeUser;
|
||||
use database::collab::{select_workspace_database_oid, CollabStorage, GetCollabOrigin};
|
||||
use database::publish::select_published_view_ids_for_workspace;
|
||||
|
|
@ -419,12 +419,14 @@ async fn add_new_space_to_folder(
|
|||
.with_view_id(view_id)
|
||||
.with_name(name)
|
||||
.with_extra(|builder| {
|
||||
let mut extra = builder
|
||||
.is_space(true, to_space_permission(space_permission))
|
||||
.build();
|
||||
extra["space_icon_color"] = json!(space_icon_color);
|
||||
extra["space_icon"] = json!(space_icon);
|
||||
extra
|
||||
builder
|
||||
.with_space_info(SpaceInfo {
|
||||
space_icon: Some(space_icon.to_string()),
|
||||
space_icon_color: Some(space_icon_color.to_string()),
|
||||
space_permission: to_space_permission(space_permission),
|
||||
..Default::default()
|
||||
})
|
||||
.build()
|
||||
})
|
||||
.build()
|
||||
.view;
|
||||
|
|
|
|||
Loading…
Reference in New Issue