chore: stop writing to af_collab_member

This commit is contained in:
khorshuheng 2024-12-11 11:54:34 +08:00
parent af38efe6d9
commit c1c5bf7420
13 changed files with 40 additions and 333 deletions

View file

@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT rp.permission_id\n FROM af_role_permissions rp\n JOIN af_roles ON rp.role_id = af_roles.id\n WHERE af_roles.name = 'Owner';\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "permission_id",
"type_info": "Int4"
}
],
"parameters": {
"Left": []
},
"nullable": [
false
]
},
"hash": "711debcb02d19b1de4ff7dfcf77c2a431c9fe83ffd362d41b7f0f14a2f241d4b"
}

View file

@ -1,19 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "CALL af_collab_upsert($1, $2, $3, $4, $5, $6)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Text",
"Int4",
"Int8",
"Int4",
"Bytea"
]
},
"nullable": []
},
"hash": "7e413ca3430f3270e9f903c8bc2151a5f354cd951c20dbd6261d65dbdb503cbc"
}

View file

@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n WITH workspace_check AS (\n SELECT EXISTS(\n SELECT 1\n FROM af_workspace_member\n WHERE af_workspace_member.uid = (SELECT uid FROM af_user WHERE uuid = $1) AND\n af_workspace_member.workspace_id = $3\n ) AS \"workspace_exists\"\n ),\n collab_check AS (\n SELECT EXISTS(\n SELECT 1\n FROM af_collab_member\n WHERE oid = $2\n ) AS \"collab_exists\"\n )\n SELECT\n NOT collab_check.collab_exists OR (\n workspace_check.workspace_exists AND\n EXISTS(\n SELECT 1\n FROM af_collab_member\n JOIN af_permissions ON af_collab_member.permission_id = af_permissions.id\n WHERE\n af_collab_member.uid = (SELECT uid FROM af_user WHERE uuid = $1) AND\n af_collab_member.oid = $2 AND\n af_permissions.access_level > 20\n )\n ) AS \"permission_check\"\n FROM workspace_check, collab_check;\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "permission_check",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Uuid",
"Text",
"Uuid"
]
},
"nullable": [
null
]
},
"hash": "a6b4725375e940cacdcc622b5288a38253db8bd48ba0774344d20fb6957f9ca6"
}

View file

@ -0,0 +1,20 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO af_collab (oid, blob, len, partition_key, encrypt, owner_uid, workspace_id)\n VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT (oid, partition_key)\n DO UPDATE SET blob = $2, len = $3, encrypt = $5, owner_uid = $6 WHERE excluded.workspace_id = af_collab.workspace_id;\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Bytea",
"Int4",
"Int4",
"Int4",
"Int8",
"Uuid"
]
},
"nullable": []
},
"hash": "c62e3c19160fdbcf2ef7bc2c85ec012f628d593c8b2eba5e6ef3ba313045a696"
}

View file

@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO af_collab_member (uid, oid, permission_id)\n SELECT * FROM UNNEST($1::bigint[], $2::uuid[], $3::int[])\n ON CONFLICT (uid, oid)\n DO NOTHING;\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8Array",
"UuidArray",
"Int4Array"
]
},
"nullable": []
},
"hash": "ceaa58cd92cd2a4c554c2a57fee11fbfd0bdb2b0e1b777d8533ae7c37d3b69e2"
}

View file

@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n WITH ins_user AS (\n INSERT INTO af_user (uid, uuid, email, name)\n VALUES ($1, $2, $3, $4)\n RETURNING uid\n ),\n owner_role AS (\n SELECT id FROM af_roles WHERE name = 'Owner'\n ),\n ins_workspace AS (\n INSERT INTO af_workspace (owner_uid)\n SELECT uid FROM ins_user\n RETURNING workspace_id, owner_uid\n ),\n ins_collab_member AS (\n INSERT INTO af_collab_member (uid, oid, permission_id)\n SELECT ins_workspace.owner_uid,\n ins_workspace.workspace_id::TEXT,\n (SELECT permission_id FROM af_role_permissions WHERE role_id = owner_role.id)\n FROM ins_workspace, owner_role\n )\n SELECT workspace_id FROM ins_workspace;\n ",
"query": "\n WITH ins_user AS (\n INSERT INTO af_user (uid, uuid, email, name)\n VALUES ($1, $2, $3, $4)\n RETURNING uid\n ),\n owner_role AS (\n SELECT id FROM af_roles WHERE name = 'Owner'\n ),\n ins_workspace AS (\n INSERT INTO af_workspace (owner_uid)\n SELECT uid FROM ins_user\n RETURNING workspace_id, owner_uid\n )\n SELECT workspace_id FROM ins_workspace;\n ",
"describe": {
"columns": [
{
@ -21,5 +21,5 @@
false
]
},
"hash": "ce3b2a3ddee0f420166719e39e0e4befa495bb6438ef88be860fa1e557bf9281"
"hash": "e2b4d66736962d1e3d0b9cf687ce5c5e653b465462f53433a28cf314e5c87d6c"
}

View file

@ -1,32 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT uid, oid, access_level\n FROM af_collab_member\n INNER JOIN af_permissions\n ON af_collab_member.permission_id = af_permissions.id\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "uid",
"type_info": "Int8"
},
{
"ordinal": 1,
"name": "oid",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "access_level",
"type_info": "Int4"
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
false,
false
]
},
"hash": "f1b56cf92eeb5f7ddda80876c1ecf5b6a5357a58d18b9bf6f14e6a2261bd1182"
}

View file

@ -7,11 +7,10 @@ use database_entity::dto::{
use shared_entity::dto::workspace_dto::DatabaseRowUpdatedItem;
use crate::collab::{partition_key_from_collab_type, SNAPSHOT_PER_HOUR};
use crate::pg_row::AFCollabRowMeta;
use crate::pg_row::AFSnapshotRow;
use crate::pg_row::{AFCollabMemberAccessLevelRow, AFCollabRowMeta};
use app_error::AppError;
use chrono::{DateTime, Duration, Utc};
use futures_util::stream::BoxStream;
use sqlx::postgres::PgRow;
use sqlx::{Error, Executor, PgPool, Postgres, Row, Transaction};
@ -61,24 +60,24 @@ pub async fn insert_into_af_collab(
);
sqlx::query!(
r#"CALL af_collab_upsert($1, $2, $3, $4, $5, $6)"#,
workspace_id,
r#"
INSERT INTO af_collab (oid, blob, len, partition_key, encrypt, owner_uid, workspace_id)
VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT (oid, partition_key)
DO UPDATE SET blob = $2, len = $3, encrypt = $5, owner_uid = $6 WHERE excluded.workspace_id = af_collab.workspace_id;
"#,
params.object_id,
partition_key,
*uid,
encrypt,
params.encoded_collab_v1.as_ref(),
params.encoded_collab_v1.len() as i32,
partition_key,
encrypt,
uid,
workspace_id,
)
.execute(tx.deref_mut())
.await
.map_err(|err| {
.await.map_err(|err| {
AppError::Internal(anyhow!(
"Update af_collab failed: workspace_id:{}, uid:{}, object_id:{}, collab_type:{}. error: {:?}",
workspace_id,
uid,
params.object_id,
params.collab_type,
err,
workspace_id, uid, params.object_id, params.collab_type, err,
))
})?;
@ -154,25 +153,12 @@ pub async fn insert_into_af_collab_bulk_for_user(
let encrypt = 0;
let workspace_uuid = Uuid::from_str(workspace_id)?;
// Insert values into the `af_collab_member` and `af_collab` tables in bulk
// Insert values into `af_collab` tables in bulk
let len = collab_params_list.len();
let mut object_ids: Vec<Uuid> = Vec::with_capacity(len);
let mut blobs: Vec<Vec<u8>> = Vec::with_capacity(len);
let mut lengths: Vec<i32> = Vec::with_capacity(len);
let mut partition_keys: Vec<i32> = Vec::with_capacity(len);
let mut permission_ids: Vec<i32> = Vec::with_capacity(len);
let permission_id: i32 = sqlx::query_scalar!(
r#"
SELECT rp.permission_id
FROM af_role_permissions rp
JOIN af_roles ON rp.role_id = af_roles.id
WHERE af_roles.name = 'Owner';
"#
)
.fetch_one(tx.deref_mut())
.await?;
let mut visited = HashSet::with_capacity(collab_params_list.len());
for params in collab_params_list {
let oid = Uuid::from_str(&params.object_id)?;
@ -182,7 +168,6 @@ pub async fn insert_into_af_collab_bulk_for_user(
blobs.push(params.encoded_collab_v1.to_vec());
lengths.push(params.encoded_collab_v1.len() as i32);
partition_keys.push(partition_key);
permission_ids.push(permission_id);
}
}
@ -214,28 +199,6 @@ pub async fn insert_into_af_collab_bulk_for_user(
))
})?;
// Bulk insert into `af_collab_member` for the user and provided collab params
sqlx::query!(
r#"
INSERT INTO af_collab_member (uid, oid, permission_id)
SELECT * FROM UNNEST($1::bigint[], $2::uuid[], $3::int[])
ON CONFLICT (uid, oid)
DO NOTHING;
"#,
&uids,
&object_ids,
&permission_ids
)
.execute(tx.deref_mut())
.await
.map_err(|err| {
AppError::Internal(anyhow!(
"Bulk insert/update into af_collab_member failed for uid: {}, error details: {:?}",
uid,
err
))
})?;
Ok(())
}
@ -571,21 +534,6 @@ pub async fn delete_collab_member(
Ok(())
}
pub fn select_collab_member_access_level(
pg_pool: &PgPool,
) -> BoxStream<'_, sqlx::Result<AFCollabMemberAccessLevelRow>> {
sqlx::query_as!(
AFCollabMemberAccessLevelRow,
r#"
SELECT uid, oid, access_level
FROM af_collab_member
INNER JOIN af_permissions
ON af_collab_member.permission_id = af_permissions.id
"#
)
.fetch(pg_pool)
}
#[inline]
pub async fn select_collab_members(
oid: &str,

View file

@ -130,13 +130,6 @@ pub async fn create_user<'a, E: Executor<'a, Database = Postgres>>(
INSERT INTO af_workspace (owner_uid)
SELECT uid FROM ins_user
RETURNING workspace_id, owner_uid
),
ins_collab_member AS (
INSERT INTO af_collab_member (uid, oid, permission_id)
SELECT ins_workspace.owner_uid,
ins_workspace.workspace_id::TEXT,
(SELECT permission_id FROM af_role_permissions WHERE role_id = owner_role.id)
FROM ins_workspace, owner_role
)
SELECT workspace_id FROM ins_workspace;
"#,

View file

@ -210,60 +210,6 @@ pub async fn select_user_role<'a, E: Executor<'a, Database = Postgres>>(
Ok(AFRole::from(row))
}
/// Checks the user's permission to edit a collab object.
/// user can edit collab if:
/// 1. user is the member of the workspace
/// 2. the collab object is not exist
/// 3. the collab object is exist and the user is the member of the collab and the role is owner or member
#[allow(dead_code)]
pub async fn select_user_can_edit_collab(
pg_pool: &PgPool,
user_uuid: &Uuid,
workspace_id: &Uuid,
object_id: &str,
) -> Result<bool, AppError> {
let permission_check = sqlx::query_scalar!(
r#"
WITH workspace_check AS (
SELECT EXISTS(
SELECT 1
FROM af_workspace_member
WHERE af_workspace_member.uid = (SELECT uid FROM af_user WHERE uuid = $1) AND
af_workspace_member.workspace_id = $3
) AS "workspace_exists"
),
collab_check AS (
SELECT EXISTS(
SELECT 1
FROM af_collab_member
WHERE oid = $2
) AS "collab_exists"
)
SELECT
NOT collab_check.collab_exists OR (
workspace_check.workspace_exists AND
EXISTS(
SELECT 1
FROM af_collab_member
JOIN af_permissions ON af_collab_member.permission_id = af_permissions.id
WHERE
af_collab_member.uid = (SELECT uid FROM af_user WHERE uuid = $1) AND
af_collab_member.oid = $2 AND
af_permissions.access_level > 20
)
) AS "permission_check"
FROM workspace_check, collab_check;
"#,
user_uuid,
object_id,
workspace_id,
)
.fetch_one(pg_pool)
.await?;
Ok(permission_check.unwrap_or(false))
}
#[inline]
pub async fn upsert_workspace_member_with_txn(
txn: &mut Transaction<'_, sqlx::Postgres>,

View file

@ -0,0 +1 @@
DROP PROCEDURE IF EXISTS af_collab_upsert

View file

@ -8,37 +8,6 @@ use database_entity::dto::{
};
use uuid::Uuid;
#[tokio::test]
async fn collab_owner_permission_test() {
let (c, _user) = generate_unique_registered_user_client().await;
let workspace_id = workspace_id_from_client(&c).await;
let object_id = Uuid::new_v4().to_string();
let uid = c.get_profile().await.unwrap().uid;
let encode_collab = test_encode_collab_v1(&object_id, "title", "hello world")
.encode_to_bytes()
.unwrap();
c.create_collab(CreateCollabParams {
object_id: object_id.clone(),
encoded_collab_v1: encode_collab,
collab_type: CollabType::Unknown,
workspace_id: workspace_id.clone(),
})
.await
.unwrap();
let member = c
.get_collab_member(WorkspaceCollabIdentify {
uid,
object_id,
workspace_id,
})
.await
.unwrap();
assert_eq!(member.permission.access_level, AFAccessLevel::FullAccess);
}
#[tokio::test]
async fn update_collab_member_permission_test() {
let (c, _user) = generate_unique_registered_user_client().await;
@ -163,7 +132,7 @@ async fn add_collab_member_then_remove_test() {
.await
.unwrap()
.0;
assert_eq!(members.len(), 2);
assert_eq!(members.len(), 1);
// Delete the member
c_1
@ -182,5 +151,5 @@ async fn add_collab_member_then_remove_test() {
.await
.unwrap()
.0;
assert_eq!(members.len(), 1);
assert_eq!(members.len(), 0);
}

View file

@ -1,7 +1,7 @@
use app_error::ErrorCode;
use client_api::entity::AFWorkspaceInvitationStatus;
use client_api_test::{api_client_with_email, TestClient};
use database_entity::dto::{AFAccessLevel, AFRole, QueryCollabMembers};
use database_entity::dto::AFRole;
use shared_entity::dto::workspace_dto::WorkspaceMemberInvitation;
#[tokio::test]
@ -9,7 +9,6 @@ async fn get_workspace_owner_after_sign_up_test() {
let c1 = TestClient::new_user_without_ws_conn().await;
let workspace_id = c1.workspace_id().await;
// after the user sign up, the user should be the owner of the workspace
let members = c1
.api_client
.get_workspace_members(&workspace_id)
@ -17,22 +16,6 @@ async fn get_workspace_owner_after_sign_up_test() {
.unwrap();
assert_eq!(members.len(), 1);
assert_eq!(members[0].email, c1.email().await);
// after user sign up, the user should have full access to the workspace
let collab_members = c1
.api_client
.get_collab_members(QueryCollabMembers {
workspace_id: workspace_id.clone(),
object_id: workspace_id.clone(),
})
.await
.unwrap()
.0;
assert_eq!(collab_members.len(), 1);
assert_eq!(
collab_members[0].permission.access_level,
AFAccessLevel::FullAccess
);
}
#[tokio::test]
@ -254,48 +237,6 @@ async fn workspace_add_member() {
assert_eq!(members[3].email, guest.email().await);
assert_eq!(members[3].role, AFRole::Guest);
// after adding the members to the workspace, we should be able to get the collab members
// of the workspace.
let collab_members = owner
.api_client
.get_collab_members(QueryCollabMembers {
workspace_id: workspace_id.clone(),
object_id: workspace_id.clone(),
})
.await
.unwrap()
.0;
assert_eq!(collab_members.len(), 4);
// owner
assert_eq!(collab_members[0].uid, owner.uid().await);
assert_eq!(
collab_members[0].permission.access_level,
AFAccessLevel::FullAccess
);
// other owner
assert_eq!(collab_members[1].uid, other_owner.uid().await);
assert_eq!(
collab_members[1].permission.access_level,
AFAccessLevel::FullAccess
);
// member
assert_eq!(collab_members[2].uid, member.uid().await);
assert_eq!(
collab_members[2].permission.access_level,
AFAccessLevel::ReadAndWrite
);
// guest
assert_eq!(collab_members[3].uid, guest.uid().await);
assert_eq!(
collab_members[3].permission.access_level,
AFAccessLevel::ReadOnly
);
}
#[tokio::test]