feat: batch unpublish

This commit is contained in:
Zack Fu Zi Xiang 2024-06-20 12:05:12 +08:00
parent 31f5c786a6
commit b525e333f0
No known key found for this signature in database
11 changed files with 96 additions and 106 deletions

View file

@ -1,15 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "\n DELETE FROM af_published_collab\n WHERE workspace_id = $1 AND view_id = $2\n ",
"query": "\n DELETE FROM af_published_collab\n WHERE workspace_id = $1\n AND view_id = ANY($2)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid"
"UuidArray"
]
},
"nullable": []
},
"hash": "cb7c6555f1c837748cf0c7706000b28026c3dcdb7305f8c3a49082e1067f1fd8"
"hash": "02eab22805a4cba99dc7fc554f63f6a16f89a5160d1095e1906985b9ec2123ec"
}

View file

@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT COUNT(*)\n FROM af_published_collab\n WHERE workspace_id = $1\n AND view_id = ANY($2)\n AND published_by = (SELECT uid FROM af_user WHERE uuid = $3)\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Uuid",
"UuidArray",
"Uuid"
]
},
"nullable": [
null
]
},
"hash": "87628d6739441a22229d08832d09cbf4598c36204a6885b2e279c848cedcfa75"
}

View file

@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE af_published_collab\n SET blob = $1\n WHERE workspace_id = $2\n AND view_id = $3\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Bytea",
"Uuid",
"Uuid"
]
},
"nullable": []
},
"hash": "c51b2030045bd58b1b3ac2ed12c24fedd32b19b456f2a865860cad597903fa5b"
}

View file

@ -1,19 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO af_published_collab (workspace_id, view_id, doc_name, published_by, metadata)\n SELECT * FROM UNNEST(\n (SELECT array_agg((SELECT $1::uuid)) FROM generate_series(1, $6))::uuid[],\n $2::uuid[],\n $3::text[],\n (SELECT array_agg((SELECT uid FROM af_user WHERE uuid = $4)) FROM generate_series(1, $6))::bigint[],\n $5::jsonb[]\n )\n ON CONFLICT (workspace_id, view_id) DO UPDATE\n SET metadata = EXCLUDED.metadata\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"UuidArray",
"TextArray",
"Uuid",
"JsonbArray",
"Int4"
]
},
"nullable": []
},
"hash": "d979dc9b4db36e59e4eda6b9643c034e89a684d739333653bea51a402226076e"
}

View file

@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT EXISTS(\n SELECT 1\n FROM af_published_collab\n WHERE workspace_id = $1\n AND view_id = $2\n AND published_by = (SELECT uid FROM af_user WHERE uuid = $3)\n );\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Uuid"
]
},
"nullable": [
null
]
},
"hash": "dd6ff315461ec898e43bc4624b51b10ef73fd1f87f94ce4f2e9f32136a1b4f67"
}

View file

@ -0,0 +1,20 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO af_published_collab (workspace_id, view_id, doc_name, published_by, metadata, blob)\n SELECT * FROM UNNEST(\n (SELECT array_agg((SELECT $1::uuid)) FROM generate_series(1, $7))::uuid[],\n $2::uuid[],\n $3::text[],\n (SELECT array_agg((SELECT uid FROM af_user WHERE uuid = $4)) FROM generate_series(1, $7))::bigint[],\n $5::jsonb[],\n $6::bytea[]\n )\n ON CONFLICT (workspace_id, view_id) DO UPDATE\n SET metadata = EXCLUDED.metadata\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"UuidArray",
"TextArray",
"Uuid",
"JsonbArray",
"ByteaArray",
"Int4"
]
},
"nullable": []
},
"hash": "fa640accaba3655cd842ebc4838d65fcd003c6a645876f7aa8e677eaad59517c"
}

View file

