feat: add publish info to publish outline items (#1156)
This commit is contained in:
parent
505b4ca8fc
commit
a5d94a09d6
|
|
@ -46,6 +46,7 @@ jobs:
|
|||
- name: Build Docker Images
|
||||
run: |
|
||||
export DOCKER_DEFAULT_PLATFORM=linux/amd64
|
||||
cp deploy.env .env
|
||||
docker compose build appflowy_cloud appflowy_worker admin_frontend
|
||||
|
||||
- name: Push docker images to docker hub
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n apc.view_id,\n apc.publish_name,\n au.email AS publisher_email,\n apc.created_at AS publish_timestamp\n FROM af_published_collab apc\n JOIN af_user au ON apc.published_by = au.uid\n WHERE workspace_id = $1\n AND unpublished_at IS NULL\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "view_id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "publish_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "publisher_email",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "publish_timestamp",
|
||||
"type_info": "Timestamptz"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "4787139d2189fc33ac25ac07bb9f585f578bde4cd3f75a7da95aa849a25bca9d"
|
||||
}
|
||||
|
|
@ -686,3 +686,10 @@ impl From<AFQuickNoteRow> for QuickNote {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AFPublishViewWithPublishInfo {
|
||||
pub view_id: Uuid,
|
||||
pub publish_name: String,
|
||||
pub publisher_email: String,
|
||||
pub publish_timestamp: DateTime<Utc>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ use database_entity::dto::{
|
|||
use sqlx::{Executor, PgPool, Postgres};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::pg_row::AFPublishViewWithPublishInfo;
|
||||
|
||||
pub async fn select_user_is_collab_publisher_for_all_views(
|
||||
pg_pool: &PgPool,
|
||||
user_uuid: &Uuid,
|
||||
|
|
@ -678,3 +680,31 @@ pub async fn select_published_view_ids_for_workspace<'a, E: Executor<'a, Databas
|
|||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub async fn select_published_view_ids_with_publish_info_for_workspace<
|
||||
'a,
|
||||
E: Executor<'a, Database = Postgres>,
|
||||
>(
|
||||
executor: E,
|
||||
workspace_id: Uuid,
|
||||
) -> Result<Vec<AFPublishViewWithPublishInfo>, AppError> {
|
||||
let res = sqlx::query_as!(
|
||||
AFPublishViewWithPublishInfo,
|
||||
r#"
|
||||
SELECT
|
||||
apc.view_id,
|
||||
apc.publish_name,
|
||||
au.email AS publisher_email,
|
||||
apc.created_at AS publish_timestamp
|
||||
FROM af_published_collab apc
|
||||
JOIN af_user au ON apc.published_by = au.uid
|
||||
WHERE workspace_id = $1
|
||||
AND unpublished_at IS NULL
|
||||
"#,
|
||||
workspace_id,
|
||||
)
|
||||
.fetch_all(executor)
|
||||
.await?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -389,11 +389,20 @@ pub struct PublishedView {
|
|||
pub icon: Option<ViewIcon>,
|
||||
pub layout: ViewLayout,
|
||||
pub is_published: bool,
|
||||
#[serde(flatten)]
|
||||
pub info: Option<PublishedViewInfo>,
|
||||
/// contains fields like `is_space`, and font information
|
||||
pub extra: Option<serde_json::Value>,
|
||||
pub children: Vec<PublishedView>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PublishedViewInfo {
|
||||
pub publisher_email: String,
|
||||
pub publish_name: String,
|
||||
pub publish_timestamp: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct AFDatabase {
|
||||
pub id: String,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ use database::collab::select_last_updated_database_row_ids;
|
|||
use database::collab::select_workspace_database_oid;
|
||||
use database::collab::{CollabStorage, GetCollabOrigin};
|
||||
use database::publish::select_published_view_ids_for_workspace;
|
||||
use database::publish::select_published_view_ids_with_publish_info_for_workspace;
|
||||
use database::publish::select_workspace_id_for_publish_namespace;
|
||||
use database_entity::dto::QueryCollab;
|
||||
use database_entity::dto::QueryCollabResult;
|
||||
|
|
@ -46,6 +47,7 @@ use shared_entity::dto::workspace_dto::AFInsertDatabaseField;
|
|||
use shared_entity::dto::workspace_dto::DatabaseRowUpdatedItem;
|
||||
use shared_entity::dto::workspace_dto::FavoriteFolderView;
|
||||
use shared_entity::dto::workspace_dto::FolderViewMinimal;
|
||||
use shared_entity::dto::workspace_dto::PublishedViewInfo;
|
||||
use shared_entity::dto::workspace_dto::RecentFolderView;
|
||||
use shared_entity::dto::workspace_dto::TrashFolderView;
|
||||
use sqlx::PgPool;
|
||||
|
|
@ -457,13 +459,28 @@ pub async fn get_published_view(
|
|||
&workspace_id.to_string(),
|
||||
)
|
||||
.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()
|
||||
.map(|id| id.to_string())
|
||||
.collect();
|
||||
let published_view: PublishedView =
|
||||
collab_folder_to_published_outline(&workspace_id.to_string(), &folder, &publish_view_ids)?;
|
||||
let publish_view_ids_with_publish_info =
|
||||
select_published_view_ids_with_publish_info_for_workspace(pg_pool, workspace_id).await?;
|
||||
let publish_view_id_to_info_map: HashMap<String, PublishedViewInfo> =
|
||||
publish_view_ids_with_publish_info
|
||||
.into_iter()
|
||||
.map(|pv| {
|
||||
(
|
||||
pv.view_id.to_string(),
|
||||
PublishedViewInfo {
|
||||
publisher_email: pv.publisher_email.clone(),
|
||||
publish_name: pv.publish_name.clone(),
|
||||
publish_timestamp: pv.publish_timestamp,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let published_view: PublishedView = collab_folder_to_published_outline(
|
||||
&workspace_id.to_string(),
|
||||
&folder,
|
||||
&publish_view_id_to_info_map,
|
||||
)?;
|
||||
Ok(published_view)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use app_error::AppError;
|
||||
use collab_folder::Folder;
|
||||
use shared_entity::dto::workspace_dto::PublishedView;
|
||||
use shared_entity::dto::workspace_dto::{PublishedView, PublishedViewInfo};
|
||||
|
||||
use super::folder_view::{to_dto_view_icon, to_dto_view_layout};
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ use super::folder_view::{to_dto_view_icon, to_dto_view_layout};
|
|||
pub fn collab_folder_to_published_outline(
|
||||
root_view_id: &str,
|
||||
folder: &Folder,
|
||||
publish_view_ids: &HashSet<String>,
|
||||
publish_view_id_to_info_map: &HashMap<String, PublishedViewInfo>,
|
||||
) -> Result<PublishedView, AppError> {
|
||||
let mut unviewable = HashSet::new();
|
||||
for trash_view in folder.get_all_trash_sections() {
|
||||
|
|
@ -24,7 +24,7 @@ pub fn collab_folder_to_published_outline(
|
|||
root_view_id,
|
||||
folder,
|
||||
&unviewable,
|
||||
publish_view_ids,
|
||||
publish_view_id_to_info_map,
|
||||
0,
|
||||
max_depth,
|
||||
)
|
||||
|
|
@ -39,7 +39,7 @@ fn to_publish_view(
|
|||
view_id: &str,
|
||||
folder: &Folder,
|
||||
unviewable: &HashSet<String>,
|
||||
publish_view_ids: &HashSet<String>,
|
||||
publish_view_id_to_info_map: &HashMap<String, PublishedViewInfo>,
|
||||
depth: u32,
|
||||
max_depth: u32,
|
||||
) -> Option<PublishedView> {
|
||||
|
|
@ -65,6 +65,8 @@ fn to_publish_view(
|
|||
serde_json::Value::Null
|
||||
})
|
||||
});
|
||||
// If pruned_view is not empty, then one or more of the children is published.
|
||||
// Hence, this view should be included in the published outline, even if it is not published itself.
|
||||
let pruned_view: Vec<PublishedView> = view
|
||||
.children
|
||||
.iter()
|
||||
|
|
@ -74,13 +76,13 @@ fn to_publish_view(
|
|||
&child_view_id.id,
|
||||
folder,
|
||||
unviewable,
|
||||
publish_view_ids,
|
||||
publish_view_id_to_info_map,
|
||||
depth + 1,
|
||||
max_depth,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let is_published = publish_view_ids.contains(view_id);
|
||||
let is_published = publish_view_id_to_info_map.contains_key(view_id);
|
||||
if parent_view_id.is_empty() || is_published || !pruned_view.is_empty() {
|
||||
Some(PublishedView {
|
||||
view_id: view.id.clone(),
|
||||
|
|
@ -93,6 +95,7 @@ fn to_publish_view(
|
|||
layout: to_dto_view_layout(&view.layout),
|
||||
extra,
|
||||
children: pruned_view,
|
||||
info: publish_view_id_to_info_map.get(view_id).cloned(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
Loading…
Reference in New Issue