fix: fix various publish issues

This commit is contained in:
Zack Fu Zi Xiang 2024-06-29 11:23:23 +08:00
parent b02f8a2844
commit 395486adc3
No known key found for this signature in database
7 changed files with 72 additions and 20 deletions

View File

@ -117,9 +117,6 @@ pub enum AppError {
#[error("{0}")] #[error("{0}")]
OverrideWithIncorrectData(String), OverrideWithIncorrectData(String),
#[error("{0}")]
PublishNamespaceNotSet(String),
#[error("{0}")] #[error("{0}")]
PublishNamespaceAlreadyTaken(String), PublishNamespaceAlreadyTaken(String),
} }
@ -180,7 +177,6 @@ impl AppError {
AppError::NoRequiredData(_) => ErrorCode::NoRequiredData, AppError::NoRequiredData(_) => ErrorCode::NoRequiredData,
AppError::OverrideWithIncorrectData(_) => ErrorCode::OverrideWithIncorrectData, AppError::OverrideWithIncorrectData(_) => ErrorCode::OverrideWithIncorrectData,
AppError::Utf8Error(_) => ErrorCode::Internal, AppError::Utf8Error(_) => ErrorCode::Internal,
AppError::PublishNamespaceNotSet(_) => ErrorCode::PublishNamespaceNotSet,
AppError::PublishNamespaceAlreadyTaken(_) => ErrorCode::PublishNamespaceAlreadyTaken, AppError::PublishNamespaceAlreadyTaken(_) => ErrorCode::PublishNamespaceAlreadyTaken,
} }
} }

View File

