feat: patching of publish name
This commit is contained in:
parent
e738508d79
commit
b775aa9d4c
|
|
@ -3,7 +3,8 @@ use client_api_entity::workspace_dto::PublishInfoView;
|
||||||
use client_api_entity::{workspace_dto::PublishedDuplicate, PublishInfo, UpdatePublishNamespace};
|
use client_api_entity::{workspace_dto::PublishedDuplicate, PublishInfo, UpdatePublishNamespace};
|
||||||
use client_api_entity::{
|
use client_api_entity::{
|
||||||
CreateGlobalCommentParams, CreateReactionParams, DeleteGlobalCommentParams, DeleteReactionParams,
|
CreateGlobalCommentParams, CreateReactionParams, DeleteGlobalCommentParams, DeleteReactionParams,
|
||||||
GetReactionQueryParams, GlobalComments, PublishInfoMeta, Reactions, UpdateDefaultPublishView,
|
GetReactionQueryParams, GlobalComments, PatchPublishedCollab, PublishInfoMeta, Reactions,
|
||||||
|
UpdateDefaultPublishView,
|
||||||
};
|
};
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
use shared_entity::response::{AppResponse, AppResponseError};
|
use shared_entity::response::{AppResponse, AppResponseError};
|
||||||
|
|
@ -75,6 +76,22 @@ impl Client {
|
||||||
.into_data()
|
.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(
|
pub async fn unpublish_collabs(
|
||||||
&self,
|
&self,
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
|
|
@ -251,7 +268,7 @@ impl Client {
|
||||||
&self,
|
&self,
|
||||||
view_id: &uuid::Uuid,
|
view_id: &uuid::Uuid,
|
||||||
) -> Result<PublishInfo, AppResponseError> {
|
) -> 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?;
|
let resp = self.cloud_client.get(&url).send().await?;
|
||||||
AppResponse::<PublishInfo>::from_response(resp)
|
AppResponse::<PublishInfo>::from_response(resp)
|
||||||
|
|
|
||||||
|
|
@ -1133,6 +1133,12 @@ pub struct PublishCollabItem<Meta, Data> {
|
||||||
pub data: Data,
|
pub data: Data,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct PatchPublishedCollab {
|
||||||
|
pub view_id: Uuid,
|
||||||
|
pub publish_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct GlobalComments {
|
pub struct GlobalComments {
|
||||||
pub comments: Vec<GlobalComment>,
|
pub comments: Vec<GlobalComment>,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use app_error::AppError;
|
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 sqlx::{Executor, PgPool, Postgres};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
|
@ -238,6 +240,46 @@ pub async fn delete_published_collabs<'a, E: Executor<'a, Database = Postgres>>(
|
||||||
Ok(())
|
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]
|
#[inline]
|
||||||
pub async fn select_published_metadata_for_view_id(
|
pub async fn select_published_metadata_for_view_id(
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
|
|
|
||||||
|
|
@ -204,7 +204,8 @@ pub fn workspace_scope() -> Scope {
|
||||||
.service(
|
.service(
|
||||||
web::resource("/{workspace_id}/publish")
|
web::resource("/{workspace_id}/publish")
|
||||||
.route(web::post().to(post_publish_collabs_handler))
|
.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(
|
.service(
|
||||||
web::resource("/{workspace_id}/folder").route(web::get().to(get_workspace_folder_handler)),
|
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()))
|
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(
|
async fn delete_published_collabs_handler(
|
||||||
workspace_id: web::Path<Uuid>,
|
workspace_id: web::Path<Uuid>,
|
||||||
user_uuid: UserUuid,
|
user_uuid: UserUuid,
|
||||||
|
|
@ -1449,11 +1467,11 @@ async fn delete_published_collabs_handler(
|
||||||
let workspace_id = workspace_id.into_inner();
|
let workspace_id = workspace_id.into_inner();
|
||||||
let view_ids = view_ids.into_inner();
|
let view_ids = view_ids.into_inner();
|
||||||
if view_ids.is_empty() {
|
if view_ids.is_empty() {
|
||||||
return Ok(Json(AppResponse::Ok()));
|
return Err(AppError::InvalidRequest("No view_ids provided".to_string()).into());
|
||||||
}
|
}
|
||||||
state
|
state
|
||||||
.published_collab_store
|
.published_collab_store
|
||||||
.delete_collab(&workspace_id, &view_ids, &user_uuid)
|
.delete_collabs(&workspace_id, &view_ids, &user_uuid)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(Json(AppResponse::Ok()))
|
Ok(Json(AppResponse::Ok()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,11 @@ use database::{
|
||||||
collab::GetCollabOrigin,
|
collab::GetCollabOrigin,
|
||||||
publish::{
|
publish::{
|
||||||
select_all_published_collab_info, select_default_published_view_id,
|
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 std::sync::Arc;
|
||||||
|
|
||||||
use app_error::AppError;
|
use app_error::AppError;
|
||||||
|
|
@ -251,12 +253,19 @@ pub trait PublishedCollabStore: Sync + Send + 'static {
|
||||||
publish_name: &str,
|
publish_name: &str,
|
||||||
) -> Result<Vec<u8>, AppError>;
|
) -> Result<Vec<u8>, AppError>;
|
||||||
|
|
||||||
async fn delete_collab(
|
async fn delete_collabs(
|
||||||
&self,
|
&self,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
view_ids: &[Uuid],
|
view_ids: &[Uuid],
|
||||||
user_uuid: &Uuid,
|
user_uuid: &Uuid,
|
||||||
) -> Result<(), AppError>;
|
) -> Result<(), AppError>;
|
||||||
|
|
||||||
|
async fn patch_collabs(
|
||||||
|
&self,
|
||||||
|
workspace_id: &Uuid,
|
||||||
|
user_uuid: &Uuid,
|
||||||
|
patches: &[PatchPublishedCollab],
|
||||||
|
) -> Result<(), AppError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PublishedCollabPostgresStore {
|
pub struct PublishedCollabPostgresStore {
|
||||||
|
|
@ -351,7 +360,7 @@ impl PublishedCollabStore for PublishedCollabPostgresStore {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_collab(
|
async fn delete_collabs(
|
||||||
&self,
|
&self,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
view_ids: &[Uuid],
|
view_ids: &[Uuid],
|
||||||
|
|
@ -361,6 +370,15 @@ impl PublishedCollabStore for PublishedCollabPostgresStore {
|
||||||
delete_published_collabs(&self.pg_pool, workspace_id, view_ids).await?;
|
delete_published_collabs(&self.pg_pool, workspace_id, view_ids).await?;
|
||||||
Ok(())
|
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 {
|
pub struct PublishedCollabS3StoreWithPostgresFallback {
|
||||||
|
|
@ -519,7 +537,7 @@ impl PublishedCollabStore for PublishedCollabS3StoreWithPostgresFallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_collab(
|
async fn delete_collabs(
|
||||||
&self,
|
&self,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
view_ids: &[Uuid],
|
view_ids: &[Uuid],
|
||||||
|
|
@ -534,4 +552,36 @@ impl PublishedCollabStore for PublishedCollabS3StoreWithPostgresFallback {
|
||||||
delete_published_collabs(&self.pg_pool, workspace_id, view_ids).await?;
|
delete_published_collabs(&self.pg_pool, workspace_id, view_ids).await?;
|
||||||
Ok(())
|
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(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ use app_error::ErrorCode;
|
||||||
use appflowy_cloud::biz::collab::folder_view::collab_folder_to_folder_view;
|
use appflowy_cloud::biz::collab::folder_view::collab_folder_to_folder_view;
|
||||||
use appflowy_cloud::biz::workspace::ops::collab_from_doc_state;
|
use appflowy_cloud::biz::workspace::ops::collab_from_doc_state;
|
||||||
use client_api::entity::{
|
use client_api::entity::{
|
||||||
AFRole, GlobalComment, PublishCollabItem, PublishCollabMetadata, PublishInfoMeta,
|
AFRole, GlobalComment, PatchPublishedCollab, PublishCollabItem, PublishCollabMetadata,
|
||||||
|
PublishInfoMeta,
|
||||||
};
|
};
|
||||||
use client_api_test::TestClient;
|
use client_api_test::TestClient;
|
||||||
use client_api_test::{generate_unique_registered_user_client, localhost_client};
|
use client_api_test::{generate_unique_registered_user_client, localhost_client};
|
||||||
|
|
@ -255,6 +256,55 @@ async fn test_publish_doc() {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.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
|
// Deleted collab should not be accessible
|
||||||
let guest_client = localhost_client();
|
let guest_client = localhost_client();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue