diff --git a/.sqlx/query-ee58ab18f882ed89f3506d3e28eef43c32e09e6c545a08f35fb5169e84553af6.json b/.sqlx/query-93f6a59171d7cd08d321c777f24255621280fbcf6a2c009afd601eac16c9ba3a.json similarity index 68% rename from .sqlx/query-ee58ab18f882ed89f3506d3e28eef43c32e09e6c545a08f35fb5169e84553af6.json rename to .sqlx/query-93f6a59171d7cd08d321c777f24255621280fbcf6a2c009afd601eac16c9ba3a.json index 57fd20158..189c03562 100644 --- a/.sqlx/query-ee58ab18f882ed89f3506d3e28eef43c32e09e6c545a08f35fb5169e84553af6.json +++ b/.sqlx/query-93f6a59171d7cd08d321c777f24255621280fbcf6a2c009afd601eac16c9ba3a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT view_id\n FROM af_published_collab\n WHERE workspace_id = $1\n ", + "query": "\n SELECT view_id\n FROM af_published_collab\n WHERE workspace_id = $1\n AND unpublished_at IS NULL\n ", "describe": { "columns": [ { @@ -18,5 +18,5 @@ false ] }, - "hash": "ee58ab18f882ed89f3506d3e28eef43c32e09e6c545a08f35fb5169e84553af6" + "hash": "93f6a59171d7cd08d321c777f24255621280fbcf6a2c009afd601eac16c9ba3a" } diff --git a/libs/client-api/src/http_view.rs b/libs/client-api/src/http_view.rs index ad1cfc8d2..d6e08a228 100644 --- a/libs/client-api/src/http_view.rs +++ b/libs/client-api/src/http_view.rs @@ -188,6 +188,24 @@ impl Client { AppResponse::<()>::from_response(resp).await?.into_error() } + pub async fn unpublish_page( + &self, + workspace_id: Uuid, + view_id: &str, + ) -> Result<(), AppResponseError> { + let url = format!( + "{}/api/workspace/{}/page-view/{}/unpublish", + self.base_url, workspace_id, view_id + ); + let resp = self + .http_client_with_auth(Method::POST, &url) + .await? + .json(&json!({})) + .send() + .await?; + AppResponse::<()>::from_response(resp).await?.into_error() + } + pub async fn create_space( &self, workspace_id: Uuid, diff --git a/libs/database/src/publish.rs b/libs/database/src/publish.rs index 840192b02..4843f9a3d 100644 --- a/libs/database/src/publish.rs +++ b/libs/database/src/publish.rs @@ -669,6 +669,7 @@ pub async fn select_published_view_ids_for_workspace<'a, E: Executor<'a, Databas SELECT view_id FROM af_published_collab WHERE workspace_id = $1 + AND unpublished_at IS NULL "#, workspace_id, ) diff --git a/src/api/workspace.rs b/src/api/workspace.rs index 25293e709..923515fe5 100644 --- a/src/api/workspace.rs +++ b/src/api/workspace.rs @@ -14,7 +14,7 @@ use crate::biz::workspace::ops::{ use crate::biz::workspace::page_view::{ create_page, create_space, delete_all_pages_from_trash, delete_trash, get_page_view_collab, move_page, move_page_to_trash, publish_page, restore_all_pages_from_trash, - restore_page_from_trash, update_page, update_page_collab_data, update_space, + restore_page_from_trash, unpublish_page, update_page, update_page_collab_data, update_space, }; use crate::biz::workspace::publish::get_workspace_default_publish_view_info_meta; use crate::biz::workspace::quick_note::{ @@ -193,6 +193,10 @@ pub fn workspace_scope() -> Scope { web::resource("/{workspace_id}/page-view/{view_id}/publish") .route(web::post().to(publish_page_handler)), ) + .service( + web::resource("/{workspace_id}/page-view/{view_id}/unpublish") + .route(web::post().to(unpublish_page_handler)), + ) .service( web::resource("/{workspace_id}/batch/collab") .route(web::post().to(batch_create_collab_handler)), @@ -1288,6 +1292,10 @@ async fn publish_page_handler( .get_user_uid(&user_uuid) .await .map_err(AppResponseError::from)?; + state + .workspace_access_control + .enforce_role(&uid, &workspace_id.to_string(), AFRole::Member) + .await?; let PublishPageParams { publish_name, visible_database_view_ids, @@ -1307,6 +1315,31 @@ async fn publish_page_handler( Ok(Json(AppResponse::Ok())) } +async fn unpublish_page_handler( + user_uuid: UserUuid, + path: web::Path<(Uuid, Uuid)>, + state: Data, +) -> Result>> { + let (workspace_uuid, view_uuid) = path.into_inner(); + let uid = state + .user_cache + .get_user_uid(&user_uuid) + .await + .map_err(AppResponseError::from)?; + state + .workspace_access_control + .enforce_role(&uid, &workspace_uuid.to_string(), AFRole::Member) + .await?; + unpublish_page( + state.published_collab_store.as_ref(), + workspace_uuid, + *user_uuid, + view_uuid, + ) + .await?; + Ok(Json(AppResponse::Ok())) +} + async fn update_page_view_handler( user_uuid: UserUuid, path: web::Path<(Uuid, String)>, diff --git a/src/biz/workspace/page_view.rs b/src/biz/workspace/page_view.rs index 577437428..3d6833865 100644 --- a/src/biz/workspace/page_view.rs +++ b/src/biz/workspace/page_view.rs @@ -1254,6 +1254,17 @@ async fn generate_publish_data_for_database( Ok(serde_json::ser::to_vec(&data)?) } +pub async fn unpublish_page( + publish_collab_store: &dyn PublishedCollabStore, + workspace_id: Uuid, + user_uuid: Uuid, + view_id: Uuid, +) -> Result<(), AppError> { + publish_collab_store + .unpublish_collabs(&workspace_id, &[view_id], &user_uuid) + .await +} + pub async fn get_page_view_collab( pg_pool: &PgPool, collab_access_control_storage: &CollabAccessControlStorage, diff --git a/tests/workspace/page_view.rs b/tests/workspace/page_view.rs index 468927101..c14220f44 100644 --- a/tests/workspace/page_view.rs +++ b/tests/workspace/page_view.rs @@ -758,11 +758,12 @@ async fn publish_page() { .view_id .clone(); let page_to_be_published = vec![database_page_id, document_page_id]; + let workspace_uuid = Uuid::parse_str(&workspace_id).unwrap(); for view_id in &page_to_be_published { web_client .api_client .publish_page( - Uuid::parse_str(&workspace_id).unwrap(), + workspace_uuid, view_id, &PublishPageParams { publish_name: None, @@ -794,4 +795,17 @@ async fn publish_page() { for view_id in &page_to_be_published { assert!(published_view_ids.contains(view_id)); } + for view_id in &page_to_be_published { + web_client + .api_client + .unpublish_page(workspace_uuid, view_id) + .await + .unwrap(); + } + let published_view = web_client + .api_client + .get_published_outline(&publish_namespace) + .await + .unwrap(); + assert_eq!(published_view.children.len(), 0); }