@ -887,7 +887,7 @@ pub async fn update_workspace_publish_namespace<'a, E: Executor<'a, Database = P
pub async fn select_workspace_publish_namespace<'a, E: Executor<'a, Database = Postgres>>( pub async fn select_workspace_publish_namespace<'a, E: Executor<'a, Database = Postgres>>(
executor: E, executor: E,
workspace_id: &Uuid, workspace_id: &Uuid,
) -> Result<Option<String>, AppError> { ) -> Result<String, AppError> {
let res = sqlx::query_scalar!( let res = sqlx::query_scalar!(
r#" r#"
SELECT publish_namespace SELECT publish_namespace

View File

@ -0,0 +1,9 @@
-- Update existing null values to ensure no nulls are present before adding NOT NULL constraint
UPDATE public.af_workspace
SET publish_namespace = uuid_generate_v4()::text
WHERE publish_namespace IS NULL;
-- Alter the column to set NOT NULL constraint and a default value
ALTER TABLE public.af_workspace
ALTER COLUMN publish_namespace SET NOT NULL,
ALTER COLUMN publish_namespace SET DEFAULT uuid_generate_v4()::text;

View File

@ -47,6 +47,7 @@ pub const WORKSPACE_MEMBER_PATTERN: &str = "/api/workspace/{workspace_id}/member
pub const WORKSPACE_INVITE_PATTERN: &str = "/api/workspace/{workspace_id}/invite"; pub const WORKSPACE_INVITE_PATTERN: &str = "/api/workspace/{workspace_id}/invite";
pub const COLLAB_PATTERN: &str = "/api/workspace/{workspace_id}/collab/{object_id}"; pub const COLLAB_PATTERN: &str = "/api/workspace/{workspace_id}/collab/{object_id}";
pub const V1_COLLAB_PATTERN: &str = "/api/workspace/v1/{workspace_id}/collab/{object_id}"; pub const V1_COLLAB_PATTERN: &str = "/api/workspace/v1/{workspace_id}/collab/{object_id}";
pub const WORKSPACE_PUBLISH_PATTERN: &str = "/api/workspace/{workspace_id}/publish";
pub const WORKSPACE_PUBLISH_NAMESPACE_PATTERN: &str = pub const WORKSPACE_PUBLISH_NAMESPACE_PATTERN: &str =
"/api/workspace/{workspace_id}/publish-namespace"; "/api/workspace/{workspace_id}/publish-namespace";

View File

@ -21,7 +21,7 @@ use database_entity::dto::AFRole;
use crate::api::workspace::{ use crate::api::workspace::{
WORKSPACE_INVITE_PATTERN, WORKSPACE_MEMBER_PATTERN, WORKSPACE_PATTERN, WORKSPACE_INVITE_PATTERN, WORKSPACE_MEMBER_PATTERN, WORKSPACE_PATTERN,
WORKSPACE_PUBLISH_NAMESPACE_PATTERN, WORKSPACE_PUBLISH_NAMESPACE_PATTERN, WORKSPACE_PUBLISH_PATTERN,
}; };
use crate::middleware::access_control_mw::{AccessResource, MiddlewareAccessControl}; use crate::middleware::access_control_mw::{AccessResource, MiddlewareAccessControl};
use crate::state::UserCache; use crate::state::UserCache;
@ -48,6 +48,10 @@ where
], ],
// Require role for given resources // Require role for given resources
require_role_rules: vec![ require_role_rules: vec![
(
ResourceDef::new(WORKSPACE_PUBLISH_PATTERN),
[(Method::DELETE, AFRole::Member)].into(),
),
// Only the Owner can manager the workspace members // Only the Owner can manager the workspace members
( (
ResourceDef::new(WORKSPACE_MEMBER_PATTERN), ResourceDef::new(WORKSPACE_MEMBER_PATTERN),

View File

@ -132,15 +132,7 @@ pub async fn get_workspace_publish_namespace(
pg_pool: &PgPool, pg_pool: &PgPool,
workspace_id: &Uuid, workspace_id: &Uuid,
) -> Result<String, AppError> { ) -> Result<String, AppError> {
let namespace = match select_workspace_publish_namespace(pg_pool, workspace_id).await? { select_workspace_publish_namespace(pg_pool, workspace_id).await
Some(namespace) => namespace,
None => {
return Err(AppError::PublishNamespaceNotSet(
"publish namespace is not set for the workspace".to_string(),
))
},
};
Ok(namespace)
} }
pub async fn publish_collabs( pub async fn publish_collabs(

View File

@ -1,4 +1,5 @@
use client_api::entity::{PublishCollabItem, PublishCollabMetadata}; use client_api::entity::{AFRole, PublishCollabItem, PublishCollabMetadata};
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};
#[tokio::test] #[tokio::test]
@ -7,13 +8,11 @@ async fn test_set_publish_namespace_set() {
let workspace_id = get_first_workspace_string(&c).await; let workspace_id = get_first_workspace_string(&c).await;
{ {
// cannot get namespace if not set // can get namespace before setting, which is random string
let err = c let _ = c
.get_workspace_publish_namespace(&workspace_id.to_string()) .get_workspace_publish_namespace(&workspace_id.to_string())
.await .await
.err()
.unwrap(); .unwrap();
assert_eq!(format!("{:?}", err.code), "PublishNamespaceNotSet");
} }
let namespace = uuid::Uuid::new_v4().to_string(); let namespace = uuid::Uuid::new_v4().to_string();
@ -127,6 +126,20 @@ async fn test_publish_doc() {
.await .await
.unwrap(); .unwrap();
assert_eq!(blob, "yrs_encoded_data_1"); assert_eq!(blob, "yrs_encoded_data_1");
let publish_info = guest_client
.get_published_collab_info(&view_id_2)
.await
.unwrap();
assert_eq!(publish_info.namespace, Some(my_namespace.clone()));
assert_eq!(publish_info.publish_name, publish_name_2);
assert_eq!(publish_info.view_id, view_id_2);
let blob = guest_client
.get_published_collab_blob(&my_namespace, publish_name_2)
.await
.unwrap();
assert_eq!(blob, "yrs_encoded_data_2");
} }
c.unpublish_collabs(&workspace_id, &[view_id_1]) c.unpublish_collabs(&workspace_id, &[view_id_1])
@ -200,6 +213,43 @@ async fn get_first_workspace_string(c: &client_api::Client) -> String {
.to_string() .to_string()
} }
#[tokio::test]
async fn workspace_member_publish_unpublish() {
let client_1 = TestClient::new_user_without_ws_conn().await;
let workspace_id = client_1.workspace_id().await;
let client_2 = TestClient::new_user_without_ws_conn().await;
client_1
.invite_and_accepted_workspace_member(&workspace_id, &client_2, AFRole::Member)
.await
.unwrap();
let view_id = uuid::Uuid::new_v4();
// member can publish without owner setting namespace
client_2
.api_client
.publish_collabs::<MyCustomMetadata, &[u8]>(
&workspace_id,
vec![PublishCollabItem {
meta: PublishCollabMetadata {
view_id,
publish_name: "publish-name-1".to_string(),
metadata: MyCustomMetadata {
title: "my_title_1".to_string(),
},
},
data: "yrs_encoded_data_1".as_bytes(),
}],
)
.await
.unwrap();
client_2
.api_client
.unpublish_collabs(&workspace_id, &[view_id])
.await
.unwrap();
}
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
struct MyCustomMetadata { struct MyCustomMetadata {
title: String, title: String,