2024-12-20 00:15:01 +08:00
|
|
|
use flowy_folder::view_operation::{GatherEncodedCollab, ViewData};
|
2024-04-13 01:08:47 +08:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2024-04-12 10:21:41 +02:00
|
|
|
use collab_folder::{FolderData, View};
|
2023-12-31 07:29:40 +08:00
|
|
|
use flowy_folder::entities::icon::UpdateViewIconPayloadPB;
|
|
|
|
use flowy_folder::event_map::FolderEvent;
|
|
|
|
use flowy_folder::event_map::FolderEvent::*;
|
2024-04-12 10:21:41 +02:00
|
|
|
use flowy_folder::{entities::*, ViewLayout};
|
2024-07-22 13:35:42 +08:00
|
|
|
use flowy_folder_pub::entities::PublishPayload;
|
2024-04-12 10:21:41 +02:00
|
|
|
use flowy_search::services::manager::{SearchHandler, SearchType};
|
2023-10-25 21:35:47 +08:00
|
|
|
use flowy_user::entities::{
|
2024-06-24 14:19:36 +08:00
|
|
|
AcceptWorkspaceInvitationPB, QueryWorkspacePB, RemoveWorkspaceMemberPB,
|
2024-04-11 14:47:34 +08:00
|
|
|
RepeatedWorkspaceInvitationPB, RepeatedWorkspaceMemberPB, WorkspaceMemberInvitationPB,
|
2023-10-25 21:35:47 +08:00
|
|
|
WorkspaceMemberPB,
|
|
|
|
};
|
2023-10-24 20:11:06 +08:00
|
|
|
use flowy_user::errors::FlowyError;
|
2023-10-25 21:35:47 +08:00
|
|
|
use flowy_user::event_map::UserEvent;
|
2024-04-11 14:47:34 +08:00
|
|
|
use flowy_user_pub::entities::Role;
|
2023-10-24 20:11:06 +08:00
|
|
|
|
|
|
|
use crate::event_builder::EventBuilder;
|
|
|
|
use crate::EventIntegrationTest;
|
|
|
|
|
|
|
|
impl EventIntegrationTest {
|
2024-04-11 14:47:34 +08:00
|
|
|
pub async fn invite_workspace_member(&self, workspace_id: &str, email: &str, role: Role) {
|
2024-04-11 20:15:40 +08:00
|
|
|
EventBuilder::new(self.clone())
|
2024-04-11 14:47:34 +08:00
|
|
|
.event(UserEvent::InviteWorkspaceMember)
|
|
|
|
.payload(WorkspaceMemberInvitationPB {
|
|
|
|
workspace_id: workspace_id.to_string(),
|
|
|
|
invitee_email: email.to_string(),
|
|
|
|
role: role.into(),
|
|
|
|
})
|
|
|
|
.async_send()
|
2024-04-11 20:15:40 +08:00
|
|
|
.await;
|
2024-04-11 14:47:34 +08:00
|
|
|
}
|
|
|
|
|
2024-06-24 14:19:36 +08:00
|
|
|
// convenient function to add workspace member by inviting and accepting the invitation
|
|
|
|
pub async fn add_workspace_member(&self, workspace_id: &str, other: &EventIntegrationTest) {
|
|
|
|
let other_email = other.get_user_profile().await.unwrap().email;
|
|
|
|
|
|
|
|
self
|
|
|
|
.invite_workspace_member(workspace_id, &other_email, Role::Member)
|
|
|
|
.await;
|
|
|
|
|
|
|
|
let invitations = other.list_workspace_invitations().await;
|
|
|
|
let target_invi = invitations
|
|
|
|
.items
|
|
|
|
.into_iter()
|
|
|
|
.find(|i| i.workspace_id == workspace_id)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
other
|
|
|
|
.accept_workspace_invitation(&target_invi.invite_id)
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
|
2024-04-11 14:47:34 +08:00
|
|
|
pub async fn list_workspace_invitations(&self) -> RepeatedWorkspaceInvitationPB {
|
2023-10-25 21:35:47 +08:00
|
|
|
EventBuilder::new(self.clone())
|
2024-04-11 14:47:34 +08:00
|
|
|
.event(UserEvent::ListWorkspaceInvitations)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn accept_workspace_invitation(&self, invitation_id: &str) {
|
|
|
|
if let Some(err) = EventBuilder::new(self.clone())
|
|
|
|
.event(UserEvent::AcceptWorkspaceInvitation)
|
|
|
|
.payload(AcceptWorkspaceInvitationPB {
|
|
|
|
invite_id: invitation_id.to_string(),
|
|
|
|
})
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.error()
|
|
|
|
{
|
|
|
|
panic!("Accept workspace invitation failed: {:?}", err)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn delete_workspace_member(&self, workspace_id: &str, email: &str) {
|
|
|
|
if let Some(err) = EventBuilder::new(self.clone())
|
2023-10-25 21:35:47 +08:00
|
|
|
.event(UserEvent::RemoveWorkspaceMember)
|
|
|
|
.payload(RemoveWorkspaceMemberPB {
|
|
|
|
workspace_id: workspace_id.to_string(),
|
|
|
|
email: email.to_string(),
|
|
|
|
})
|
|
|
|
.async_send()
|
2024-04-11 14:47:34 +08:00
|
|
|
.await
|
|
|
|
.error()
|
|
|
|
{
|
|
|
|
panic!("Delete workspace member failed: {:?}", err)
|
|
|
|
};
|
2023-10-25 21:35:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn get_workspace_members(&self, workspace_id: &str) -> Vec<WorkspaceMemberPB> {
|
|
|
|
EventBuilder::new(self.clone())
|
2024-06-17 14:30:19 +02:00
|
|
|
.event(UserEvent::GetWorkspaceMembers)
|
2023-10-25 21:35:47 +08:00
|
|
|
.payload(QueryWorkspacePB {
|
|
|
|
workspace_id: workspace_id.to_string(),
|
|
|
|
})
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<RepeatedWorkspaceMemberPB>()
|
|
|
|
.items
|
|
|
|
}
|
|
|
|
|
2023-11-01 11:45:35 +08:00
|
|
|
pub async fn get_current_workspace(&self) -> WorkspacePB {
|
2023-10-24 20:11:06 +08:00
|
|
|
EventBuilder::new(self.clone())
|
2023-11-01 11:45:35 +08:00
|
|
|
.event(FolderEvent::ReadCurrentWorkspace)
|
2023-10-24 20:11:06 +08:00
|
|
|
.async_send()
|
|
|
|
.await
|
2023-11-01 11:45:35 +08:00
|
|
|
.parse::<WorkspacePB>()
|
2023-10-24 20:11:06 +08:00
|
|
|
}
|
|
|
|
|
2024-04-12 10:21:41 +02:00
|
|
|
pub fn get_folder_search_handler(&self) -> &Arc<dyn SearchHandler> {
|
|
|
|
self
|
|
|
|
.appflowy_core
|
|
|
|
.search_manager
|
|
|
|
.get_handler(SearchType::Folder)
|
|
|
|
.unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// create views in the folder.
|
|
|
|
pub async fn create_views(&self, views: Vec<View>) {
|
|
|
|
let create_view_params = views
|
|
|
|
.into_iter()
|
|
|
|
.map(|view| CreateViewParams {
|
|
|
|
parent_view_id: view.parent_view_id,
|
|
|
|
name: view.name,
|
|
|
|
layout: view.layout.into(),
|
|
|
|
view_id: view.id,
|
2024-10-29 11:21:49 +08:00
|
|
|
initial_data: ViewData::Empty,
|
2024-04-12 10:21:41 +02:00
|
|
|
meta: Default::default(),
|
|
|
|
set_as_current: false,
|
|
|
|
index: None,
|
|
|
|
section: None,
|
2024-06-25 10:03:02 +08:00
|
|
|
icon: view.icon,
|
|
|
|
extra: view.extra,
|
2024-04-12 10:21:41 +02:00
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
for params in create_view_params {
|
|
|
|
self
|
|
|
|
.appflowy_core
|
|
|
|
.folder_manager
|
2024-07-02 13:02:15 +08:00
|
|
|
.create_view_with_params(params, true)
|
2024-04-12 10:21:41 +02:00
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-21 10:47:31 +08:00
|
|
|
/// Create orphan views in the folder.
|
|
|
|
/// Orphan view: the parent_view_id equal to the view_id
|
|
|
|
/// Normally, the orphan view will be created in nested database
|
|
|
|
pub async fn create_orphan_view(&self, name: &str, view_id: &str, layout: ViewLayoutPB) {
|
|
|
|
let payload = CreateOrphanViewPayloadPB {
|
|
|
|
name: name.to_string(),
|
|
|
|
layout,
|
|
|
|
view_id: view_id.to_string(),
|
|
|
|
initial_data: vec![],
|
|
|
|
};
|
|
|
|
EventBuilder::new(self.clone())
|
|
|
|
.event(FolderEvent::CreateOrphanView)
|
|
|
|
.payload(payload)
|
|
|
|
.async_send()
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
|
2024-08-18 05:16:42 +02:00
|
|
|
pub async fn get_folder_data(&self) -> FolderData {
|
2024-12-08 18:25:25 +08:00
|
|
|
self
|
2024-08-18 05:16:42 +02:00
|
|
|
.appflowy_core
|
|
|
|
.folder_manager
|
2024-12-08 18:25:25 +08:00
|
|
|
.get_folder_data()
|
|
|
|
.await
|
|
|
|
.unwrap()
|
2024-04-12 10:21:41 +02:00
|
|
|
}
|
|
|
|
|
2024-07-08 13:45:57 +08:00
|
|
|
pub async fn get_publish_payload(
|
|
|
|
&self,
|
|
|
|
view_id: &str,
|
2024-07-22 13:35:42 +08:00
|
|
|
include_children: bool,
|
|
|
|
) -> Vec<PublishPayload> {
|
2024-07-08 13:45:57 +08:00
|
|
|
let manager = self.folder_manager.clone();
|
|
|
|
let payload = manager
|
|
|
|
.get_batch_publish_payload(view_id, None, include_children)
|
|
|
|
.await;
|
|
|
|
|
|
|
|
if payload.is_err() {
|
|
|
|
panic!("Get publish payload failed")
|
|
|
|
}
|
|
|
|
|
|
|
|
payload.unwrap()
|
|
|
|
}
|
|
|
|
|
2024-12-20 00:15:01 +08:00
|
|
|
pub async fn gather_encode_collab_from_disk(
|
2024-07-22 13:35:42 +08:00
|
|
|
&self,
|
|
|
|
view_id: &str,
|
|
|
|
layout: ViewLayout,
|
2024-12-20 00:15:01 +08:00
|
|
|
) -> GatherEncodedCollab {
|
2024-12-08 18:25:25 +08:00
|
|
|
self
|
|
|
|
.folder_manager
|
2024-12-20 00:15:01 +08:00
|
|
|
.gather_publish_encode_collab(view_id, &layout)
|
2024-07-22 13:35:42 +08:00
|
|
|
.await
|
|
|
|
.unwrap()
|
2024-07-08 13:45:57 +08:00
|
|
|
}
|
|
|
|
|
2023-10-24 20:11:06 +08:00
|
|
|
pub async fn get_all_workspace_views(&self) -> Vec<ViewPB> {
|
|
|
|
EventBuilder::new(self.clone())
|
2024-03-21 11:02:03 +07:00
|
|
|
.event(FolderEvent::ReadCurrentWorkspaceViews)
|
2023-10-24 20:11:06 +08:00
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<RepeatedViewPB>()
|
|
|
|
.items
|
|
|
|
}
|
|
|
|
|
2024-07-22 13:35:42 +08:00
|
|
|
// get all the views in the current workspace, including the views in the trash and the orphan views
|
|
|
|
pub async fn get_all_views(&self) -> Vec<ViewPB> {
|
|
|
|
EventBuilder::new(self.clone())
|
|
|
|
.event(FolderEvent::GetAllViews)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<RepeatedViewPB>()
|
|
|
|
.items
|
|
|
|
}
|
|
|
|
|
2023-12-27 11:42:39 +08:00
|
|
|
pub async fn get_trash(&self) -> RepeatedTrashPB {
|
|
|
|
EventBuilder::new(self.clone())
|
|
|
|
.event(FolderEvent::ListTrashItems)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<RepeatedTrashPB>()
|
|
|
|
}
|
|
|
|
|
2023-10-24 20:11:06 +08:00
|
|
|
pub async fn delete_view(&self, view_id: &str) {
|
|
|
|
let payload = RepeatedViewIdPB {
|
|
|
|
items: vec![view_id.to_string()],
|
|
|
|
};
|
|
|
|
|
|
|
|
// delete the view. the view will be moved to trash
|
2024-04-11 14:47:34 +08:00
|
|
|
if let Some(err) = EventBuilder::new(self.clone())
|
2023-10-24 20:11:06 +08:00
|
|
|
.event(FolderEvent::DeleteView)
|
|
|
|
.payload(payload)
|
|
|
|
.async_send()
|
2024-04-11 14:47:34 +08:00
|
|
|
.await
|
|
|
|
.error()
|
|
|
|
{
|
|
|
|
panic!("Delete view failed: {:?}", err)
|
|
|
|
};
|
2023-10-24 20:11:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_view(&self, changeset: UpdateViewPayloadPB) -> Option<FlowyError> {
|
|
|
|
// delete the view. the view will be moved to trash
|
|
|
|
EventBuilder::new(self.clone())
|
|
|
|
.event(FolderEvent::UpdateView)
|
|
|
|
.payload(changeset)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.error()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_view_icon(&self, payload: UpdateViewIconPayloadPB) -> Option<FlowyError> {
|
|
|
|
EventBuilder::new(self.clone())
|
|
|
|
.event(FolderEvent::UpdateViewIcon)
|
|
|
|
.payload(payload)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.error()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_view(&self, parent_id: &str, name: String) -> ViewPB {
|
2024-07-22 13:35:42 +08:00
|
|
|
self
|
|
|
|
.create_view_with_layout(parent_id, name, Default::default())
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_view_with_layout(
|
|
|
|
&self,
|
|
|
|
parent_id: &str,
|
|
|
|
name: String,
|
|
|
|
layout: ViewLayoutPB,
|
|
|
|
) -> ViewPB {
|
2023-10-24 20:11:06 +08:00
|
|
|
let payload = CreateViewPayloadPB {
|
|
|
|
parent_view_id: parent_id.to_string(),
|
|
|
|
name,
|
|
|
|
thumbnail: None,
|
2024-07-22 13:35:42 +08:00
|
|
|
layout,
|
2023-10-24 20:11:06 +08:00
|
|
|
initial_data: vec![],
|
|
|
|
meta: Default::default(),
|
|
|
|
set_as_current: false,
|
|
|
|
index: None,
|
2024-03-21 11:02:03 +07:00
|
|
|
section: None,
|
2024-06-25 10:03:02 +08:00
|
|
|
view_id: None,
|
2024-07-01 14:43:57 +08:00
|
|
|
extra: None,
|
2023-10-24 20:11:06 +08:00
|
|
|
};
|
|
|
|
EventBuilder::new(self.clone())
|
|
|
|
.event(FolderEvent::CreateView)
|
|
|
|
.payload(payload)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<ViewPB>()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn get_view(&self, view_id: &str) -> ViewPB {
|
|
|
|
EventBuilder::new(self.clone())
|
2023-12-24 07:44:08 +08:00
|
|
|
.event(FolderEvent::GetView)
|
2023-10-24 20:11:06 +08:00
|
|
|
.payload(ViewIdPB {
|
|
|
|
value: view_id.to_string(),
|
|
|
|
})
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<ViewPB>()
|
|
|
|
}
|
2024-03-12 10:59:52 +08:00
|
|
|
|
2024-07-01 14:44:08 +08:00
|
|
|
pub async fn import_data(&self, data: ImportPayloadPB) -> Vec<ViewPB> {
|
2024-03-12 10:59:52 +08:00
|
|
|
EventBuilder::new(self.clone())
|
|
|
|
.event(FolderEvent::ImportData)
|
|
|
|
.payload(data)
|
|
|
|
.async_send()
|
|
|
|
.await
|
2024-07-01 14:44:08 +08:00
|
|
|
.parse::<RepeatedViewPB>()
|
|
|
|
.items
|
2024-03-12 10:59:52 +08:00
|
|
|
}
|
2024-05-21 10:47:31 +08:00
|
|
|
|
|
|
|
pub async fn get_view_ancestors(&self, view_id: &str) -> Vec<ViewPB> {
|
|
|
|
EventBuilder::new(self.clone())
|
|
|
|
.event(FolderEvent::GetViewAncestors)
|
|
|
|
.payload(ViewIdPB {
|
|
|
|
value: view_id.to_string(),
|
|
|
|
})
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<RepeatedViewPB>()
|
|
|
|
.items
|
|
|
|
}
|
2023-10-24 20:11:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ViewTest {
|
|
|
|
pub sdk: EventIntegrationTest,
|
|
|
|
pub workspace: WorkspacePB,
|
|
|
|
pub child_view: ViewPB,
|
|
|
|
}
|
|
|
|
impl ViewTest {
|
|
|
|
#[allow(dead_code)]
|
2024-04-12 10:21:41 +02:00
|
|
|
pub async fn new(sdk: &EventIntegrationTest, layout: ViewLayout, data: Vec<u8>) -> Self {
|
2023-11-01 11:45:35 +08:00
|
|
|
let workspace = sdk.folder_manager.get_current_workspace().await.unwrap();
|
2023-10-24 20:11:06 +08:00
|
|
|
|
|
|
|
let payload = CreateViewPayloadPB {
|
|
|
|
parent_view_id: workspace.id.clone(),
|
|
|
|
name: "View A".to_string(),
|
|
|
|
thumbnail: Some("http://1.png".to_string()),
|
2024-04-12 10:21:41 +02:00
|
|
|
layout: layout.into(),
|
2023-10-24 20:11:06 +08:00
|
|
|
initial_data: data,
|
|
|
|
meta: Default::default(),
|
|
|
|
set_as_current: true,
|
|
|
|
index: None,
|
2024-03-21 11:02:03 +07:00
|
|
|
section: None,
|
2024-06-25 10:03:02 +08:00
|
|
|
view_id: None,
|
2024-07-01 14:43:57 +08:00
|
|
|
extra: None,
|
2023-10-24 20:11:06 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
let view = EventBuilder::new(sdk.clone())
|
|
|
|
.event(CreateView)
|
|
|
|
.payload(payload)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<ViewPB>();
|
2024-04-12 10:21:41 +02:00
|
|
|
|
2023-10-24 20:11:06 +08:00
|
|
|
Self {
|
|
|
|
sdk: sdk.clone(),
|
|
|
|
workspace,
|
|
|
|
child_view: view,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn new_grid_view(sdk: &EventIntegrationTest, data: Vec<u8>) -> Self {
|
2024-04-12 10:21:41 +02:00
|
|
|
Self::new(sdk, ViewLayout::Grid, data).await
|
2023-10-24 20:11:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn new_board_view(sdk: &EventIntegrationTest, data: Vec<u8>) -> Self {
|
2024-04-12 10:21:41 +02:00
|
|
|
Self::new(sdk, ViewLayout::Board, data).await
|
2023-10-24 20:11:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn new_calendar_view(sdk: &EventIntegrationTest, data: Vec<u8>) -> Self {
|
2024-04-12 10:21:41 +02:00
|
|
|
Self::new(sdk, ViewLayout::Calendar, data).await
|
2023-10-24 20:11:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-01 11:45:35 +08:00
|
|
|
#[allow(dead_code)]
|
2023-10-24 20:11:06 +08:00
|
|
|
async fn create_workspace(sdk: &EventIntegrationTest, name: &str, desc: &str) -> WorkspacePB {
|
|
|
|
let request = CreateWorkspacePayloadPB {
|
|
|
|
name: name.to_owned(),
|
|
|
|
desc: desc.to_owned(),
|
|
|
|
};
|
|
|
|
|
|
|
|
EventBuilder::new(sdk.clone())
|
2024-03-13 15:07:52 +08:00
|
|
|
.event(CreateFolderWorkspace)
|
2023-10-24 20:11:06 +08:00
|
|
|
.payload(request)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<WorkspacePB>()
|
|
|
|
}
|