@ -76,18 +76,16 @@ impl Client {
AppResponse::<()>::from_response(resp).await?.into_error()
}
pub async fn delete_published_collab(
pub async fn unpublish_collabs(
&self,
workspace_id: &str,
view_id: &uuid::Uuid,
view_ids: &[uuid::Uuid],
) -> Result<(), AppResponseError> {
let url = format!(
"{}/api/workspace/{}/publish/{}",
self.base_url, workspace_id, view_id
);
let url = format!("{}/api/workspace/{}/publish", self.base_url, workspace_id);
let resp = self
.http_client_with_auth(Method::DELETE, &url)
.await?
.json(view_ids)
.send()
.await?;
AppResponse::<()>::from_response(resp).await?.into_error()

View file

@ -144,30 +144,31 @@ pub async fn select_user_is_workspace_owner(
Ok(exists.unwrap_or(false))
}
pub async fn select_user_is_collab_publisher(
pub async fn select_user_is_collab_publisher_for_all_views(
pg_pool: &PgPool,
user_uuid: &Uuid,
workspace_uuid: &Uuid,
view_id: &Uuid,
view_ids: &[Uuid],
) -> Result<bool, AppError> {
let exists = sqlx::query_scalar!(
let count = sqlx::query_scalar!(
r#"
SELECT EXISTS(
SELECT 1
FROM af_published_collab
WHERE workspace_id = $1
AND view_id = $2
AND published_by = (SELECT uid FROM af_user WHERE uuid = $3)
);
SELECT COUNT(*)
FROM af_published_collab
WHERE workspace_id = $1
AND view_id = ANY($2)
AND published_by = (SELECT uid FROM af_user WHERE uuid = $3)
"#,
workspace_uuid,
view_id,
view_ids,
user_uuid,
)
.fetch_one(pg_pool)
.await?;
Ok(exists.unwrap_or(false))
match count {
Some(c) => Ok(c == view_ids.len() as i64),
None => Ok(false),
}
}
#[inline]
@ -963,27 +964,28 @@ pub async fn select_publish_collab_meta<'a, E: Executor<'a, Database = Postgres>
}
#[inline]
pub async fn delete_published_collab<'a, E: Executor<'a, Database = Postgres>>(
pub async fn delete_published_collabs<'a, E: Executor<'a, Database = Postgres>>(
executor: E,
workspace_id: &Uuid,
view_id: &Uuid,
view_ids: &[Uuid],
) -> Result<(), AppError> {
let res = sqlx::query!(
r#"
DELETE FROM af_published_collab
WHERE workspace_id = $1 AND view_id = $2
WHERE workspace_id = $1
AND view_id = ANY($2)
"#,
workspace_id,
view_id,
view_ids,
)
.execute(executor)
.await?;
if res.rows_affected() != 1 {
if res.rows_affected() != view_ids.len() as u64 {
tracing::error!(
"Failed to delete published collab, workspace_id: {}, view_id: {}, rows_affected: {}",
"Failed to delete published collabs, workspace_id: {}, view_ids: {:?}, rows_affected: {}",
workspace_id,
view_id,
view_ids,
res.rows_affected()
);
}

View file

@ -148,11 +148,8 @@ pub fn workspace_scope() -> Scope {
)
.service(
web::resource("/{workspace_id}/publish")
.route(web::post().to(post_publish_collab_handler))
)
.service(
web::resource("/{workspace_id}/publish/{view_id}")
.route(web::delete().to(delete_publish_collab_handler))
.route(web::post().to(post_publish_collabs_handler))
.route(web::delete().to(delete_published_collabs_handler))
)
.service(
web::resource("/{workspace_id}/collab/{object_id}/member/list")
@ -1003,7 +1000,7 @@ async fn get_published_collab_info_handler(
Ok(Json(AppResponse::Ok().with_data(collab_data)))
}
async fn post_publish_collab_handler(
async fn post_publish_collabs_handler(
workspace_id: web::Path<Uuid>,
user_uuid: UserUuid,
mut payload: Payload,
@ -1015,7 +1012,6 @@ async fn post_publish_collab_handler(
let mut accumulator = Vec::<PublishCollabItem<serde_json::Value, Vec<u8>>>::new();
while let Some(item) = payload.try_next().await? {
println!("Publishing collab item: {:#?}", item);
let item_len = item.len();
let mut cursor = Cursor::new(item);
@ -1044,21 +1040,29 @@ async fn post_publish_collab_handler(
);
}
if accumulator.is_empty() {
return Ok(Json(AppResponse::Ok()));
}
biz::workspace::ops::publish_collabs(&state.pg_pool, &workspace_id, &user_uuid, &accumulator)
.await?;
Ok(Json(AppResponse::Ok()))
}
async fn delete_publish_collab_handler(
path_param: web::Path<(Uuid, Uuid)>,
async fn delete_published_collabs_handler(
workspace_id: web::Path<Uuid>,
user_uuid: UserUuid,
state: Data<AppState>,
view_ids: Json<Vec<Uuid>>,
) -> Result<Json<AppResponse<()>>> {
let (workspace_id, view_id) = path_param.into_inner();
let workspace_id = workspace_id.into_inner();
let view_ids = view_ids.into_inner();
if view_ids.is_empty() {
return Ok(Json(AppResponse::Ok()));
}
biz::workspace::ops::delete_published_workspace_collab(
&state.pg_pool,
&workspace_id,
&view_id,
&view_ids,
&user_uuid,
)
.await?;

View file

@ -19,11 +19,11 @@ use database::pg_row::{AFWorkspaceMemberRow, AFWorkspaceRow};
use database::user::select_uid_from_email;
use database::workspace::{
change_workspace_icon, delete_from_workspace, delete_published_collab, delete_workspace_members,
change_workspace_icon, delete_from_workspace, delete_published_collabs, delete_workspace_members,
get_invitation_by_id, insert_or_replace_publish_collab_metas, insert_user_workspace,
insert_workspace_invitation, rename_workspace, select_all_user_workspaces,
select_publish_collab_meta, select_published_collab_blob, select_published_collab_info,
select_user_is_collab_publisher, select_user_is_workspace_owner, select_workspace,
select_user_is_collab_publisher_for_all_views, select_user_is_workspace_owner, select_workspace,
select_workspace_invitations_for_user, select_workspace_member, select_workspace_member_list,
select_workspace_publish_namespace, select_workspace_publish_namespace_exists,
select_workspace_settings, select_workspace_total_collab_bytes, update_updated_at_of_workspace,
@ -184,11 +184,11 @@ pub async fn get_published_collab_info(
pub async fn delete_published_workspace_collab(
pg_pool: &PgPool,
workspace_id: &Uuid,
view_id: &Uuid,
view_ids: &[Uuid],
user_uuid: &Uuid,
) -> Result<(), AppError> {
check_workspace_owner_or_publisher(pg_pool, user_uuid, workspace_id, view_id).await?;
delete_published_collab(pg_pool, workspace_id, view_id).await?;
check_workspace_owner_or_publisher(pg_pool, user_uuid, workspace_id, view_ids).await?;
delete_published_collabs(pg_pool, workspace_id, view_ids).await?;
Ok(())
}
@ -573,12 +573,13 @@ async fn check_workspace_owner_or_publisher(
pg_pool: &PgPool,
user_uuid: &Uuid,
workspace_id: &Uuid,
view_id: &Uuid,
view_id: &[Uuid],
) -> Result<(), AppError> {
let is_owner = select_user_is_workspace_owner(pg_pool, user_uuid, workspace_id).await?;
if !is_owner {
let is_publisher =
select_user_is_collab_publisher(pg_pool, user_uuid, workspace_id, view_id).await?;
select_user_is_collab_publisher_for_all_views(pg_pool, user_uuid, workspace_id, view_id)
.await?;
if !is_publisher {
return Err(AppError::UserUnAuthorized(
"User is not the owner of the workspace or the publisher of the document".to_string(),

View file

@ -129,7 +129,7 @@ async fn test_publish_doc() {
assert_eq!(blob, "yrs_encoded_data_1");
}
c.delete_published_collab(&workspace_id, &view_id_1)
c.unpublish_collabs(&workspace_id, &[view_id_1])
.await
.unwrap();