feat: support for original and modified namespace
This commit is contained in:
parent
58efe8417e
commit
8d8c895703
|
|
@ -256,7 +256,7 @@ impl ClientAPI {
|
||||||
})?;
|
})?;
|
||||||
match self.client.get_published_collab_info(&view_id).await {
|
match self.client.get_published_collab_info(&view_id).await {
|
||||||
Ok(info) => Ok(PublishInfo {
|
Ok(info) => Ok(PublishInfo {
|
||||||
namespace: info.namespace,
|
namespace: Some(info.namespace),
|
||||||
publish_name: info.publish_name,
|
publish_name: info.publish_name,
|
||||||
}),
|
}),
|
||||||
Err(err) => Err(ClientResponse::from(err)),
|
Err(err) => Err(ClientResponse::from(err)),
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,15 @@ impl Client {
|
||||||
.into_data()
|
.into_data()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Changes the namespace for the first non-original publish namespace
|
||||||
|
/// or the original publish namespace if not exists.
|
||||||
pub async fn set_workspace_publish_namespace(
|
pub async fn set_workspace_publish_namespace(
|
||||||
&self,
|
&self,
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
new_namespace: &str,
|
new_namespace: String,
|
||||||
) -> Result<(), AppResponseError> {
|
) -> Result<(), AppResponseError> {
|
||||||
|
let old_namespace = self.get_workspace_publish_namespace(workspace_id).await?;
|
||||||
|
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"{}/api/workspace/{}/publish-namespace",
|
"{}/api/workspace/{}/publish-namespace",
|
||||||
self.base_url, workspace_id
|
self.base_url, workspace_id
|
||||||
|
|
@ -49,7 +53,8 @@ impl Client {
|
||||||
.http_client_with_auth(Method::PUT, &url)
|
.http_client_with_auth(Method::PUT, &url)
|
||||||
.await?
|
.await?
|
||||||
.json(&UpdatePublishNamespace {
|
.json(&UpdatePublishNamespace {
|
||||||
new_namespace: new_namespace.to_string(),
|
old_namespace,
|
||||||
|
new_namespace,
|
||||||
})
|
})
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
||||||
|
|
@ -372,6 +372,7 @@ pub struct CollabMemberIdentify {
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct UpdatePublishNamespace {
|
pub struct UpdatePublishNamespace {
|
||||||
|
pub old_namespace: String,
|
||||||
pub new_namespace: String,
|
pub new_namespace: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -411,7 +412,7 @@ pub struct AFCollabMember {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct PublishInfo {
|
pub struct PublishInfo {
|
||||||
pub namespace: Option<String>,
|
pub namespace: String,
|
||||||
pub publish_name: String,
|
pub publish_name: String,
|
||||||
pub view_id: Uuid,
|
pub view_id: Uuid,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|
@ -1509,6 +1510,13 @@ pub struct CreateImportTaskResponse {
|
||||||
pub presigned_url: String,
|
pub presigned_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WorkspaceNamespace {
|
||||||
|
pub workspace_id: Uuid,
|
||||||
|
pub namespace: String,
|
||||||
|
pub is_original: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::dto::{
|
use crate::dto::{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use app_error::AppError;
|
use app_error::AppError;
|
||||||
use database_entity::dto::{
|
use database_entity::dto::{
|
||||||
PatchPublishedCollab, PublishCollabItem, PublishCollabKey, PublishInfo,
|
PatchPublishedCollab, PublishCollabItem, PublishCollabKey, PublishInfo, WorkspaceNamespace,
|
||||||
};
|
};
|
||||||
use sqlx::{Executor, PgPool, Postgres};
|
use sqlx::{Executor, PgPool, Postgres};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
@ -41,8 +41,8 @@ pub async fn select_workspace_publish_namespace_exists<'a, E: Executor<'a, Datab
|
||||||
r#"
|
r#"
|
||||||
SELECT EXISTS(
|
SELECT EXISTS(
|
||||||
SELECT 1
|
SELECT 1
|
||||||
FROM af_workspace
|
FROM af_workspace_namespace
|
||||||
WHERE publish_namespace = $1
|
WHERE namespace = $1
|
||||||
)
|
)
|
||||||
"#,
|
"#,
|
||||||
namespace,
|
namespace,
|
||||||
|
|
@ -54,19 +54,26 @@ pub async fn select_workspace_publish_namespace_exists<'a, E: Executor<'a, Datab
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn update_workspace_publish_namespace<'a, E: Executor<'a, Database = Postgres>>(
|
pub async fn update_non_orginal_workspace_publish_namespace<
|
||||||
|
'a,
|
||||||
|
E: Executor<'a, Database = Postgres>,
|
||||||
|
>(
|
||||||
executor: E,
|
executor: E,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
|
old_namespace: &str,
|
||||||
new_namespace: &str,
|
new_namespace: &str,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
let res = sqlx::query!(
|
let res = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
UPDATE af_workspace
|
UPDATE af_workspace_namespace
|
||||||
SET publish_namespace = $1
|
SET namespace = $1
|
||||||
WHERE workspace_id = $2
|
WHERE workspace_id = $2
|
||||||
|
AND namespace = $3
|
||||||
|
AND is_original = FALSE
|
||||||
"#,
|
"#,
|
||||||
new_namespace,
|
new_namespace,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
|
old_namespace,
|
||||||
)
|
)
|
||||||
.execute(executor)
|
.execute(executor)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
@ -140,19 +147,20 @@ pub async fn update_workspace_default_publish_view_set_null<
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn select_workspace_publish_namespace<'a, E: Executor<'a, Database = Postgres>>(
|
pub async fn select_workspace_publish_namespaces<'a, E: Executor<'a, Database = Postgres>>(
|
||||||
executor: E,
|
executor: E,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
) -> Result<String, AppError> {
|
) -> Result<Vec<WorkspaceNamespace>, AppError> {
|
||||||
let res = sqlx::query_scalar!(
|
let res = sqlx::query_as!(
|
||||||
|
WorkspaceNamespace,
|
||||||
r#"
|
r#"
|
||||||
SELECT publish_namespace
|
SELECT workspace_id, namespace, is_original
|
||||||
FROM af_workspace
|
FROM af_workspace_namespace
|
||||||
WHERE workspace_id = $1
|
WHERE workspace_id = $1
|
||||||
"#,
|
"#,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
)
|
)
|
||||||
.fetch_one(executor)
|
.fetch_all(executor)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
|
@ -225,7 +233,7 @@ pub async fn select_publish_collab_meta<'a, E: Executor<'a, Database = Postgres>
|
||||||
r#"
|
r#"
|
||||||
SELECT metadata
|
SELECT metadata
|
||||||
FROM af_published_collab
|
FROM af_published_collab
|
||||||
WHERE workspace_id = (SELECT workspace_id FROM af_workspace WHERE publish_namespace = $1)
|
WHERE workspace_id = (SELECT workspace_id FROM af_workspace_namespace WHERE namespace = $1)
|
||||||
AND publish_name = $2
|
AND publish_name = $2
|
||||||
"#,
|
"#,
|
||||||
publish_namespace,
|
publish_namespace,
|
||||||
|
|
@ -354,7 +362,7 @@ pub async fn select_published_collab_workspace_view_id<'a, E: Executor<'a, Datab
|
||||||
r#"
|
r#"
|
||||||
SELECT workspace_id, view_id
|
SELECT workspace_id, view_id
|
||||||
FROM af_published_collab
|
FROM af_published_collab
|
||||||
WHERE workspace_id = (SELECT workspace_id FROM af_workspace WHERE publish_namespace = $1)
|
WHERE workspace_id = (SELECT workspace_id FROM af_workspace_namespace WHERE namespace = $1)
|
||||||
AND publish_name = $2
|
AND publish_name = $2
|
||||||
"#,
|
"#,
|
||||||
publish_namespace,
|
publish_namespace,
|
||||||
|
|
@ -375,7 +383,7 @@ pub async fn select_published_collab_blob<'a, E: Executor<'a, Database = Postgre
|
||||||
r#"
|
r#"
|
||||||
SELECT blob
|
SELECT blob
|
||||||
FROM af_published_collab
|
FROM af_published_collab
|
||||||
WHERE workspace_id = (SELECT workspace_id FROM af_workspace WHERE publish_namespace = $1)
|
WHERE workspace_id = (SELECT workspace_id FROM af_workspace_namespace WHERE namespace = $1)
|
||||||
AND publish_name = $2
|
AND publish_name = $2
|
||||||
"#,
|
"#,
|
||||||
publish_namespace,
|
publish_namespace,
|
||||||
|
|
@ -398,7 +406,7 @@ pub async fn select_default_published_view_id_for_namespace<
|
||||||
r#"
|
r#"
|
||||||
SELECT default_published_view_id
|
SELECT default_published_view_id
|
||||||
FROM af_workspace
|
FROM af_workspace
|
||||||
WHERE publish_namespace = $1
|
WHERE workspace_id = (SELECT workspace_id FROM af_workspace_namespace WHERE namespace = $1)
|
||||||
"#,
|
"#,
|
||||||
namespace,
|
namespace,
|
||||||
)
|
)
|
||||||
|
|
@ -426,15 +434,36 @@ pub async fn select_default_published_view_id<'a, E: Executor<'a, Database = Pos
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn select_published_collab_info_for_view_ids<'a, E: Executor<'a, Database = Postgres>>(
|
async fn select_first_non_original_namespace(
|
||||||
executor: E,
|
pg_pool: &PgPool,
|
||||||
|
namespace: &str,
|
||||||
|
) -> Result<Option<String>, AppError> {
|
||||||
|
let res = sqlx::query_scalar!(
|
||||||
|
r#"
|
||||||
|
SELECT namespace
|
||||||
|
FROM af_workspace_namespace
|
||||||
|
WHERE workspace_id = (SELECT workspace_id FROM af_workspace_namespace WHERE namespace = $1)
|
||||||
|
AND is_original = FALSE
|
||||||
|
ORDER BY created_at ASC
|
||||||
|
LIMIT 1
|
||||||
|
"#,
|
||||||
|
namespace,
|
||||||
|
)
|
||||||
|
.fetch_optional(pg_pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn select_published_collab_info_for_view_ids(
|
||||||
|
pg_pool: &PgPool,
|
||||||
view_ids: &[Uuid],
|
view_ids: &[Uuid],
|
||||||
) -> Result<Vec<PublishInfo>, AppError> {
|
) -> Result<Vec<PublishInfo>, AppError> {
|
||||||
let res = sqlx::query_as!(
|
let mut res = sqlx::query_as!(
|
||||||
PublishInfo,
|
PublishInfo,
|
||||||
r#"
|
r#"
|
||||||
SELECT
|
SELECT
|
||||||
aw.publish_namespace AS namespace,
|
awn.namespace,
|
||||||
apc.publish_name,
|
apc.publish_name,
|
||||||
apc.view_id,
|
apc.view_id,
|
||||||
au.email AS publisher_email,
|
au.email AS publisher_email,
|
||||||
|
|
@ -442,51 +471,47 @@ pub async fn select_published_collab_info_for_view_ids<'a, E: Executor<'a, Datab
|
||||||
FROM af_published_collab apc
|
FROM af_published_collab apc
|
||||||
JOIN af_user au ON apc.published_by = au.uid
|
JOIN af_user au ON apc.published_by = au.uid
|
||||||
JOIN af_workspace aw ON apc.workspace_id = aw.workspace_id
|
JOIN af_workspace aw ON apc.workspace_id = aw.workspace_id
|
||||||
|
JOIN af_workspace_namespace awn ON aw.workspace_id = awn.workspace_id AND awn.is_original = TRUE
|
||||||
WHERE apc.view_id = ANY($1);
|
WHERE apc.view_id = ANY($1);
|
||||||
"#,
|
"#,
|
||||||
view_ids,
|
view_ids,
|
||||||
)
|
)
|
||||||
.fetch_all(executor)
|
.fetch_all(pg_pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
if res.is_empty() {
|
||||||
|
return Ok(res);
|
||||||
|
}
|
||||||
|
if let Some(non_original_namespace) =
|
||||||
|
select_first_non_original_namespace(pg_pool, &res[0].namespace).await?
|
||||||
|
{
|
||||||
|
res.iter_mut().for_each(|info| {
|
||||||
|
info.namespace = non_original_namespace.clone();
|
||||||
|
});
|
||||||
|
}
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn select_published_collab_info<'a, E: Executor<'a, Database = Postgres>>(
|
pub async fn select_published_collab_info(
|
||||||
executor: E,
|
pg_pool: &PgPool,
|
||||||
view_id: &Uuid,
|
view_id: &Uuid,
|
||||||
) -> Result<PublishInfo, AppError> {
|
) -> Result<PublishInfo, AppError> {
|
||||||
let res = sqlx::query_as!(
|
select_published_collab_info_for_view_ids(pg_pool, &[*view_id])
|
||||||
PublishInfo,
|
.await?
|
||||||
r#"
|
.into_iter()
|
||||||
SELECT
|
.next()
|
||||||
aw.publish_namespace AS namespace,
|
.ok_or(AppError::RecordNotFound(view_id.to_string()))
|
||||||
apc.publish_name,
|
|
||||||
apc.view_id,
|
|
||||||
au.email AS publisher_email,
|
|
||||||
apc.created_at AS publish_timestamp
|
|
||||||
FROM af_published_collab apc
|
|
||||||
JOIN af_user au ON apc.published_by = au.uid
|
|
||||||
JOIN af_workspace aw ON apc.workspace_id = aw.workspace_id
|
|
||||||
WHERE apc.view_id = $1;
|
|
||||||
"#,
|
|
||||||
view_id,
|
|
||||||
)
|
|
||||||
.fetch_one(executor)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn select_all_published_collab_info<'a, E: Executor<'a, Database = Postgres>>(
|
pub async fn select_all_published_collab_info(
|
||||||
executor: E,
|
pg_pool: &PgPool,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
) -> Result<Vec<PublishInfo>, AppError> {
|
) -> Result<Vec<PublishInfo>, AppError> {
|
||||||
let res = sqlx::query_as!(
|
let mut res = sqlx::query_as!(
|
||||||
PublishInfo,
|
PublishInfo,
|
||||||
r#"
|
r#"
|
||||||
SELECT
|
SELECT
|
||||||
aw.publish_namespace AS namespace,
|
awn.namespace,
|
||||||
apc.publish_name,
|
apc.publish_name,
|
||||||
apc.view_id,
|
apc.view_id,
|
||||||
au.email AS publisher_email,
|
au.email AS publisher_email,
|
||||||
|
|
@ -494,16 +519,36 @@ pub async fn select_all_published_collab_info<'a, E: Executor<'a, Database = Pos
|
||||||
FROM af_published_collab apc
|
FROM af_published_collab apc
|
||||||
JOIN af_user au ON apc.published_by = au.uid
|
JOIN af_user au ON apc.published_by = au.uid
|
||||||
JOIN af_workspace aw ON apc.workspace_id = aw.workspace_id
|
JOIN af_workspace aw ON apc.workspace_id = aw.workspace_id
|
||||||
|
JOIN af_workspace_namespace awn ON aw.workspace_id = awn.workspace_id AND awn.is_original = TRUE
|
||||||
WHERE apc.workspace_id = $1;
|
WHERE apc.workspace_id = $1;
|
||||||
"#,
|
"#,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
)
|
)
|
||||||
.fetch_all(executor)
|
.fetch_all(pg_pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
use_non_orginal_namespace_if_possible(pg_pool, &mut res).await?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn use_non_orginal_namespace_if_possible(
|
||||||
|
pg_pool: &PgPool,
|
||||||
|
publish_infos: &mut [PublishInfo],
|
||||||
|
) -> Result<(), AppError> {
|
||||||
|
if publish_infos.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(non_original_namespace) =
|
||||||
|
select_first_non_original_namespace(pg_pool, &publish_infos[0].namespace).await?
|
||||||
|
{
|
||||||
|
publish_infos.iter_mut().for_each(|info| {
|
||||||
|
info.namespace = non_original_namespace.clone();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn select_workspace_id_for_publish_namespace<'a, E: Executor<'a, Database = Postgres>>(
|
pub async fn select_workspace_id_for_publish_namespace<'a, E: Executor<'a, Database = Postgres>>(
|
||||||
executor: E,
|
executor: E,
|
||||||
publish_namespace: &str,
|
publish_namespace: &str,
|
||||||
|
|
@ -511,8 +556,8 @@ pub async fn select_workspace_id_for_publish_namespace<'a, E: Executor<'a, Datab
|
||||||
let res = sqlx::query!(
|
let res = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
SELECT workspace_id
|
SELECT workspace_id
|
||||||
FROM af_workspace
|
FROM af_workspace_namespace
|
||||||
WHERE publish_namespace = $1
|
WHERE namespace = $1
|
||||||
"#,
|
"#,
|
||||||
publish_namespace,
|
publish_namespace,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1053,159 +1053,13 @@ pub async fn upsert_workspace_settings(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub async fn select_workspace_publish_namespace_exists<'a, E: Executor<'a, Database = Postgres>>(
|
|
||||||
executor: E,
|
|
||||||
workspace_id: &Uuid,
|
|
||||||
namespace: &str,
|
|
||||||
) -> Result<bool, AppError> {
|
|
||||||
let res = sqlx::query_scalar!(
|
|
||||||
r#"
|
|
||||||
SELECT EXISTS(
|
|
||||||
SELECT 1
|
|
||||||
FROM af_workspace
|
|
||||||
WHERE workspace_id = $1
|
|
||||||
AND publish_namespace = $2
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
workspace_id,
|
|
||||||
namespace,
|
|
||||||
)
|
|
||||||
.fetch_one(executor)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(res.unwrap_or(false))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub async fn update_workspace_publish_namespace<'a, E: Executor<'a, Database = Postgres>>(
|
|
||||||
executor: E,
|
|
||||||
workspace_id: &Uuid,
|
|
||||||
new_namespace: &str,
|
|
||||||
) -> Result<(), AppError> {
|
|
||||||
let res = sqlx::query!(
|
|
||||||
r#"
|
|
||||||
UPDATE af_workspace
|
|
||||||
SET publish_namespace = $1
|
|
||||||
WHERE workspace_id = $2
|
|
||||||
"#,
|
|
||||||
new_namespace,
|
|
||||||
workspace_id,
|
|
||||||
)
|
|
||||||
.execute(executor)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if res.rows_affected() != 1 {
|
|
||||||
tracing::error!(
|
|
||||||
"Failed to update workspace publish namespace, workspace_id: {}, new_namespace: {}, rows_affected: {}",
|
|
||||||
workspace_id, new_namespace, res.rows_affected()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub async fn select_workspace_publish_namespace<'a, E: Executor<'a, Database = Postgres>>(
|
|
||||||
executor: E,
|
|
||||||
workspace_id: &Uuid,
|
|
||||||
) -> Result<String, AppError> {
|
|
||||||
let res = sqlx::query_scalar!(
|
|
||||||
r#"
|
|
||||||
SELECT publish_namespace
|
|
||||||
FROM af_workspace
|
|
||||||
WHERE workspace_id = $1
|
|
||||||
"#,
|
|
||||||
workspace_id,
|
|
||||||
)
|
|
||||||
.fetch_one(executor)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub async fn select_publish_collab_meta<'a, E: Executor<'a, Database = Postgres>>(
|
|
||||||
executor: E,
|
|
||||||
publish_namespace: &str,
|
|
||||||
publish_name: &str,
|
|
||||||
) -> Result<serde_json::Value, AppError> {
|
|
||||||
let res = sqlx::query!(
|
|
||||||
r#"
|
|
||||||
SELECT metadata
|
|
||||||
FROM af_published_collab
|
|
||||||
WHERE workspace_id = (SELECT workspace_id FROM af_workspace WHERE publish_namespace = $1)
|
|
||||||
AND publish_name = $2
|
|
||||||
"#,
|
|
||||||
publish_namespace,
|
|
||||||
publish_name,
|
|
||||||
)
|
|
||||||
.fetch_one(executor)
|
|
||||||
.await?;
|
|
||||||
let metadata: serde_json::Value = res.metadata;
|
|
||||||
Ok(metadata)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub async fn delete_published_collabs<'a, E: Executor<'a, Database = Postgres>>(
|
|
||||||
executor: E,
|
|
||||||
workspace_id: &Uuid,
|
|
||||||
view_ids: &[Uuid],
|
|
||||||
) -> Result<(), AppError> {
|
|
||||||
let res = sqlx::query!(
|
|
||||||
r#"
|
|
||||||
DELETE FROM af_published_collab
|
|
||||||
WHERE workspace_id = $1
|
|
||||||
AND view_id = ANY($2)
|
|
||||||
"#,
|
|
||||||
workspace_id,
|
|
||||||
view_ids,
|
|
||||||
)
|
|
||||||
.execute(executor)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if res.rows_affected() != view_ids.len() as u64 {
|
|
||||||
tracing::error!(
|
|
||||||
"Failed to delete published collabs, workspace_id: {}, view_ids: {:?}, rows_affected: {}",
|
|
||||||
workspace_id,
|
|
||||||
view_ids,
|
|
||||||
res.rows_affected()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub async fn select_published_collab_blob<'a, E: Executor<'a, Database = Postgres>>(
|
|
||||||
executor: E,
|
|
||||||
publish_namespace: &str,
|
|
||||||
publish_name: &str,
|
|
||||||
) -> Result<Vec<u8>, AppError> {
|
|
||||||
let res = sqlx::query_scalar!(
|
|
||||||
r#"
|
|
||||||
SELECT blob
|
|
||||||
FROM af_published_collab
|
|
||||||
WHERE workspace_id = (SELECT workspace_id FROM af_workspace WHERE publish_namespace = $1)
|
|
||||||
AND publish_name = $2
|
|
||||||
"#,
|
|
||||||
publish_namespace,
|
|
||||||
publish_name,
|
|
||||||
)
|
|
||||||
.fetch_one(executor)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn select_owner_of_published_collab<'a, E: Executor<'a, Database = Postgres>>(
|
pub async fn select_owner_of_published_collab<'a, E: Executor<'a, Database = Postgres>>(
|
||||||
executor: E,
|
executor: E,
|
||||||
view_id: &Uuid,
|
view_id: &Uuid,
|
||||||
) -> Result<Uuid, AppError> {
|
) -> Result<Uuid, AppError> {
|
||||||
let res = sqlx::query!(
|
let res = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
SELECT
|
SELECT af.uuid
|
||||||
af.uuid
|
|
||||||
FROM af_published_collab apc
|
FROM af_published_collab apc
|
||||||
JOIN af_user af ON af.uid = apc.published_by
|
JOIN af_user af ON af.uid = apc.published_by
|
||||||
WHERE view_id = $1
|
WHERE view_id = $1
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ ALTER TABLE af_workspace DROP CONSTRAINT af_workspace_publish_namespace_key;
|
||||||
|
|
||||||
-- Table to store user defined namespace for workspace
|
-- Table to store user defined namespace for workspace
|
||||||
CREATE TABLE IF NOT EXISTS af_workspace_namespace (
|
CREATE TABLE IF NOT EXISTS af_workspace_namespace (
|
||||||
namespace TEXT NOT NULL PRIMARY KEY,
|
namespace TEXT NOT NULL PRIMARY KEY,
|
||||||
workspace_id UUID NOT NULL,
|
workspace_id UUID NOT NULL,
|
||||||
is_original BOOLEAN NOT NULL,
|
default_view_id UUID,
|
||||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
FOREIGN KEY (workspace_id) REFERENCES af_workspace (workspace_id) ON DELETE CASCADE
|
FOREIGN KEY (workspace_id) REFERENCES af_workspace (workspace_id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1190,9 +1190,17 @@ async fn put_publish_namespace_handler(
|
||||||
.workspace_access_control
|
.workspace_access_control
|
||||||
.enforce_role(&uid, &workspace_id.to_string(), AFRole::Owner)
|
.enforce_role(&uid, &workspace_id.to_string(), AFRole::Owner)
|
||||||
.await?;
|
.await?;
|
||||||
let new_namespace = payload.into_inner().new_namespace;
|
let UpdatePublishNamespace {
|
||||||
biz::workspace::publish::set_workspace_namespace(&state.pg_pool, &workspace_id, &new_namespace)
|
old_namespace,
|
||||||
.await?;
|
new_namespace,
|
||||||
|
} = payload.into_inner();
|
||||||
|
biz::workspace::publish::set_workspace_namespace(
|
||||||
|
&state.pg_pool,
|
||||||
|
&workspace_id,
|
||||||
|
&old_namespace,
|
||||||
|
&new_namespace,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
Ok(Json(AppResponse::Ok()))
|
Ok(Json(AppResponse::Ok()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@ use database::{
|
||||||
collab::GetCollabOrigin,
|
collab::GetCollabOrigin,
|
||||||
publish::{
|
publish::{
|
||||||
select_all_published_collab_info, select_default_published_view_id,
|
select_all_published_collab_info, select_default_published_view_id,
|
||||||
select_default_published_view_id_for_namespace, update_published_collabs,
|
select_default_published_view_id_for_namespace, select_workspace_publish_namespaces,
|
||||||
update_workspace_default_publish_view, update_workspace_default_publish_view_set_null,
|
update_published_collabs, update_workspace_default_publish_view,
|
||||||
|
update_workspace_default_publish_view_set_null,
|
||||||
},
|
},
|
||||||
workspace::{select_publish_name_exists, select_view_id_from_publish_name},
|
workspace::{select_publish_name_exists, select_view_id_from_publish_name},
|
||||||
};
|
};
|
||||||
|
|
@ -29,8 +30,7 @@ use database::{
|
||||||
select_published_collab_blob, select_published_collab_info,
|
select_published_collab_blob, select_published_collab_info,
|
||||||
select_published_collab_workspace_view_id, select_published_data_for_view_id,
|
select_published_collab_workspace_view_id, select_published_data_for_view_id,
|
||||||
select_published_metadata_for_view_id, select_user_is_collab_publisher_for_all_views,
|
select_published_metadata_for_view_id, select_user_is_collab_publisher_for_all_views,
|
||||||
select_workspace_publish_namespace, select_workspace_publish_namespace_exists,
|
select_workspace_publish_namespace_exists, update_non_orginal_workspace_publish_namespace,
|
||||||
update_workspace_publish_namespace,
|
|
||||||
},
|
},
|
||||||
workspace::select_user_is_workspace_owner,
|
workspace::select_user_is_workspace_owner,
|
||||||
};
|
};
|
||||||
|
|
@ -88,6 +88,7 @@ fn get_collab_s3_key(workspace_id: &Uuid, view_id: &Uuid) -> String {
|
||||||
pub async fn set_workspace_namespace(
|
pub async fn set_workspace_namespace(
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
|
old_namespace: &str,
|
||||||
new_namespace: &str,
|
new_namespace: &str,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
check_workspace_namespace(new_namespace).await?;
|
check_workspace_namespace(new_namespace).await?;
|
||||||
|
|
@ -96,7 +97,13 @@ pub async fn set_workspace_namespace(
|
||||||
"publish namespace is already taken".to_string(),
|
"publish namespace is already taken".to_string(),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
update_workspace_publish_namespace(pg_pool, workspace_id, new_namespace).await?;
|
update_non_orginal_workspace_publish_namespace(
|
||||||
|
pg_pool,
|
||||||
|
workspace_id,
|
||||||
|
old_namespace,
|
||||||
|
new_namespace,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,7 +172,25 @@ 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> {
|
||||||
select_workspace_publish_namespace(pg_pool, workspace_id).await
|
let mut ws_namespaces = select_workspace_publish_namespaces(pg_pool, workspace_id).await?;
|
||||||
|
match ws_namespaces.len() {
|
||||||
|
0 => Err(AppError::RecordNotFound(format!(
|
||||||
|
"No publish namespace found for workspace_id: {}",
|
||||||
|
workspace_id
|
||||||
|
))),
|
||||||
|
1 => Ok(ws_namespaces.remove(0).namespace),
|
||||||
|
_ => {
|
||||||
|
for ws_namespace in ws_namespaces {
|
||||||
|
if !ws_namespace.is_original {
|
||||||
|
return Ok(ws_namespace.namespace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(AppError::RecordNotFound(format!(
|
||||||
|
"Cannot find non-original publish namespace for workspace_id: {}",
|
||||||
|
workspace_id
|
||||||
|
)))
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_collab_publish_info(
|
pub async fn list_collab_publish_info(
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ async fn test_set_publish_namespace_set() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let namespace = uuid::Uuid::new_v4().to_string();
|
let new_namespace = uuid::Uuid::new_v4().to_string();
|
||||||
c.set_workspace_publish_namespace(&workspace_id.to_string(), &namespace)
|
c.set_workspace_publish_namespace(&workspace_id.to_string(), new_namespace.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ async fn test_set_publish_namespace_set() {
|
||||||
let (c2, _user) = generate_unique_registered_user_client().await;
|
let (c2, _user) = generate_unique_registered_user_client().await;
|
||||||
let workspace_id_2 = get_first_workspace_string(&c2).await;
|
let workspace_id_2 = get_first_workspace_string(&c2).await;
|
||||||
let err = c2
|
let err = c2
|
||||||
.set_workspace_publish_namespace(&workspace_id_2.to_string(), &namespace)
|
.set_workspace_publish_namespace(&workspace_id_2.to_string(), new_namespace.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
@ -63,7 +63,7 @@ async fn test_set_publish_namespace_set() {
|
||||||
{
|
{
|
||||||
// cannot set the same namespace
|
// cannot set the same namespace
|
||||||
let err = c
|
let err = c
|
||||||
.set_workspace_publish_namespace(&workspace_id.to_string(), &namespace)
|
.set_workspace_publish_namespace(&workspace_id.to_string(), new_namespace.clone())
|
||||||
.await
|
.await
|
||||||
.err()
|
.err()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -74,10 +74,10 @@ async fn test_set_publish_namespace_set() {
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
let new_namespace_2 = uuid::Uuid::new_v4().to_string();
|
||||||
{
|
{
|
||||||
// can replace the namespace
|
// can replace the namespace
|
||||||
let namespace = uuid::Uuid::new_v4().to_string();
|
c.set_workspace_publish_namespace(&workspace_id.to_string(), new_namespace_2.clone())
|
||||||
c.set_workspace_publish_namespace(&workspace_id.to_string(), &namespace)
|
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
@ -85,12 +85,12 @@ async fn test_set_publish_namespace_set() {
|
||||||
.get_workspace_publish_namespace(&workspace_id.to_string())
|
.get_workspace_publish_namespace(&workspace_id.to_string())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(got_namespace, namespace);
|
assert_eq!(got_namespace, new_namespace_2);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// cannot set namespace with invalid chars
|
// cannot set namespace with invalid chars
|
||||||
let err = c
|
let err = c
|
||||||
.set_workspace_publish_namespace(&workspace_id.to_string(), "/|(*&)(&#@!") // invalid chars
|
.set_workspace_publish_namespace(&workspace_id.to_string(), "/|(*&)(&#@!".to_string()) // invalid chars
|
||||||
.await
|
.await
|
||||||
.err()
|
.err()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -108,7 +108,7 @@ async fn test_publish_doc() {
|
||||||
let (c, _user) = generate_unique_registered_user_client().await;
|
let (c, _user) = generate_unique_registered_user_client().await;
|
||||||
let workspace_id = get_first_workspace_string(&c).await;
|
let workspace_id = get_first_workspace_string(&c).await;
|
||||||
let my_namespace = uuid::Uuid::new_v4().to_string();
|
let my_namespace = uuid::Uuid::new_v4().to_string();
|
||||||
c.set_workspace_publish_namespace(&workspace_id.to_string(), &my_namespace)
|
c.set_workspace_publish_namespace(&workspace_id.to_string(), my_namespace.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
@ -239,7 +239,7 @@ async fn test_publish_doc() {
|
||||||
.get_published_collab_info(&view_id_1)
|
.get_published_collab_info(&view_id_1)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(publish_info.namespace, Some(my_namespace.clone()));
|
assert_eq!(publish_info.namespace, my_namespace.clone());
|
||||||
assert_eq!(publish_info.publish_name, publish_name_1);
|
assert_eq!(publish_info.publish_name, publish_name_1);
|
||||||
assert_eq!(publish_info.view_id, view_id_1);
|
assert_eq!(publish_info.view_id, view_id_1);
|
||||||
|
|
||||||
|
|
@ -253,7 +253,7 @@ async fn test_publish_doc() {
|
||||||
.get_published_collab_info(&view_id_2)
|
.get_published_collab_info(&view_id_2)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(publish_info.namespace, Some(my_namespace.clone()));
|
assert_eq!(publish_info.namespace, my_namespace.clone());
|
||||||
assert_eq!(publish_info.publish_name, publish_name_2);
|
assert_eq!(publish_info.publish_name, publish_name_2);
|
||||||
assert_eq!(publish_info.view_id, view_id_2);
|
assert_eq!(publish_info.view_id, view_id_2);
|
||||||
|
|
||||||
|
|
@ -457,7 +457,7 @@ async fn test_publish_comments() {
|
||||||
let workspace_id = get_first_workspace_string(&page_owner_client).await;
|
let workspace_id = get_first_workspace_string(&page_owner_client).await;
|
||||||
let published_view_namespace = uuid::Uuid::new_v4().to_string();
|
let published_view_namespace = uuid::Uuid::new_v4().to_string();
|
||||||
page_owner_client
|
page_owner_client
|
||||||
.set_workspace_publish_namespace(&workspace_id.to_string(), &published_view_namespace)
|
.set_workspace_publish_namespace(&workspace_id.to_string(), published_view_namespace)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
@ -653,7 +653,7 @@ async fn test_excessive_comment_length() {
|
||||||
let workspace_id = get_first_workspace_string(&client).await;
|
let workspace_id = get_first_workspace_string(&client).await;
|
||||||
let published_view_namespace = uuid::Uuid::new_v4().to_string();
|
let published_view_namespace = uuid::Uuid::new_v4().to_string();
|
||||||
client
|
client
|
||||||
.set_workspace_publish_namespace(&workspace_id.to_string(), &published_view_namespace)
|
.set_workspace_publish_namespace(&workspace_id.to_string(), published_view_namespace)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
@ -689,7 +689,7 @@ async fn test_publish_reactions() {
|
||||||
let workspace_id = get_first_workspace_string(&page_owner_client).await;
|
let workspace_id = get_first_workspace_string(&page_owner_client).await;
|
||||||
let published_view_namespace = uuid::Uuid::new_v4().to_string();
|
let published_view_namespace = uuid::Uuid::new_v4().to_string();
|
||||||
page_owner_client
|
page_owner_client
|
||||||
.set_workspace_publish_namespace(&workspace_id.to_string(), &published_view_namespace)
|
.set_workspace_publish_namespace(&workspace_id.to_string(), published_view_namespace)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
@ -813,7 +813,7 @@ async fn test_publish_load_test() {
|
||||||
let (c, _user) = generate_unique_registered_user_client().await;
|
let (c, _user) = generate_unique_registered_user_client().await;
|
||||||
let workspace_id = get_first_workspace_string(&c).await;
|
let workspace_id = get_first_workspace_string(&c).await;
|
||||||
let my_namespace = uuid::Uuid::new_v4().to_string();
|
let my_namespace = uuid::Uuid::new_v4().to_string();
|
||||||
c.set_workspace_publish_namespace(&workspace_id.to_string(), &my_namespace)
|
c.set_workspace_publish_namespace(&workspace_id.to_string(), my_namespace)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ async fn test_template_crud() {
|
||||||
let workspace_id = get_first_workspace_string(&authorized_client).await;
|
let workspace_id = get_first_workspace_string(&authorized_client).await;
|
||||||
let published_view_namespace = uuid::Uuid::new_v4().to_string();
|
let published_view_namespace = uuid::Uuid::new_v4().to_string();
|
||||||
authorized_client
|
authorized_client
|
||||||
.set_workspace_publish_namespace(&workspace_id.to_string(), &published_view_namespace)
|
.set_workspace_publish_namespace(&workspace_id.to_string(), published_view_namespace.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let published_view_ids: Vec<Uuid> = (0..4).map(|_| Uuid::new_v4()).collect();
|
let published_view_ids: Vec<Uuid> = (0..4).map(|_| Uuid::new_v4()).collect();
|
||||||
|
|
@ -362,13 +362,8 @@ async fn test_template_crud() {
|
||||||
assert!(view_ids.contains(&published_view_ids[2]));
|
assert!(view_ids.contains(&published_view_ids[2]));
|
||||||
assert!(view_ids.contains(&published_view_ids[3]));
|
assert!(view_ids.contains(&published_view_ids[3]));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
templates[0]
|
templates[0].publish_info.namespace,
|
||||||
.publish_info
|
published_view_namespace
|
||||||
.namespace
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.to_string(),
|
|
||||||
published_view_namespace.clone()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let featured_templates = guest_client
|
let featured_templates = guest_client
|
||||||
|
|
@ -408,7 +403,7 @@ async fn test_template_crud() {
|
||||||
published_view_ids[0]
|
published_view_ids[0]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
template.publish_info.namespace.unwrap(),
|
template.publish_info.namespace,
|
||||||
published_view_namespace.clone()
|
published_view_namespace.clone()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue