2024-04-12 17:08:47 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2024-04-12 08:21:41 +00:00
|
|
|
use collab_folder::{FolderData, View};
|
2023-12-30 23:29:40 +00:00
|
|
|
use flowy_folder::entities::icon::UpdateViewIconPayloadPB;
|
|
|
|
use flowy_folder::event_map::FolderEvent;
|
|
|
|
use flowy_folder::event_map::FolderEvent::*;
|
2024-04-12 08:21:41 +00:00
|
|
|
use flowy_folder::{entities::*, ViewLayout};
|
|
|
|
use flowy_search::services::manager::{SearchHandler, SearchType};
|
2023-10-25 13:35:47 +00:00
|
|
|
use flowy_user::entities::{
|
2024-06-24 06:19:36 +00:00
|
|
|
AcceptWorkspaceInvitationPB, QueryWorkspacePB, RemoveWorkspaceMemberPB,
|
2024-04-11 06:47:34 +00:00
|
|
|
RepeatedWorkspaceInvitationPB, RepeatedWorkspaceMemberPB, WorkspaceMemberInvitationPB,
|
2023-10-25 13:35:47 +00:00
|
|
|
WorkspaceMemberPB,
|
|
|
|
};
|
2023-10-24 12:11:06 +00:00
|
|
|
use flowy_user::errors::FlowyError;
|
2023-10-25 13:35:47 +00:00
|
|
|
use flowy_user::event_map::UserEvent;
|
2024-04-11 06:47:34 +00:00
|
|
|
use flowy_user_pub::entities::Role;
|
2023-10-24 12:11:06 +00:00
|
|
|
|
|
|
|
use crate::event_builder::EventBuilder;
|
|
|
|
use crate::EventIntegrationTest;
|
|
|
|
|
|
|
|
impl EventIntegrationTest {
|
2024-04-11 06:47:34 +00:00
|
|
|
pub async fn invite_workspace_member(&self, workspace_id: &str, email: &str, role: Role) {
|
2024-04-11 12:15:40 +00:00
|
|
|
EventBuilder::new(self.clone())
|
2024-04-11 06:47:34 +00: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 12:15:40 +00:00
|
|
|
.await;
|
2024-04-11 06:47:34 +00:00
|
|
|
}
|
|
|
|
|
2024-06-24 06:19:36 +00: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 06:47:34 +00:00
|
|
|
pub async fn list_workspace_invitations(&self) -> RepeatedWorkspaceInvitationPB {
|
2023-10-25 13:35:47 +00:00
|
|
|
EventBuilder::new(self.clone())
|
2024-04-11 06:47:34 +00: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 13:35:47 +00:00
|
|
|
.event(UserEvent::RemoveWorkspaceMember)
|
|
|
|
.payload(RemoveWorkspaceMemberPB {
|
|
|
|
workspace_id: workspace_id.to_string(),
|
|
|
|
email: email.to_string(),
|
|
|
|
})
|
|
|
|
.async_send()
|
2024-04-11 06:47:34 +00:00
|
|
|
.await
|
|
|
|
.error()
|
|
|
|
{
|
|
|
|
panic!("Delete workspace member failed: {:?}", err)
|
|
|
|
};
|
2023-10-25 13:35:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn get_workspace_members(&self, workspace_id: &str) -> Vec<WorkspaceMemberPB> {
|
|
|
|
EventBuilder::new(self.clone())
|
2024-06-17 12:30:19 +00:00
|
|
|
.event(UserEvent::GetWorkspaceMembers)
|
2023-10-25 13:35:47 +00:00
|
|
|
.payload(QueryWorkspacePB {
|
|
|
|
workspace_id: workspace_id.to_string(),
|
|
|
|
})
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<RepeatedWorkspaceMemberPB>()
|
|
|
|
.items
|
|
|
|
}
|
|
|
|
|
2023-11-01 03:45:35 +00:00
|
|
|
pub async fn get_current_workspace(&self) -> WorkspacePB {
|
2023-10-24 12:11:06 +00:00
|
|
|
EventBuilder::new(self.clone())
|
2023-11-01 03:45:35 +00:00
|
|
|
.event(FolderEvent::ReadCurrentWorkspace)
|
2023-10-24 12:11:06 +00:00
|
|
|
.async_send()
|
|
|
|
.await
|
2023-11-01 03:45:35 +00:00
|
|
|
.parse::<WorkspacePB>()
|
2023-10-24 12:11:06 +00:00
|
|
|
}
|
|
|
|
|
2024-04-12 08:21:41 +00: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,
|
|
|
|
desc: "".to_string(),
|
|
|
|
layout: view.layout.into(),
|
|
|
|
view_id: view.id,
|
|
|
|
initial_data: vec![],
|
|
|
|
meta: Default::default(),
|
|
|
|
set_as_current: false,
|
|
|
|
index: None,
|
|
|
|
section: None,
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
for params in create_view_params {
|
|
|
|
self
|
|
|
|
.appflowy_core
|
|
|
|
.folder_manager
|
|
|
|
.create_view_with_params(params)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-21 02:47:31 +00: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(),
|
|
|
|
desc: "".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-04-12 08:21:41 +00:00
|
|
|
pub fn get_folder_data(&self) -> FolderData {
|
|
|
|
let mutex_folder = self.appflowy_core.folder_manager.get_mutex_folder().clone();
|
2024-04-23 13:46:57 +00:00
|
|
|
let folder_lock_guard = mutex_folder.read();
|
2024-04-12 08:21:41 +00:00
|
|
|
let folder = folder_lock_guard.as_ref().unwrap();
|
2024-04-26 01:44:07 +00:00
|
|
|
let workspace_id = self.appflowy_core.user_manager.workspace_id().unwrap();
|
|
|
|
folder.get_folder_data(&workspace_id).clone().unwrap()
|
2024-04-12 08:21:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-24 12:11:06 +00:00
|
|
|
pub async fn get_all_workspace_views(&self) -> Vec<ViewPB> {
|
|
|
|
EventBuilder::new(self.clone())
|
2024-03-21 04:02:03 +00:00
|
|
|
.event(FolderEvent::ReadCurrentWorkspaceViews)
|
2023-10-24 12:11:06 +00:00
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<RepeatedViewPB>()
|
|
|
|
.items
|
|
|
|
}
|
|
|
|
|
2023-12-27 03:42:39 +00:00
|
|
|
pub async fn get_trash(&self) -> RepeatedTrashPB {
|
|
|
|
EventBuilder::new(self.clone())
|
|
|
|
.event(FolderEvent::ListTrashItems)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<RepeatedTrashPB>()
|
|
|
|
}
|
|
|
|
|
2023-10-24 12:11:06 +00: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 06:47:34 +00:00
|
|
|
if let Some(err) = EventBuilder::new(self.clone())
|
2023-10-24 12:11:06 +00:00
|
|
|
.event(FolderEvent::DeleteView)
|
|
|
|
.payload(payload)
|
|
|
|
.async_send()
|
2024-04-11 06:47:34 +00:00
|
|
|
.await
|
|
|
|
.error()
|
|
|
|
{
|
|
|
|
panic!("Delete view failed: {:?}", err)
|
|
|
|
};
|
2023-10-24 12:11:06 +00: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 {
|
|
|
|
let payload = CreateViewPayloadPB {
|
|
|
|
parent_view_id: parent_id.to_string(),
|
|
|
|
name,
|
|
|
|
desc: "".to_string(),
|
|
|
|
thumbnail: None,
|
|
|
|
layout: Default::default(),
|
|
|
|
initial_data: vec![],
|
|
|
|
meta: Default::default(),
|
|
|
|
set_as_current: false,
|
|
|
|
index: None,
|
2024-03-21 04:02:03 +00:00
|
|
|
section: None,
|
2023-10-24 12:11:06 +00: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-23 23:44:08 +00:00
|
|
|
.event(FolderEvent::GetView)
|
2023-10-24 12:11:06 +00:00
|
|
|
.payload(ViewIdPB {
|
|
|
|
value: view_id.to_string(),
|
|
|
|
})
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<ViewPB>()
|
|
|
|
}
|
2024-03-12 02:59:52 +00:00
|
|
|
|
|
|
|
pub async fn import_data(&self, data: ImportPB) -> ViewPB {
|
|
|
|
EventBuilder::new(self.clone())
|
|
|
|
.event(FolderEvent::ImportData)
|
|
|
|
.payload(data)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<ViewPB>()
|
|
|
|
}
|
2024-05-21 02:47:31 +00: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 12:11:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ViewTest {
|
|
|
|
pub sdk: EventIntegrationTest,
|
|
|
|
pub workspace: WorkspacePB,
|
|
|
|
pub child_view: ViewPB,
|
|
|
|
}
|
|
|
|
impl ViewTest {
|
|
|
|
#[allow(dead_code)]
|
2024-04-12 08:21:41 +00:00
|
|
|
pub async fn new(sdk: &EventIntegrationTest, layout: ViewLayout, data: Vec<u8>) -> Self {
|
2023-11-01 03:45:35 +00:00
|
|
|
let workspace = sdk.folder_manager.get_current_workspace().await.unwrap();
|
2023-10-24 12:11:06 +00:00
|
|
|
|
|
|
|
let payload = CreateViewPayloadPB {
|
|
|
|
parent_view_id: workspace.id.clone(),
|
|
|
|
name: "View A".to_string(),
|
|
|
|
desc: "".to_string(),
|
|
|
|
thumbnail: Some("http://1.png".to_string()),
|
2024-04-12 08:21:41 +00:00
|
|
|
layout: layout.into(),
|
2023-10-24 12:11:06 +00:00
|
|
|
initial_data: data,
|
|
|
|
meta: Default::default(),
|
|
|
|
set_as_current: true,
|
|
|
|
index: None,
|
2024-03-21 04:02:03 +00:00
|
|
|
section: None,
|
2023-10-24 12:11:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let view = EventBuilder::new(sdk.clone())
|
|
|
|
.event(CreateView)
|
|
|
|
.payload(payload)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<ViewPB>();
|
2024-04-12 08:21:41 +00:00
|
|
|
|
2023-10-24 12:11:06 +00:00
|
|
|
Self {
|
|
|
|
sdk: sdk.clone(),
|
|
|
|
workspace,
|
|
|
|
child_view: view,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn new_grid_view(sdk: &EventIntegrationTest, data: Vec<u8>) -> Self {
|
2024-04-12 08:21:41 +00:00
|
|
|
Self::new(sdk, ViewLayout::Grid, data).await
|
2023-10-24 12:11:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn new_board_view(sdk: &EventIntegrationTest, data: Vec<u8>) -> Self {
|
2024-04-12 08:21:41 +00:00
|
|
|
Self::new(sdk, ViewLayout::Board, data).await
|
2023-10-24 12:11:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn new_calendar_view(sdk: &EventIntegrationTest, data: Vec<u8>) -> Self {
|
2024-04-12 08:21:41 +00:00
|
|
|
Self::new(sdk, ViewLayout::Calendar, data).await
|
2023-10-24 12:11:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-01 03:45:35 +00:00
|
|
|
#[allow(dead_code)]
|
2023-10-24 12:11:06 +00: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 07:07:52 +00:00
|
|
|
.event(CreateFolderWorkspace)
|
2023-10-24 12:11:06 +00:00
|
|
|
.payload(request)
|
|
|
|
.async_send()
|
|
|
|
.await
|
|
|
|
.parse::<WorkspacePB>()
|
|
|
|
}
|