feat: batch unpublish
This commit is contained in:
parent
31f5c786a6
commit
b525e333f0
|
|
@ -1,15 +1,15 @@
|
||||||
{
|
{
|
||||||
"db_name": "PostgreSQL",
|
"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": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"Left": [
|
"Left": [
|
||||||
"Uuid",
|
"Uuid",
|
||||||
"Uuid"
|
"UuidArray"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"nullable": []
|
"nullable": []
|
||||||
},
|
},
|
||||||
"hash": "cb7c6555f1c837748cf0c7706000b28026c3dcdb7305f8c3a49082e1067f1fd8"
|
"hash": "02eab22805a4cba99dc7fc554f63f6a16f89a5160d1095e1906985b9ec2123ec"
|
||||||
}
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -76,18 +76,16 @@ impl Client {
|
||||||
AppResponse::<()>::from_response(resp).await?.into_error()
|
AppResponse::<()>::from_response(resp).await?.into_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_published_collab(
|
pub async fn unpublish_collabs(
|
||||||
&self,
|
&self,
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
view_id: &uuid::Uuid,
|
view_ids: &[uuid::Uuid],
|
||||||
) -> Result<(), AppResponseError> {
|
) -> Result<(), AppResponseError> {
|
||||||
let url = format!(
|
let url = format!("{}/api/workspace/{}/publish", self.base_url, workspace_id);
|
||||||
"{}/api/workspace/{}/publish/{}",
|
|
||||||
self.base_url, workspace_id, view_id
|
|
||||||
);
|
|
||||||
let resp = self
|
let resp = self
|
||||||
.http_client_with_auth(Method::DELETE, &url)
|
.http_client_with_auth(Method::DELETE, &url)
|
||||||
.await?
|
.await?
|
||||||
|
.json(view_ids)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
AppResponse::<()>::from_response(resp).await?.into_error()
|
AppResponse::<()>::from_response(resp).await?.into_error()
|
||||||
|
|
|
||||||
|
|
@ -144,30 +144,31 @@ pub async fn select_user_is_workspace_owner(
|
||||||
Ok(exists.unwrap_or(false))
|
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,
|
pg_pool: &PgPool,
|
||||||
user_uuid: &Uuid,
|
user_uuid: &Uuid,
|
||||||
workspace_uuid: &Uuid,
|
workspace_uuid: &Uuid,
|
||||||
view_id: &Uuid,
|
view_ids: &[Uuid],
|
||||||
) -> Result<bool, AppError> {
|
) -> Result<bool, AppError> {
|
||||||
let exists = sqlx::query_scalar!(
|
let count = sqlx::query_scalar!(
|
||||||
r#"
|
r#"
|
||||||
SELECT EXISTS(
|
SELECT COUNT(*)
|
||||||
SELECT 1
|
FROM af_published_collab
|
||||||
FROM af_published_collab
|
WHERE workspace_id = $1
|
||||||
WHERE workspace_id = $1
|
AND view_id = ANY($2)
|
||||||
AND view_id = $2
|
AND published_by = (SELECT uid FROM af_user WHERE uuid = $3)
|
||||||
AND published_by = (SELECT uid FROM af_user WHERE uuid = $3)
|
|
||||||
);
|
|
||||||
"#,
|
"#,
|
||||||
workspace_uuid,
|
workspace_uuid,
|
||||||
view_id,
|
view_ids,
|
||||||
user_uuid,
|
user_uuid,
|
||||||
)
|
)
|
||||||
.fetch_one(pg_pool)
|
.fetch_one(pg_pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(exists.unwrap_or(false))
|
match count {
|
||||||
|
Some(c) => Ok(c == view_ids.len() as i64),
|
||||||
|
None => Ok(false),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -963,27 +964,28 @@ pub async fn select_publish_collab_meta<'a, E: Executor<'a, Database = Postgres>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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,
|
executor: E,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
view_id: &Uuid,
|
view_ids: &[Uuid],
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
let res = sqlx::query!(
|
let res = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
DELETE FROM af_published_collab
|
DELETE FROM af_published_collab
|
||||||
WHERE workspace_id = $1 AND view_id = $2
|
WHERE workspace_id = $1
|
||||||
|
AND view_id = ANY($2)
|
||||||
"#,
|
"#,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
view_id,
|
view_ids,
|
||||||
)
|
)
|
||||||
.execute(executor)
|
.execute(executor)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if res.rows_affected() != 1 {
|
if res.rows_affected() != view_ids.len() as u64 {
|
||||||
tracing::error!(
|
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,
|
workspace_id,
|
||||||
view_id,
|
view_ids,
|
||||||
res.rows_affected()
|
res.rows_affected()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,11 +148,8 @@ pub fn workspace_scope() -> Scope {
|
||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/{workspace_id}/publish")
|
web::resource("/{workspace_id}/publish")
|
||||||
.route(web::post().to(post_publish_collab_handler))
|
.route(web::post().to(post_publish_collabs_handler))
|
||||||
)
|
.route(web::delete().to(delete_published_collabs_handler))
|
||||||
.service(
|
|
||||||
web::resource("/{workspace_id}/publish/{view_id}")
|
|
||||||
.route(web::delete().to(delete_publish_collab_handler))
|
|
||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/{workspace_id}/collab/{object_id}/member/list")
|
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)))
|
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>,
|
workspace_id: web::Path<Uuid>,
|
||||||
user_uuid: UserUuid,
|
user_uuid: UserUuid,
|
||||||
mut payload: Payload,
|
mut payload: Payload,
|
||||||
|
|
@ -1015,7 +1012,6 @@ async fn post_publish_collab_handler(
|
||||||
let mut accumulator = Vec::<PublishCollabItem<serde_json::Value, Vec<u8>>>::new();
|
let mut accumulator = Vec::<PublishCollabItem<serde_json::Value, Vec<u8>>>::new();
|
||||||
|
|
||||||
while let Some(item) = payload.try_next().await? {
|
while let Some(item) = payload.try_next().await? {
|
||||||
println!("Publishing collab item: {:#?}", item);
|
|
||||||
let item_len = item.len();
|
let item_len = item.len();
|
||||||
|
|
||||||
let mut cursor = Cursor::new(item);
|
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)
|
biz::workspace::ops::publish_collabs(&state.pg_pool, &workspace_id, &user_uuid, &accumulator)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(Json(AppResponse::Ok()))
|
Ok(Json(AppResponse::Ok()))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_publish_collab_handler(
|
async fn delete_published_collabs_handler(
|
||||||
path_param: web::Path<(Uuid, Uuid)>,
|
workspace_id: web::Path<Uuid>,
|
||||||
user_uuid: UserUuid,
|
user_uuid: UserUuid,
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
|
view_ids: Json<Vec<Uuid>>,
|
||||||
) -> Result<Json<AppResponse<()>>> {
|
) -> 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(
|
biz::workspace::ops::delete_published_workspace_collab(
|
||||||
&state.pg_pool,
|
&state.pg_pool,
|
||||||
&workspace_id,
|
&workspace_id,
|
||||||
&view_id,
|
&view_ids,
|
||||||
&user_uuid,
|
&user_uuid,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@ use database::pg_row::{AFWorkspaceMemberRow, AFWorkspaceRow};
|
||||||
|
|
||||||
use database::user::select_uid_from_email;
|
use database::user::select_uid_from_email;
|
||||||
use database::workspace::{
|
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,
|
get_invitation_by_id, insert_or_replace_publish_collab_metas, insert_user_workspace,
|
||||||
insert_workspace_invitation, rename_workspace, select_all_user_workspaces,
|
insert_workspace_invitation, rename_workspace, select_all_user_workspaces,
|
||||||
select_publish_collab_meta, select_published_collab_blob, select_published_collab_info,
|
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_invitations_for_user, select_workspace_member, select_workspace_member_list,
|
||||||
select_workspace_publish_namespace, select_workspace_publish_namespace_exists,
|
select_workspace_publish_namespace, select_workspace_publish_namespace_exists,
|
||||||
select_workspace_settings, select_workspace_total_collab_bytes, update_updated_at_of_workspace,
|
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(
|
pub async fn delete_published_workspace_collab(
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
view_id: &Uuid,
|
view_ids: &[Uuid],
|
||||||
user_uuid: &Uuid,
|
user_uuid: &Uuid,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
check_workspace_owner_or_publisher(pg_pool, user_uuid, workspace_id, view_id).await?;
|
check_workspace_owner_or_publisher(pg_pool, user_uuid, workspace_id, view_ids).await?;
|
||||||
delete_published_collab(pg_pool, workspace_id, view_id).await?;
|
delete_published_collabs(pg_pool, workspace_id, view_ids).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -573,12 +573,13 @@ async fn check_workspace_owner_or_publisher(
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
user_uuid: &Uuid,
|
user_uuid: &Uuid,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
view_id: &Uuid,
|
view_id: &[Uuid],
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
let is_owner = select_user_is_workspace_owner(pg_pool, user_uuid, workspace_id).await?;
|
let is_owner = select_user_is_workspace_owner(pg_pool, user_uuid, workspace_id).await?;
|
||||||
if !is_owner {
|
if !is_owner {
|
||||||
let is_publisher =
|
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 {
|
if !is_publisher {
|
||||||
return Err(AppError::UserUnAuthorized(
|
return Err(AppError::UserUnAuthorized(
|
||||||
"User is not the owner of the workspace or the publisher of the document".to_string(),
|
"User is not the owner of the workspace or the publisher of the document".to_string(),
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ async fn test_publish_doc() {
|
||||||
assert_eq!(blob, "yrs_encoded_data_1");
|
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
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue