feat: use sqlx row stream to load collab policy (#217)

* feat: use sqlx row stream to load collab policy

* fix: access control object type
This commit is contained in:
Zack 2023-12-16 19:24:51 -08:00 committed by GitHub
parent 1eed034a83
commit 24ab19f2a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 115 additions and 99 deletions

View File

@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO af_collab_member (uid, oid, permission_id)\n VALUES ($1, $2, $3)\n ON CONFLICT (uid, oid)\n DO UPDATE\n SET permission_id = excluded.permission_id;\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Text",
"Int4"
]
},
"nullable": []
},
"hash": "19fd96e0183b93b1751440a2562624f2ffc9c958ed3d06b26162eb1c249c62e9"
}

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": "42d345fbdc25ad7b36d35515079e00e018e4f58a9a4ac4efbfa4768cadcc6c85"
}

View File

@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT DISTINCT af_collab_member.oid FROM af_collab_member",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "oid",
"type_info": "Text"
}
],
"parameters": {
"Left": []
},
"nullable": [
false
]
},
"hash": "8135c6a16c27a0ccbde65473a8041007ae9ef7f546fadb656a2948ffb0db8e53"
}

View File

@ -0,0 +1,32 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n 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": "9eba47895808e9968529d789a02758807486054028990fffef62fb89ac047750"
}

View File

@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": " \n INSERT INTO af_collab_member (uid, oid, permission_id)\n VALUES ($1, $2, $3)\n ON CONFLICT (uid, oid)\n DO UPDATE\n SET permission_id = excluded.permission_id;\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Text",
"Int4"
]
},
"nullable": []
},
"hash": "c5ba2a6febad1655b75eecad9d088694a6f0f93a84c32a0228a7cfd1a6f063f1"
}

View File

@ -0,0 +1,20 @@
{
"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": "d6708c221831093b03524bd6b73974f6f41db00b5f58f47ad7180d068e273406"
}

View File

@ -62,6 +62,13 @@ pub struct AFWorkspaceMemberRow {
pub role: AFRole,
}
#[derive(FromRow)]
pub struct AFCollabMemerAccessLevelRow {
pub uid: i64,
pub oid: String,
pub access_level: AFAccessLevel,
}
#[derive(FromRow, Clone, Debug, Serialize, Deserialize)]
pub struct AFCollabMemberRow {
pub uid: i64,

View File

@ -5,7 +5,10 @@ use database_entity::dto::{
BatchQueryCollab, InsertCollabParams, QueryCollabResult, RawData,
};
use database_entity::pg_row::AFCollabMemerAccessLevelRow;
use app_error::AppError;
use futures_util::stream::BoxStream;
use sqlx::postgres::PgRow;
use sqlx::{Error, Executor, PgPool, Postgres, Row, Transaction};
use std::collections::HashMap;
@ -101,7 +104,7 @@ pub async fn insert_into_af_collab(
// Get the permission_id of the Owner
let permission_id: i32 = sqlx::query_scalar!(
r#"
SELECT rp.permission_id
SELECT rp.permission_id
FROM af_role_permissions rp
JOIN af_roles ON rp.role_id = af_roles.id
WHERE af_roles.name = 'Owner';
@ -340,7 +343,7 @@ pub async fn upsert_collab_member_with_txn<T: AsRef<str> + Debug>(
.context("Get permission id from access level fail")?;
sqlx::query!(
r#"
r#"
INSERT INTO af_collab_member (uid, oid, permission_id)
VALUES ($1, $2, $3)
ON CONFLICT (uid, oid)
@ -382,24 +385,20 @@ pub async fn delete_collab_member(uid: i64, oid: &str, pg_pool: &PgPool) -> Resu
Ok(())
}
#[instrument(level = "info", skip_all, err)]
pub async fn select_all_collab_members(
pub fn select_collab_member_access_level(
pg_pool: &PgPool,
) -> Result<Vec<(String, Vec<AFCollabMember>)>, AppError> {
let collabs: Vec<_> = sqlx::query!("SELECT DISTINCT af_collab_member.oid FROM af_collab_member")
.fetch_all(pg_pool)
.await?
.into_iter()
.map(|r| r.oid)
.collect();
let mut collab_members = Vec::with_capacity(collabs.len());
for oid in collabs {
let members = select_collab_members(&oid, pg_pool).await?;
collab_members.push((oid, members));
}
Ok(collab_members)
) -> BoxStream<'_, sqlx::Result<AFCollabMemerAccessLevelRow>> {
sqlx::query_as!(
AFCollabMemerAccessLevelRow,
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]

View File

@ -242,13 +242,12 @@ pub async fn delete_workspace_members(
pub fn select_workspace_member_perm_stream(
pg_pool: &PgPool,
) -> Result<BoxStream<'_, sqlx::Result<AFWorkspaceMemberPermRow>>, AppError> {
let stream = sqlx::query_as!(
) -> BoxStream<'_, sqlx::Result<AFWorkspaceMemberPermRow>> {
sqlx::query_as!(
AFWorkspaceMemberPermRow,
"SELECT uid, role_id as role, workspace_id FROM af_workspace_member"
)
.fetch(pg_pool);
Ok(stream)
.fetch(pg_pool)
}
/// returns a list of workspace members, sorted by their creation time.

View File

@ -5,10 +5,10 @@ use casbin::Adapter;
use casbin::Filter;
use casbin::Model;
use casbin::Result;
use database::collab::select_all_collab_members;
use database::collab::select_collab_member_access_level;
use database::workspace::select_workspace_member_perm_stream;
use database_entity::dto::AFAccessLevel;
use database_entity::dto::AFCollabMember;
use database_entity::pg_row::AFCollabMemerAccessLevelRow;
use database_entity::pg_row::AFWorkspaceMemberPermRow;
use futures_util::stream::BoxStream;
use sqlx::PgPool;
@ -26,21 +26,23 @@ impl PgAdapter {
}
}
fn create_collab_policies(collab_members: Vec<(String, Vec<AFCollabMember>)>) -> Vec<Vec<String>> {
async fn create_collab_policies(
mut stream: BoxStream<'_, sqlx::Result<AFCollabMemerAccessLevelRow>>,
) -> Result<Vec<Vec<String>>> {
let mut policies: Vec<Vec<String>> = Vec::new();
for (oid, members) in collab_members {
for m in members {
let p = [
m.uid.to_string(),
ObjectType::Collab(&oid).to_string(),
i32::from(m.permission.access_level).to_string(),
]
.to_vec();
policies.push(p);
}
while let Some(result) = stream.next().await {
let member_access_lv = result.map_err(|err| AdapterError(Box::new(err)))?;
let policy = [
member_access_lv.uid.to_string(),
ObjectType::Collab(&member_access_lv.oid).to_string(),
i32::from(member_access_lv.access_level).to_string(),
]
.to_vec();
policies.push(policy);
}
policies
Ok(policies)
}
async fn create_workspace_policies(
@ -65,18 +67,15 @@ async fn create_workspace_policies(
#[async_trait]
impl Adapter for PgAdapter {
async fn load_policy(&mut self, model: &mut dyn Model) -> Result<()> {
let workspace_member_perm_stream = select_workspace_member_perm_stream(&self.pg_pool)
.map_err(|err| AdapterError(Box::new(err)))?;
let workspace_member_perm_stream = select_workspace_member_perm_stream(&self.pg_pool);
let workspace_policies = create_workspace_policies(workspace_member_perm_stream).await?;
// Policy definition `p` of type `p`. See `model.conf`
model.add_policies("p", "p", workspace_policies);
let collab_members = select_all_collab_members(&self.pg_pool)
.await
.map_err(|err| AdapterError(Box::new(err)))?;
let collab_member_access_lv_stream = select_collab_member_access_level(&self.pg_pool);
let collab_policies = create_collab_policies(collab_member_access_lv_stream).await?;
let collab_policies = create_collab_policies(collab_members);
// Policy definition `p` of type `p`. See `model.conf`
model.add_policies("p", "p", collab_policies);