mirror of
https://github.com/AppFlowy-IO/AppFlowy-Cloud.git
synced 2025-04-19 03:24:42 -04:00
feat: use view id
This commit is contained in:
parent
31b3275d8d
commit
18e9d0abae
7 changed files with 75 additions and 52 deletions
|
@ -1,7 +1,10 @@
|
|||
use bytes::Bytes;
|
||||
use database_entity::dto::UpdatePublishNamespace;
|
||||
use reqwest::{Body, Method};
|
||||
use shared_entity::response::{AppResponse, AppResponseError};
|
||||
use shared_entity::{
|
||||
dto::workspace_dto::PublishInfo,
|
||||
response::{AppResponse, AppResponseError},
|
||||
};
|
||||
|
||||
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)
|
||||
impl Client {
|
||||
pub async fn get_published_info(
|
||||
&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)
|
||||
|
|
|
@ -147,7 +147,7 @@ pub async fn select_user_is_collab_publisher(
|
|||
pg_pool: &PgPool,
|
||||
user_uuid: &Uuid,
|
||||
workspace_uuid: &Uuid,
|
||||
doc_name: &str,
|
||||
view_id: &Uuid,
|
||||
) -> Result<bool, AppError> {
|
||||
let exists = sqlx::query_scalar!(
|
||||
r#"
|
||||
|
@ -155,12 +155,12 @@ pub async fn select_user_is_collab_publisher(
|
|||
SELECT 1
|
||||
FROM af_published_collab
|
||||
WHERE workspace_id = $1
|
||||
AND doc_name = $2
|
||||
AND view_id = $2
|
||||
AND published_by = (SELECT uid FROM af_user WHERE uuid = $3)
|
||||
);
|
||||
"#,
|
||||
workspace_uuid,
|
||||
doc_name,
|
||||
view_id,
|
||||
user_uuid,
|
||||
)
|
||||
.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>>(
|
||||
executor: E,
|
||||
workspace_id: &Uuid,
|
||||
view_id: &Uuid,
|
||||
doc_name: &str,
|
||||
publisher_uuid: &Uuid,
|
||||
metadata: &serde_json::Value,
|
||||
) -> Result<(), AppError> {
|
||||
let res = sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO af_published_collab (doc_name, published_by, workspace_id, metadata)
|
||||
VALUES ($1, (SELECT uid FROM af_user WHERE uuid = $2), $3, $4)
|
||||
ON CONFLICT (workspace_id, doc_name) DO UPDATE
|
||||
SET metadata = $4
|
||||
INSERT INTO af_published_collab (workspace_id, view_id, doc_name, published_by, metadata)
|
||||
VALUES ($1, $2, $3, (SELECT uid FROM af_user WHERE uuid = $4), $5)
|
||||
ON CONFLICT (workspace_id, view_id) DO UPDATE
|
||||
SET metadata = $5
|
||||
"#,
|
||||
workspace_id,
|
||||
view_id,
|
||||
doc_name,
|
||||
publisher_uuid,
|
||||
workspace_id,
|
||||
metadata,
|
||||
)
|
||||
.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>>(
|
||||
executor: E,
|
||||
workspace_id: &Uuid,
|
||||
doc_name: &str,
|
||||
view_id: &Uuid,
|
||||
) -> Result<(), AppError> {
|
||||
let res = sqlx::query!(
|
||||
r#"
|
||||
DELETE FROM af_published_collab
|
||||
WHERE workspace_id = $1 AND doc_name = $2
|
||||
WHERE workspace_id = $1 AND view_id = $2
|
||||
"#,
|
||||
workspace_id,
|
||||
doc_name,
|
||||
view_id,
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
|
||||
if res.rows_affected() != 1 {
|
||||
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,
|
||||
doc_name,
|
||||
view_id,
|
||||
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>>(
|
||||
executor: E,
|
||||
workspace_id: &Uuid,
|
||||
doc_name: &str,
|
||||
view_id: &Uuid,
|
||||
blob: &[u8],
|
||||
) -> Result<(), AppError> {
|
||||
let res = sqlx::query!(
|
||||
r#"
|
||||
UPDATE af_published_collab
|
||||
SET blob = $1
|
||||
WHERE workspace_id = $2 AND doc_name = $3
|
||||
WHERE workspace_id = $2
|
||||
AND view_id = $3
|
||||
"#,
|
||||
blob,
|
||||
workspace_id,
|
||||
doc_name,
|
||||
view_id,
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
|
@ -993,7 +996,7 @@ pub async fn insert_or_replace_published_collab_blob<'a, E: Executor<'a, Databas
|
|||
if res.rows_affected() != 1 {
|
||||
tracing::error!(
|
||||
"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)]
|
||||
pub object_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct PublishInfo {
|
||||
pub namespace: String,
|
||||
pub doc_name: String,
|
||||
pub view_id: uuid::Uuid,
|
||||
}
|
||||
|
|
6
migrations/20240618173348_publish_collab_2.sql
Normal file
6
migrations/20240618173348_publish_collab_2.sql
Normal file
|
@ -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))
|
||||
)
|
||||
.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))
|
||||
)
|
||||
.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))
|
||||
)
|
||||
.service(
|
||||
web::resource("/{workspace_id}/publish/{view_id}")
|
||||
.route(web::delete().to(delete_publish_collab_handler))
|
||||
)
|
||||
.service(
|
||||
|
@ -986,15 +989,16 @@ async fn get_published_collab_blob_handler(
|
|||
}
|
||||
|
||||
async fn put_publish_collab_handler(
|
||||
path_param: web::Path<(Uuid, String)>,
|
||||
path_param: web::Path<(Uuid, Uuid, String)>,
|
||||
user_uuid: UserUuid,
|
||||
metadata: Json<serde_json::Value>,
|
||||
state: Data<AppState>,
|
||||
) -> 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(
|
||||
&state.pg_pool,
|
||||
&workspace_id,
|
||||
&view_id,
|
||||
&doc_name,
|
||||
&user_uuid,
|
||||
&metadata,
|
||||
|
@ -1004,16 +1008,16 @@ async fn put_publish_collab_handler(
|
|||
}
|
||||
|
||||
async fn put_publish_collab_blob_handler(
|
||||
path_param: web::Path<(Uuid, String)>,
|
||||
path_param: web::Path<(Uuid, Uuid)>,
|
||||
user_uuid: UserUuid,
|
||||
collab_data: Bytes,
|
||||
state: Data<AppState>,
|
||||
) -> 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(
|
||||
&state.pg_pool,
|
||||
&workspace_id,
|
||||
&doc_name,
|
||||
&view_id,
|
||||
&user_uuid,
|
||||
&collab_data,
|
||||
)
|
||||
|
@ -1022,15 +1026,15 @@ async fn put_publish_collab_blob_handler(
|
|||
}
|
||||
|
||||
async fn delete_publish_collab_handler(
|
||||
path_param: web::Path<(Uuid, String)>,
|
||||
path_param: web::Path<(Uuid, Uuid)>,
|
||||
user_uuid: UserUuid,
|
||||
state: Data<AppState>,
|
||||
) -> 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(
|
||||
&state.pg_pool,
|
||||
&workspace_id,
|
||||
&doc_name,
|
||||
&view_id,
|
||||
&user_uuid,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -153,26 +153,34 @@ pub async fn get_workspace_publish_namespace(
|
|||
pub async fn publish_collab(
|
||||
pg_pool: &PgPool,
|
||||
workspace_id: &Uuid,
|
||||
view_id: &Uuid,
|
||||
doc_name: &str,
|
||||
publisher_uuid: &Uuid,
|
||||
metadata: &serde_json::Value,
|
||||
) -> 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?;
|
||||
insert_or_replace_publish_collab_meta(pg_pool, workspace_id, doc_name, publisher_uuid, metadata)
|
||||
.await?;
|
||||
insert_or_replace_publish_collab_meta(
|
||||
pg_pool,
|
||||
workspace_id,
|
||||
view_id,
|
||||
doc_name,
|
||||
publisher_uuid,
|
||||
metadata,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn put_published_collab_blob(
|
||||
pg_pool: &PgPool,
|
||||
workspace_id: &Uuid,
|
||||
doc_name: &str,
|
||||
view_id: &Uuid,
|
||||
publisher_uuid: &Uuid,
|
||||
collab_data: &[u8],
|
||||
) -> Result<(), AppError> {
|
||||
check_workspace_owner_or_publisher(pg_pool, publisher_uuid, workspace_id, doc_name).await?;
|
||||
insert_or_replace_published_collab_blob(pg_pool, workspace_id, doc_name, collab_data).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, view_id, collab_data).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -196,11 +204,11 @@ pub async fn get_published_collab_blob(
|
|||
pub async fn delete_published_workspace_collab(
|
||||
pg_pool: &PgPool,
|
||||
workspace_id: &Uuid,
|
||||
doc_name: &str,
|
||||
view_id: &Uuid,
|
||||
user_uuid: &Uuid,
|
||||
) -> Result<(), AppError> {
|
||||
check_workspace_owner_or_publisher(pg_pool, user_uuid, workspace_id, doc_name).await?;
|
||||
delete_published_collab(pg_pool, 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, view_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -585,12 +593,12 @@ async fn check_workspace_owner_or_publisher(
|
|||
pg_pool: &PgPool,
|
||||
user_uuid: &Uuid,
|
||||
workspace_id: &Uuid,
|
||||
doc_name: &str,
|
||||
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, doc_name).await?;
|
||||
select_user_is_collab_publisher(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(),
|
||||
|
|
|
@ -73,8 +73,10 @@ async fn test_publish_doc() {
|
|||
.unwrap();
|
||||
|
||||
let my_doc_name = "my-doc";
|
||||
let view_id = uuid::Uuid::new_v4();
|
||||
c.publish_collab(
|
||||
&workspace_id,
|
||||
&view_id,
|
||||
my_doc_name,
|
||||
Metadata {
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
.unwrap();
|
||||
|
||||
|
@ -113,7 +115,7 @@ async fn test_publish_doc() {
|
|||
assert!(collab_data == "some_collab_data");
|
||||
}
|
||||
|
||||
c.delete_published_collab(&workspace_id, my_doc_name)
|
||||
c.delete_published_collab(&workspace_id, &view_id)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue