feat: patching of publish name

This commit is contained in:
Zack Fu Zi Xiang 2024-10-24 22:06:52 +08:00
parent e738508d79
commit b775aa9d4c
No known key found for this signature in database
6 changed files with 194 additions and 11 deletions

View File

@ -3,7 +3,8 @@ use client_api_entity::workspace_dto::PublishInfoView;
use client_api_entity::{workspace_dto::PublishedDuplicate, PublishInfo, UpdatePublishNamespace};
use client_api_entity::{
CreateGlobalCommentParams, CreateReactionParams, DeleteGlobalCommentParams, DeleteReactionParams,
GetReactionQueryParams, GlobalComments, PublishInfoMeta, Reactions, UpdateDefaultPublishView,
GetReactionQueryParams, GlobalComments, PatchPublishedCollab, PublishInfoMeta, Reactions,
UpdateDefaultPublishView,
};
use reqwest::Method;
use shared_entity::response::{AppResponse, AppResponseError};
@ -75,6 +76,22 @@ impl Client {
.into_data()
}
pub async fn patch_published_collabs(
&self,
workspace_id: &str,
patches: &[PatchPublishedCollab],
) -> Result<(), AppResponseError> {
let url = format!("{}/api/workspace/{}/publish", self.base_url, workspace_id);
let resp = self
.http_client_with_auth(Method::PATCH, &url)
.await?
.json(patches)
.send()
.await?;
log_request_id(&resp);
AppResponse::<()>::from_response(resp).await?.into_error()
}
pub async fn unpublish_collabs(
&self,
workspace_id: &str,
@ -251,7 +268,7 @@ impl Client {
&self,
view_id: &uuid::Uuid,
) -> Result<PublishInfo, AppResponseError> {
let url = format!("{}/api/workspace/published-info/{}", self.base_url, view_id,);
let url = format!("{}/api/workspace/published-info/{}", self.base_url, view_id);
let resp = self.cloud_client.get(&url).send().await?;
AppResponse::<PublishInfo>::from_response(resp)

View File

@ -1133,6 +1133,12 @@ pub struct PublishCollabItem<Meta, Data> {
pub data: Data,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct PatchPublishedCollab {
pub view_id: Uuid,
pub publish_name: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GlobalComments {
pub comments: Vec<GlobalComment>,

View File

@ -1,5 +1,7 @@
use app_error::AppError;
use database_entity::dto::{PublishCollabItem, PublishCollabKey, PublishInfo};
use database_entity::dto::{
PatchPublishedCollab, PublishCollabItem, PublishCollabKey, PublishInfo,
};
use sqlx::{Executor, PgPool, Postgres};
use uuid::Uuid;
@ -238,6 +240,46 @@ pub async fn delete_published_collabs<'a, E: Executor<'a, Database = Postgres>>(
Ok(())
}
#[inline]
pub async fn update_published_collabs(
txn: &mut sqlx::Transaction<'_, Postgres>,
workspace_id: &Uuid,
patches: &[PatchPublishedCollab],
) -> Result<(), AppError> {
for patch in patches {
let new_publish_name = match &patch.publish_name {
Some(new_publish_name) => new_publish_name,
None => continue,
};
let res = sqlx::query!(
r#"
UPDATE af_published_collab
SET publish_name = $1
WHERE workspace_id = $2
AND view_id = $3
"#,
patch.publish_name,
workspace_id,
patch.view_id,
)
.execute(txn.as_mut())
.await?;
if res.rows_affected() != 1 {
tracing::error!(
"Failed to update published collab publish name, workspace_id: {}, view_id: {}, new_publish_name: {}, rows_affected: {}",
workspace_id,
patch.view_id,
new_publish_name,
res.rows_affected()
);
}
}
Ok(())
}
#[inline]
pub async fn select_published_metadata_for_view_id(
pg_pool: &PgPool,

View File

@ -204,7 +204,8 @@ pub fn workspace_scope() -> Scope {
.service(
web::resource("/{workspace_id}/publish")
.route(web::post().to(post_publish_collabs_handler))
.route(web::delete().to(delete_published_collabs_handler)),
.route(web::delete().to(delete_published_collabs_handler))
.route(web::patch().to(patch_published_collabs_handler)),
)
.service(
web::resource("/{workspace_id}/folder").route(web::get().to(get_workspace_folder_handler)),
@ -1440,6 +1441,23 @@ async fn post_publish_collabs_handler(
Ok(Json(AppResponse::Ok()))
}
async fn patch_published_collabs_handler(
workspace_id: web::Path<Uuid>,
user_uuid: UserUuid,
state: Data<AppState>,
patches: Json<Vec<PatchPublishedCollab>>,
) -> Result<Json<AppResponse<()>>> {
let workspace_id = workspace_id.into_inner();
if patches.is_empty() {
return Err(AppError::InvalidRequest("No patches provided".to_string()).into());
}
state
.published_collab_store
.patch_collabs(&workspace_id, &user_uuid, &patches)
.await?;
Ok(Json(AppResponse::Ok()))
}
async fn delete_published_collabs_handler(
workspace_id: web::Path<Uuid>,
user_uuid: UserUuid,
@ -1449,11 +1467,11 @@ async fn delete_published_collabs_handler(
let workspace_id = workspace_id.into_inner();
let view_ids = view_ids.into_inner();
if view_ids.is_empty() {
return Ok(Json(AppResponse::Ok()));
return Err(AppError::InvalidRequest("No view_ids provided".to_string()).into());
}
state
.published_collab_store
.delete_collab(&workspace_id, &view_ids, &user_uuid)
.delete_collabs(&workspace_id, &view_ids, &user_uuid)
.await?;
Ok(Json(AppResponse::Ok()))
}

View File

@ -3,9 +3,11 @@ use database::{
collab::GetCollabOrigin,
publish::{
select_all_published_collab_info, select_default_published_view_id,
select_default_published_view_id_for_namespace, update_workspace_default_publish_view,
select_default_published_view_id_for_namespace, update_published_collabs,
update_workspace_default_publish_view,
},
};
use database_entity::dto::PatchPublishedCollab;
use std::sync::Arc;
use app_error::AppError;
@ -251,12 +253,19 @@ pub trait PublishedCollabStore: Sync + Send + 'static {
publish_name: &str,
) -> Result<Vec<u8>, AppError>;
async fn delete_collab(
async fn delete_collabs(
&self,
workspace_id: &Uuid,
view_ids: &[Uuid],
user_uuid: &Uuid,
) -> Result<(), AppError>;
async fn patch_collabs(
&self,
workspace_id: &Uuid,
user_uuid: &Uuid,
patches: &[PatchPublishedCollab],
) -> Result<(), AppError>;
}
pub struct PublishedCollabPostgresStore {
@ -351,7 +360,7 @@ impl PublishedCollabStore for PublishedCollabPostgresStore {
result
}
async fn delete_collab(
async fn delete_collabs(
&self,
workspace_id: &Uuid,
view_ids: &[Uuid],
@ -361,6 +370,15 @@ impl PublishedCollabStore for PublishedCollabPostgresStore {
delete_published_collabs(&self.pg_pool, workspace_id, view_ids).await?;
Ok(())
}
async fn patch_collabs(
&self,
workspace_id: &Uuid,
user_uuid: &Uuid,
patches: &[PatchPublishedCollab],
) -> Result<(), AppError> {
patch_collabs(&self.pg_pool, workspace_id, user_uuid, patches).await
}
}
pub struct PublishedCollabS3StoreWithPostgresFallback {
@ -519,7 +537,7 @@ impl PublishedCollabStore for PublishedCollabS3StoreWithPostgresFallback {
}
}
async fn delete_collab(
async fn delete_collabs(
&self,
workspace_id: &Uuid,
view_ids: &[Uuid],
@ -534,4 +552,36 @@ impl PublishedCollabStore for PublishedCollabS3StoreWithPostgresFallback {
delete_published_collabs(&self.pg_pool, workspace_id, view_ids).await?;
Ok(())
}
async fn patch_collabs(
&self,
workspace_id: &Uuid,
user_uuid: &Uuid,
patches: &[PatchPublishedCollab],
) -> Result<(), AppError> {
patch_collabs(&self.pg_pool, workspace_id, user_uuid, patches).await
}
}
async fn patch_collabs(
pg_pool: &PgPool,
workspace_id: &Uuid,
user_uuid: &Uuid,
patches: &[PatchPublishedCollab],
) -> Result<(), AppError> {
let view_ids = patches
.iter()
.map(|patch| patch.view_id)
.collect::<Vec<Uuid>>();
for patch in patches {
if let Some(new_publish_name) = patch.publish_name.as_deref() {
check_collab_publish_name(new_publish_name)?;
}
}
check_workspace_owner_or_publisher(pg_pool, user_uuid, workspace_id, &view_ids).await?;
let mut txn = pg_pool.begin().await?;
update_published_collabs(&mut txn, workspace_id, patches).await?;
txn.commit().await?;
Ok(())
}

View File

@ -2,7 +2,8 @@ use app_error::ErrorCode;
use appflowy_cloud::biz::collab::folder_view::collab_folder_to_folder_view;
use appflowy_cloud::biz::workspace::ops::collab_from_doc_state;
use client_api::entity::{
AFRole, GlobalComment, PublishCollabItem, PublishCollabMetadata, PublishInfoMeta,
AFRole, GlobalComment, PatchPublishedCollab, PublishCollabItem, PublishCollabMetadata,
PublishInfoMeta,
};
use client_api_test::TestClient;
use client_api_test::{generate_unique_registered_user_client, localhost_client};
@ -255,6 +256,55 @@ async fn test_publish_doc() {
.await
.unwrap();
{
let new_publish_name_1 = "new-publish-name-1".to_string();
// User change publish name
c.patch_published_collabs(
&workspace_id,
&[PatchPublishedCollab {
view_id: view_id_1,
publish_name: Some(new_publish_name_1.to_string()),
}],
)
.await
.unwrap();
// Guest now cannot access the collab using old publish name
let guest_client = localhost_client();
let err = guest_client
.get_published_collab::<MyCustomMetadata>(&my_namespace, publish_name_1)
.await
.err()
.unwrap();
assert_eq!(err.code, ErrorCode::RecordNotFound, "{:?}", err);
// Guest now access the collab using new publish name
let guest_client = localhost_client();
let _ = guest_client
.get_published_collab::<MyCustomMetadata>(&my_namespace, &new_publish_name_1)
.await
.unwrap();
// Switch back to old publish name
c.patch_published_collabs(
&workspace_id,
&[PatchPublishedCollab {
view_id: view_id_1,
publish_name: Some(publish_name_1.to_string()),
}],
)
.await
.unwrap();
// Guest can access the collab using the orginal publish name
let guest_client = localhost_client();
let _ = guest_client
.get_published_collab::<MyCustomMetadata>(&my_namespace, publish_name_1)
.await
.unwrap();
}
{
// Deleted collab should not be accessible
let guest_client = localhost_client();