Merge pull request #926 from AppFlowy-IO/favorite-recent-views
Add section timestamp for get recent/favorite/trash section endpoints
This commit is contained in:
commit
dd23612d49
|
|
@ -3,10 +3,10 @@ use app_error::AppError;
|
|||
use app_error::ErrorCode;
|
||||
use client_api_entity::auth_dto::DeleteUserQuery;
|
||||
use client_api_entity::server_info_dto::ServerInfoResponseItem;
|
||||
use client_api_entity::workspace_dto::FolderView;
|
||||
use client_api_entity::workspace_dto::QueryWorkspaceFolder;
|
||||
use client_api_entity::workspace_dto::QueryWorkspaceParam;
|
||||
use client_api_entity::workspace_dto::SectionItems;
|
||||
use client_api_entity::workspace_dto::FavoriteSectionItems;
|
||||
use client_api_entity::workspace_dto::RecentSectionItems;
|
||||
use client_api_entity::workspace_dto::TrashSectionItems;
|
||||
use client_api_entity::workspace_dto::{FolderView, QueryWorkspaceFolder, QueryWorkspaceParam};
|
||||
use client_api_entity::AuthProvider;
|
||||
use client_api_entity::CollabType;
|
||||
use gotrue::grant::PasswordGrant;
|
||||
|
|
@ -727,7 +727,7 @@ impl Client {
|
|||
pub async fn get_workspace_favorite(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
) -> Result<SectionItems, AppResponseError> {
|
||||
) -> Result<FavoriteSectionItems, AppResponseError> {
|
||||
let url = format!("{}/api/workspace/{}/favorite", self.base_url, workspace_id);
|
||||
let resp = self
|
||||
.http_client_with_auth(Method::GET, &url)
|
||||
|
|
@ -735,7 +735,7 @@ impl Client {
|
|||
.send()
|
||||
.await?;
|
||||
log_request_id(&resp);
|
||||
AppResponse::<SectionItems>::from_response(resp)
|
||||
AppResponse::<FavoriteSectionItems>::from_response(resp)
|
||||
.await?
|
||||
.into_data()
|
||||
}
|
||||
|
|
@ -744,7 +744,7 @@ impl Client {
|
|||
pub async fn get_workspace_recent(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
) -> Result<SectionItems, AppResponseError> {
|
||||
) -> Result<RecentSectionItems, AppResponseError> {
|
||||
let url = format!("{}/api/workspace/{}/recent", self.base_url, workspace_id);
|
||||
let resp = self
|
||||
.http_client_with_auth(Method::GET, &url)
|
||||
|
|
@ -752,7 +752,7 @@ impl Client {
|
|||
.send()
|
||||
.await?;
|
||||
log_request_id(&resp);
|
||||
AppResponse::<SectionItems>::from_response(resp)
|
||||
AppResponse::<RecentSectionItems>::from_response(resp)
|
||||
.await?
|
||||
.into_data()
|
||||
}
|
||||
|
|
@ -761,7 +761,7 @@ impl Client {
|
|||
pub async fn get_workspace_trash(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
) -> Result<SectionItems, AppResponseError> {
|
||||
) -> Result<TrashSectionItems, AppResponseError> {
|
||||
let url = format!("{}/api/workspace/{}/trash", self.base_url, workspace_id);
|
||||
let resp = self
|
||||
.http_client_with_auth(Method::GET, &url)
|
||||
|
|
@ -769,7 +769,7 @@ impl Client {
|
|||
.send()
|
||||
.await?;
|
||||
log_request_id(&resp);
|
||||
AppResponse::<SectionItems>::from_response(resp)
|
||||
AppResponse::<TrashSectionItems>::from_response(resp)
|
||||
.await?
|
||||
.into_data()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,6 +142,42 @@ pub struct PublishedDuplicate {
|
|||
pub dest_view_id: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RecentFolderView {
|
||||
#[serde(flatten)]
|
||||
pub view: FolderView,
|
||||
pub last_viewed_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FavoriteFolderView {
|
||||
#[serde(flatten)]
|
||||
pub view: FolderView,
|
||||
pub favorited_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TrashFolderView {
|
||||
#[serde(flatten)]
|
||||
pub view: FolderView,
|
||||
pub deleted_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RecentSectionItems {
|
||||
pub views: Vec<RecentFolderView>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FavoriteSectionItems {
|
||||
pub views: Vec<FavoriteFolderView>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TrashSectionItems {
|
||||
pub views: Vec<TrashFolderView>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FolderView {
|
||||
pub view_id: String,
|
||||
|
|
@ -173,11 +209,6 @@ pub struct PublishInfoView {
|
|||
pub info: PublishInfo,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SectionItems {
|
||||
pub views: Vec<FolderView>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Hash, Clone, Serialize_repr, Deserialize_repr)]
|
||||
#[repr(u8)]
|
||||
pub enum IconType {
|
||||
|
|
|
|||
|
|
@ -1575,7 +1575,7 @@ async fn get_recent_views_handler(
|
|||
user_uuid: UserUuid,
|
||||
workspace_id: web::Path<Uuid>,
|
||||
state: Data<AppState>,
|
||||
) -> Result<Json<AppResponse<SectionItems>>> {
|
||||
) -> Result<Json<AppResponse<RecentSectionItems>>> {
|
||||
let uid = state.user_cache.get_user_uid(&user_uuid).await?;
|
||||
let workspace_id = workspace_id.into_inner();
|
||||
state
|
||||
|
|
@ -1589,7 +1589,7 @@ async fn get_recent_views_handler(
|
|||
workspace_id,
|
||||
)
|
||||
.await?;
|
||||
let section_items = SectionItems {
|
||||
let section_items = RecentSectionItems {
|
||||
views: folder_views,
|
||||
};
|
||||
Ok(Json(AppResponse::Ok().with_data(section_items)))
|
||||
|
|
@ -1599,7 +1599,7 @@ async fn get_favorite_views_handler(
|
|||
user_uuid: UserUuid,
|
||||
workspace_id: web::Path<Uuid>,
|
||||
state: Data<AppState>,
|
||||
) -> Result<Json<AppResponse<SectionItems>>> {
|
||||
) -> Result<Json<AppResponse<FavoriteSectionItems>>> {
|
||||
let uid = state.user_cache.get_user_uid(&user_uuid).await?;
|
||||
let workspace_id = workspace_id.into_inner();
|
||||
state
|
||||
|
|
@ -1613,7 +1613,7 @@ async fn get_favorite_views_handler(
|
|||
workspace_id,
|
||||
)
|
||||
.await?;
|
||||
let section_items = SectionItems {
|
||||
let section_items = FavoriteSectionItems {
|
||||
views: folder_views,
|
||||
};
|
||||
Ok(Json(AppResponse::Ok().with_data(section_items)))
|
||||
|
|
@ -1623,7 +1623,7 @@ async fn get_trash_views_handler(
|
|||
user_uuid: UserUuid,
|
||||
workspace_id: web::Path<Uuid>,
|
||||
state: Data<AppState>,
|
||||
) -> Result<Json<AppResponse<SectionItems>>> {
|
||||
) -> Result<Json<AppResponse<TrashSectionItems>>> {
|
||||
let uid = state.user_cache.get_user_uid(&user_uuid).await?;
|
||||
let workspace_id = workspace_id.into_inner();
|
||||
state
|
||||
|
|
@ -1632,7 +1632,7 @@ async fn get_trash_views_handler(
|
|||
.await?;
|
||||
let folder_views =
|
||||
get_user_trash_folder_views(&state.collab_access_control_storage, uid, workspace_id).await?;
|
||||
let section_items = SectionItems {
|
||||
let section_items = TrashSectionItems {
|
||||
views: folder_views,
|
||||
};
|
||||
Ok(Json(AppResponse::Ok().with_data(section_items)))
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ use std::collections::HashSet;
|
|||
use app_error::AppError;
|
||||
use chrono::DateTime;
|
||||
use collab_folder::{Folder, SectionItem, ViewLayout as CollabFolderViewLayout};
|
||||
use shared_entity::dto::workspace_dto::{FolderView, FolderViewMinimal, ViewLayout};
|
||||
use shared_entity::dto::workspace_dto::{
|
||||
FavoriteFolderView, FolderView, FolderViewMinimal, RecentFolderView, TrashFolderView, ViewLayout,
|
||||
};
|
||||
|
||||
/// Return all folders belonging to a workspace, excluding private sections which the user does not have access to.
|
||||
pub fn collab_folder_to_folder_view(
|
||||
|
|
@ -116,27 +118,96 @@ fn to_folder_view(
|
|||
})
|
||||
}
|
||||
|
||||
pub fn section_items_to_folder_view(
|
||||
pub fn section_items_to_favorite_folder_view(
|
||||
section_items: &[SectionItem],
|
||||
folder: &Folder,
|
||||
published_view_ids: &HashSet<String>,
|
||||
) -> Vec<FolderView> {
|
||||
) -> Vec<FavoriteFolderView> {
|
||||
section_items
|
||||
.iter()
|
||||
.filter_map(|section_item| {
|
||||
let view = folder.get_view(§ion_item.id);
|
||||
view.map(|v| FolderView {
|
||||
view_id: v.id.clone(),
|
||||
name: v.name.clone(),
|
||||
icon: v.icon.as_ref().map(|icon| to_dto_view_icon(icon.clone())),
|
||||
is_space: false,
|
||||
is_private: false,
|
||||
is_published: published_view_ids.contains(&v.id),
|
||||
created_at: DateTime::from_timestamp(v.created_at, 0).unwrap_or_default(),
|
||||
last_edited_time: DateTime::from_timestamp(v.last_edited_time, 0).unwrap_or_default(),
|
||||
layout: to_dto_view_layout(&v.layout),
|
||||
extra: v.extra.as_ref().map(|e| parse_extra_field_as_json(e)),
|
||||
children: vec![],
|
||||
view.map(|v| {
|
||||
let folder_view = FolderView {
|
||||
view_id: v.id.clone(),
|
||||
name: v.name.clone(),
|
||||
icon: v.icon.as_ref().map(|icon| to_dto_view_icon(icon.clone())),
|
||||
is_space: false,
|
||||
is_private: false,
|
||||
is_published: published_view_ids.contains(&v.id),
|
||||
created_at: DateTime::from_timestamp(v.created_at, 0).unwrap_or_default(),
|
||||
last_edited_time: DateTime::from_timestamp(v.last_edited_time, 0).unwrap_or_default(),
|
||||
layout: to_dto_view_layout(&v.layout),
|
||||
extra: v.extra.as_ref().map(|e| parse_extra_field_as_json(e)),
|
||||
children: vec![],
|
||||
};
|
||||
FavoriteFolderView {
|
||||
view: folder_view,
|
||||
favorited_at: DateTime::from_timestamp(section_item.timestamp, 0).unwrap_or_default(),
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn section_items_to_recent_folder_view(
|
||||
section_items: &[SectionItem],
|
||||
folder: &Folder,
|
||||
published_view_ids: &HashSet<String>,
|
||||
) -> Vec<RecentFolderView> {
|
||||
section_items
|
||||
.iter()
|
||||
.filter_map(|section_item| {
|
||||
let view = folder.get_view(§ion_item.id);
|
||||
view.map(|v| {
|
||||
let folder_view = FolderView {
|
||||
view_id: v.id.clone(),
|
||||
name: v.name.clone(),
|
||||
icon: v.icon.as_ref().map(|icon| to_dto_view_icon(icon.clone())),
|
||||
is_space: false,
|
||||
is_private: false,
|
||||
is_published: published_view_ids.contains(&v.id),
|
||||
created_at: DateTime::from_timestamp(v.created_at, 0).unwrap_or_default(),
|
||||
last_edited_time: DateTime::from_timestamp(v.last_edited_time, 0).unwrap_or_default(),
|
||||
layout: to_dto_view_layout(&v.layout),
|
||||
extra: v.extra.as_ref().map(|e| parse_extra_field_as_json(e)),
|
||||
children: vec![],
|
||||
};
|
||||
RecentFolderView {
|
||||
view: folder_view,
|
||||
last_viewed_at: DateTime::from_timestamp(section_item.timestamp, 0).unwrap_or_default(),
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn section_items_to_trash_folder_view(
|
||||
section_items: &[SectionItem],
|
||||
folder: &Folder,
|
||||
) -> Vec<TrashFolderView> {
|
||||
section_items
|
||||
.iter()
|
||||
.filter_map(|section_item| {
|
||||
let view = folder.get_view(§ion_item.id);
|
||||
view.map(|v| {
|
||||
let folder_view = FolderView {
|
||||
view_id: v.id.clone(),
|
||||
name: v.name.clone(),
|
||||
icon: v.icon.as_ref().map(|icon| to_dto_view_icon(icon.clone())),
|
||||
is_space: false,
|
||||
is_private: false,
|
||||
is_published: false,
|
||||
created_at: DateTime::from_timestamp(v.created_at, 0).unwrap_or_default(),
|
||||
last_edited_time: DateTime::from_timestamp(v.last_edited_time, 0).unwrap_or_default(),
|
||||
layout: to_dto_view_layout(&v.layout),
|
||||
extra: v.extra.as_ref().map(|e| parse_extra_field_as_json(e)),
|
||||
children: vec![],
|
||||
};
|
||||
TrashFolderView {
|
||||
view: folder_view,
|
||||
deleted_at: DateTime::from_timestamp(section_item.timestamp, 0).unwrap_or_default(),
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ use database::collab::{CollabStorage, GetCollabOrigin};
|
|||
use database::publish::select_published_view_ids_for_workspace;
|
||||
use database::publish::select_workspace_id_for_publish_namespace;
|
||||
use database_entity::dto::{QueryCollab, QueryCollabParams};
|
||||
use shared_entity::dto::workspace_dto::FavoriteFolderView;
|
||||
use shared_entity::dto::workspace_dto::RecentFolderView;
|
||||
use shared_entity::dto::workspace_dto::TrashFolderView;
|
||||
use sqlx::PgPool;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
|
|
@ -28,7 +31,9 @@ use database_entity::dto::{
|
|||
};
|
||||
|
||||
use super::folder_view::collab_folder_to_folder_view;
|
||||
use super::folder_view::section_items_to_folder_view;
|
||||
use super::folder_view::section_items_to_favorite_folder_view;
|
||||
use super::folder_view::section_items_to_recent_folder_view;
|
||||
use super::folder_view::section_items_to_trash_folder_view;
|
||||
use super::publish_outline::collab_folder_to_published_outline;
|
||||
|
||||
/// Create a new collab member
|
||||
|
|
@ -163,7 +168,7 @@ pub async fn get_user_favorite_folder_views(
|
|||
pg_pool: &PgPool,
|
||||
uid: i64,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<Vec<FolderView>, AppError> {
|
||||
) -> Result<Vec<FavoriteFolderView>, AppError> {
|
||||
let folder = get_latest_collab_folder(
|
||||
collab_storage,
|
||||
GetCollabOrigin::User { uid },
|
||||
|
|
@ -185,7 +190,7 @@ pub async fn get_user_favorite_folder_views(
|
|||
.into_iter()
|
||||
.filter(|s| !deleted_section_item_ids.contains(&s.id))
|
||||
.collect();
|
||||
Ok(section_items_to_folder_view(
|
||||
Ok(section_items_to_favorite_folder_view(
|
||||
&favorite_section_items,
|
||||
&folder,
|
||||
&publish_view_ids,
|
||||
|
|
@ -197,7 +202,7 @@ pub async fn get_user_recent_folder_views(
|
|||
pg_pool: &PgPool,
|
||||
uid: i64,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<Vec<FolderView>, AppError> {
|
||||
) -> Result<Vec<RecentFolderView>, AppError> {
|
||||
let folder = get_latest_collab_folder(
|
||||
collab_storage,
|
||||
GetCollabOrigin::User { uid },
|
||||
|
|
@ -219,7 +224,7 @@ pub async fn get_user_recent_folder_views(
|
|||
.into_iter()
|
||||
.map(|id| id.to_string())
|
||||
.collect();
|
||||
Ok(section_items_to_folder_view(
|
||||
Ok(section_items_to_recent_folder_view(
|
||||
&recent_section_items,
|
||||
&folder,
|
||||
&publish_view_ids,
|
||||
|
|
@ -230,7 +235,7 @@ pub async fn get_user_trash_folder_views(
|
|||
collab_storage: &CollabAccessControlStorage,
|
||||
uid: i64,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<Vec<FolderView>, AppError> {
|
||||
) -> Result<Vec<TrashFolderView>, AppError> {
|
||||
let folder = get_latest_collab_folder(
|
||||
collab_storage,
|
||||
GetCollabOrigin::User { uid },
|
||||
|
|
@ -238,11 +243,7 @@ pub async fn get_user_trash_folder_views(
|
|||
)
|
||||
.await?;
|
||||
let section_items = folder.get_my_trash_sections();
|
||||
Ok(section_items_to_folder_view(
|
||||
§ion_items,
|
||||
&folder,
|
||||
&HashSet::default(),
|
||||
))
|
||||
Ok(section_items_to_trash_folder_view(§ion_items, &folder))
|
||||
}
|
||||
|
||||
pub async fn get_user_workspace_structure(
|
||||
|
|
|
|||
|
|
@ -85,14 +85,17 @@ async fn get_section_items() {
|
|||
.unwrap();
|
||||
let favorite_section_items = c.get_workspace_favorite(&workspace_id).await.unwrap();
|
||||
assert_eq!(favorite_section_items.views.len(), 1);
|
||||
assert_eq!(favorite_section_items.views[0].view_id, new_favorite_id);
|
||||
assert_eq!(
|
||||
favorite_section_items.views[0].view.view_id,
|
||||
new_favorite_id
|
||||
);
|
||||
let trash_section_items = c.get_workspace_trash(&workspace_id).await.unwrap();
|
||||
assert_eq!(trash_section_items.views.len(), 1);
|
||||
assert_eq!(
|
||||
trash_section_items.views[0].view_id,
|
||||
trash_section_items.views[0].view.view_id,
|
||||
to_be_deleted_favorite_id
|
||||
);
|
||||
let recent_section_items = c.get_workspace_recent(&workspace_id).await.unwrap();
|
||||
assert_eq!(recent_section_items.views.len(), 1);
|
||||
assert_eq!(recent_section_items.views[0].view_id, recent_id);
|
||||
assert_eq!(recent_section_items.views[0].view.view_id, recent_id);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue