feat: use view id
This commit is contained in:
parent
31b3275d8d
commit
18e9d0abae
|
|
@ -1,7 +1,10 @@
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use database_entity::dto::UpdatePublishNamespace;
|
use database_entity::dto::UpdatePublishNamespace;
|
||||||
use reqwest::{Body, Method};
|
use reqwest::{Body, Method};
|
||||||
use shared_entity::response::{AppResponse, AppResponseError};
|
use shared_entity::{
|
||||||
|
dto::workspace_dto::PublishInfo,
|
||||||
|
response::{AppResponse, AppResponseError},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::Client;
|
use crate::Client;
|
||||||
|
|
||||||
|
|
@ -112,23 +115,13 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize)]
|
|
||||||
pub struct PublishInfo {
|
|
||||||
pub namespace: String,
|
|
||||||
pub doc_name: String,
|
|
||||||
pub view_id: uuid::Uuid,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guest API (no login required)
|
// Guest API (no login required)
|
||||||
impl Client {
|
impl Client {
|
||||||
pub async fn get_published_info(
|
pub async fn get_published_info(
|
||||||
&self,
|
&self,
|
||||||
view_id: &uuid::Uuid,
|
view_id: &uuid::Uuid,
|
||||||
) -> Result<PublishInfo, AppResponseError> {
|
) -> Result<PublishInfo, AppResponseError> {
|
||||||
let url = format!(
|
let url = format!("{}/api/workspace/published_info/{}", self.base_url, view_id,);
|
||||||
"{}/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)
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ pub async fn select_user_is_collab_publisher(
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
user_uuid: &Uuid,
|
user_uuid: &Uuid,
|
||||||
workspace_uuid: &Uuid,
|
workspace_uuid: &Uuid,
|
||||||
doc_name: &str,
|
view_id: &Uuid,
|
||||||
) -> Result<bool, AppError> {
|
) -> Result<bool, AppError> {
|
||||||
let exists = sqlx::query_scalar!(
|
let exists = sqlx::query_scalar!(
|
||||||
r#"
|
r#"
|
||||||
|
|
@ -155,12 +155,12 @@ pub async fn select_user_is_collab_publisher(
|
||||||
SELECT 1
|
SELECT 1
|
||||||
FROM af_published_collab
|
FROM af_published_collab
|
||||||
WHERE workspace_id = $1
|
WHERE workspace_id = $1
|
||||||
AND doc_name = $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,
|
||||||
doc_name,
|
view_id,
|
||||||
user_uuid,
|
user_uuid,
|
||||||
)
|
)
|
||||||
.fetch_one(pg_pool)
|
.fetch_one(pg_pool)
|
||||||
|
|
@ -890,20 +890,22 @@ pub async fn select_workspace_publish_namespace<'a, E: Executor<'a, Database = P
|
||||||
pub async fn insert_or_replace_publish_collab_meta<'a, E: Executor<'a, Database = Postgres>>(
|
pub async fn insert_or_replace_publish_collab_meta<'a, E: Executor<'a, Database = Postgres>>(
|
||||||
executor: E,
|
executor: E,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
|
view_id: &Uuid,
|
||||||
doc_name: &str,
|
doc_name: &str,
|
||||||
publisher_uuid: &Uuid,
|
publisher_uuid: &Uuid,
|
||||||
metadata: &serde_json::Value,
|
metadata: &serde_json::Value,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
let res = sqlx::query!(
|
let res = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO af_published_collab (doc_name, published_by, workspace_id, metadata)
|
INSERT INTO af_published_collab (workspace_id, view_id, doc_name, published_by, metadata)
|
||||||
VALUES ($1, (SELECT uid FROM af_user WHERE uuid = $2), $3, $4)
|
VALUES ($1, $2, $3, (SELECT uid FROM af_user WHERE uuid = $4), $5)
|
||||||
ON CONFLICT (workspace_id, doc_name) DO UPDATE
|
ON CONFLICT (workspace_id, view_id) DO UPDATE
|
||||||
SET metadata = $4
|
SET metadata = $5
|
||||||
"#,
|
"#,
|
||||||
|
workspace_id,
|
||||||
|
view_id,
|
||||||
doc_name,
|
doc_name,
|
||||||
publisher_uuid,
|
publisher_uuid,
|
||||||
workspace_id,
|
|
||||||
metadata,
|
metadata,
|
||||||
)
|
)
|
||||||
.execute(executor)
|
.execute(executor)
|
||||||
|
|
@ -945,24 +947,24 @@ pub async fn select_publish_collab_meta<'a, E: Executor<'a, Database = Postgres>
|
||||||
pub async fn delete_published_collab<'a, E: Executor<'a, Database = Postgres>>(
|
pub async fn delete_published_collab<'a, E: Executor<'a, Database = Postgres>>(
|
||||||
executor: E,
|
executor: E,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
doc_name: &str,
|
view_id: &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 doc_name = $2
|
WHERE workspace_id = $1 AND view_id = $2
|
||||||
"#,
|
"#,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
doc_name,
|
view_id,
|
||||||
)
|
)
|
||||||
.execute(executor)
|
.execute(executor)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if res.rows_affected() != 1 {
|
if res.rows_affected() != 1 {
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
"Failed to delete published collab, workspace_id: {}, doc_name: {}, rows_affected: {}",
|
"Failed to delete published collab, workspace_id: {}, view_id: {}, rows_affected: {}",
|
||||||
workspace_id,
|
workspace_id,
|
||||||
doc_name,
|
view_id,
|
||||||
res.rows_affected()
|
res.rows_affected()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -974,18 +976,19 @@ pub async fn delete_published_collab<'a, E: Executor<'a, Database = Postgres>>(
|
||||||
pub async fn insert_or_replace_published_collab_blob<'a, E: Executor<'a, Database = Postgres>>(
|
pub async fn insert_or_replace_published_collab_blob<'a, E: Executor<'a, Database = Postgres>>(
|
||||||
executor: E,
|
executor: E,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
doc_name: &str,
|
view_id: &Uuid,
|
||||||
blob: &[u8],
|
blob: &[u8],
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
let res = sqlx::query!(
|
let res = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
UPDATE af_published_collab
|
UPDATE af_published_collab
|
||||||
SET blob = $1
|
SET blob = $1
|
||||||
WHERE workspace_id = $2 AND doc_name = $3
|
WHERE workspace_id = $2
|
||||||
|
AND view_id = $3
|
||||||
"#,
|
"#,
|
||||||
blob,
|
blob,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
doc_name,
|
view_id,
|
||||||
)
|
)
|
||||||
.execute(executor)
|
.execute(executor)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
@ -993,7 +996,7 @@ pub async fn insert_or_replace_published_collab_blob<'a, E: Executor<'a, Databas
|
||||||
if res.rows_affected() != 1 {
|
if res.rows_affected() != 1 {
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
"Failed to insert or replace published collab blob, workspace_id: {}, doc_name: {}, rows_affected: {}",
|
"Failed to insert or replace published collab blob, workspace_id: {}, doc_name: {}, rows_affected: {}",
|
||||||
workspace_id, doc_name, res.rows_affected()
|
workspace_id, view_id, res.rows_affected()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -120,3 +120,10 @@ pub struct CollabResponse {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub object_id: String,
|
pub object_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize)]
|
||||||
|
pub struct PublishInfo {
|
||||||
|
pub namespace: String,
|
||||||
|
pub doc_name: String,
|
||||||
|
pub view_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
ALTER TABLE af_published_collab ADD COLUMN view_id UUID NOT NULL DEFAULT gen_random_uuid();
|
||||||
|
ALTER TABLE af_published_collab DROP CONSTRAINT af_published_collab_pkey;
|
||||||
|
ALTER TABLE af_published_collab ADD PRIMARY KEY (workspace_id, view_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_workspace_id_on_af_published_collab ON af_published_collab (workspace_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_published_by_on_af_published_collab ON af_published_collab (published_by);
|
||||||
|
|
@ -138,12 +138,15 @@ pub fn workspace_scope() -> Scope {
|
||||||
.route(web::get().to(get_publish_namespace_handler))
|
.route(web::get().to(get_publish_namespace_handler))
|
||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/{workspace_id}/publish/{doc_name}/blob")
|
web::resource("/{workspace_id}/publish/{view_id}/blob")
|
||||||
.route(web::put().to(put_publish_collab_blob_handler))
|
.route(web::put().to(put_publish_collab_blob_handler))
|
||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/{workspace_id}/publish/{doc_name}")
|
web::resource("/{workspace_id}/publish/{view_id}/{doc_name}")
|
||||||
.route(web::put().to(put_publish_collab_handler))
|
.route(web::put().to(put_publish_collab_handler))
|
||||||
|
)
|
||||||
|
.service(
|
||||||
|
web::resource("/{workspace_id}/publish/{view_id}")
|
||||||
.route(web::delete().to(delete_publish_collab_handler))
|
.route(web::delete().to(delete_publish_collab_handler))
|
||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
|
|
@ -986,15 +989,16 @@ async fn get_published_collab_blob_handler(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn put_publish_collab_handler(
|
async fn put_publish_collab_handler(
|
||||||
path_param: web::Path<(Uuid, String)>,
|
path_param: web::Path<(Uuid, Uuid, String)>,
|
||||||
user_uuid: UserUuid,
|
user_uuid: UserUuid,
|
||||||
metadata: Json<serde_json::Value>,
|
metadata: Json<serde_json::Value>,
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
) -> Result<Json<AppResponse<()>>> {
|
) -> Result<Json<AppResponse<()>>> {
|
||||||
let (workspace_id, doc_name) = path_param.into_inner();
|
let (workspace_id, view_id, doc_name) = path_param.into_inner();
|
||||||
biz::workspace::ops::publish_collab(
|
biz::workspace::ops::publish_collab(
|
||||||
&state.pg_pool,
|
&state.pg_pool,
|
||||||
&workspace_id,
|
&workspace_id,
|
||||||
|
&view_id,
|
||||||
&doc_name,
|
&doc_name,
|
||||||
&user_uuid,
|
&user_uuid,
|
||||||
&metadata,
|
&metadata,
|
||||||
|
|
@ -1004,16 +1008,16 @@ async fn put_publish_collab_handler(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn put_publish_collab_blob_handler(
|
async fn put_publish_collab_blob_handler(
|
||||||
path_param: web::Path<(Uuid, String)>,
|
path_param: web::Path<(Uuid, Uuid)>,
|
||||||
user_uuid: UserUuid,
|
user_uuid: UserUuid,
|
||||||
collab_data: Bytes,
|
collab_data: Bytes,
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
) -> Result<Json<AppResponse<()>>> {
|
) -> Result<Json<AppResponse<()>>> {
|
||||||
let (workspace_id, doc_name) = path_param.into_inner();
|
let (workspace_id, view_id) = path_param.into_inner();
|
||||||
biz::workspace::ops::put_published_collab_blob(
|
biz::workspace::ops::put_published_collab_blob(
|
||||||
&state.pg_pool,
|
&state.pg_pool,
|
||||||
&workspace_id,
|
&workspace_id,
|
||||||
&doc_name,
|
&view_id,
|
||||||
&user_uuid,
|
&user_uuid,
|
||||||
&collab_data,
|
&collab_data,
|
||||||
)
|
)
|
||||||
|
|
@ -1022,15 +1026,15 @@ async fn put_publish_collab_blob_handler(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_publish_collab_handler(
|
async fn delete_publish_collab_handler(
|
||||||
path_param: web::Path<(Uuid, String)>,
|
path_param: web::Path<(Uuid, Uuid)>,
|
||||||
user_uuid: UserUuid,
|
user_uuid: UserUuid,
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
) -> Result<Json<AppResponse<()>>> {
|
) -> Result<Json<AppResponse<()>>> {
|
||||||
let (workspace_id, doc_name) = path_param.into_inner();
|
let (workspace_id, view_id) = path_param.into_inner();
|
||||||
biz::workspace::ops::delete_published_workspace_collab(
|
biz::workspace::ops::delete_published_workspace_collab(
|
||||||
&state.pg_pool,
|
&state.pg_pool,
|
||||||
&workspace_id,
|
&workspace_id,
|
||||||
&doc_name,
|
&view_id,
|
||||||
&user_uuid,
|
&user_uuid,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
||||||
|
|
@ -153,26 +153,34 @@ pub async fn get_workspace_publish_namespace(
|
||||||
pub async fn publish_collab(
|
pub async fn publish_collab(
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
|
view_id: &Uuid,
|
||||||
doc_name: &str,
|
doc_name: &str,
|
||||||
publisher_uuid: &Uuid,
|
publisher_uuid: &Uuid,
|
||||||
metadata: &serde_json::Value,
|
metadata: &serde_json::Value,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
check_workspace_owner_or_publisher(pg_pool, publisher_uuid, workspace_id, doc_name).await?;
|
check_workspace_owner_or_publisher(pg_pool, publisher_uuid, workspace_id, view_id).await?;
|
||||||
check_collab_doc_name(doc_name).await?;
|
check_collab_doc_name(doc_name).await?;
|
||||||
insert_or_replace_publish_collab_meta(pg_pool, workspace_id, doc_name, publisher_uuid, metadata)
|
insert_or_replace_publish_collab_meta(
|
||||||
.await?;
|
pg_pool,
|
||||||
|
workspace_id,
|
||||||
|
view_id,
|
||||||
|
doc_name,
|
||||||
|
publisher_uuid,
|
||||||
|
metadata,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn put_published_collab_blob(
|
pub async fn put_published_collab_blob(
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
doc_name: &str,
|
view_id: &Uuid,
|
||||||
publisher_uuid: &Uuid,
|
publisher_uuid: &Uuid,
|
||||||
collab_data: &[u8],
|
collab_data: &[u8],
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
check_workspace_owner_or_publisher(pg_pool, publisher_uuid, workspace_id, doc_name).await?;
|
check_workspace_owner_or_publisher(pg_pool, publisher_uuid, workspace_id, view_id).await?;
|
||||||
insert_or_replace_published_collab_blob(pg_pool, workspace_id, doc_name, collab_data).await?;
|
insert_or_replace_published_collab_blob(pg_pool, workspace_id, view_id, collab_data).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,11 +204,11 @@ pub async fn get_published_collab_blob(
|
||||||
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,
|
||||||
doc_name: &str,
|
view_id: &Uuid,
|
||||||
user_uuid: &Uuid,
|
user_uuid: &Uuid,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
check_workspace_owner_or_publisher(pg_pool, user_uuid, workspace_id, doc_name).await?;
|
check_workspace_owner_or_publisher(pg_pool, user_uuid, workspace_id, view_id).await?;
|
||||||
delete_published_collab(pg_pool, workspace_id, doc_name).await?;
|
delete_published_collab(pg_pool, workspace_id, view_id).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -585,12 +593,12 @@ 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,
|
||||||
doc_name: &str,
|
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, doc_name).await?;
|
select_user_is_collab_publisher(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(),
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,10 @@ async fn test_publish_doc() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let my_doc_name = "my-doc";
|
let my_doc_name = "my-doc";
|
||||||
|
let view_id = uuid::Uuid::new_v4();
|
||||||
c.publish_collab(
|
c.publish_collab(
|
||||||
&workspace_id,
|
&workspace_id,
|
||||||
|
&view_id,
|
||||||
my_doc_name,
|
my_doc_name,
|
||||||
Metadata {
|
Metadata {
|
||||||
title: "my_title".to_string(),
|
title: "my_title".to_string(),
|
||||||
|
|
@ -99,7 +101,7 @@ async fn test_publish_doc() {
|
||||||
assert!(collab_data.is_empty()); // empty data because publisher need to set it
|
assert!(collab_data.is_empty()); // empty data because publisher need to set it
|
||||||
}
|
}
|
||||||
|
|
||||||
c.put_published_collab_blob(&workspace_id, my_doc_name, "some_collab_data")
|
c.put_published_collab_blob(&workspace_id, &view_id, "some_collab_data")
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
@ -113,7 +115,7 @@ async fn test_publish_doc() {
|
||||||
assert!(collab_data == "some_collab_data");
|
assert!(collab_data == "some_collab_data");
|
||||||
}
|
}
|
||||||
|
|
||||||
c.delete_published_collab(&workspace_id, my_doc_name)
|
c.delete_published_collab(&workspace_id, &view_id)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue