From f6b9221e30e1ecc90bca1421f1438cd1b7ff68fe Mon Sep 17 00:00:00 2001 From: ZzIsGod1019 <1498852723@qq.com> Date: Fri, 24 Nov 2023 09:52:02 +0800 Subject: [PATCH] kv: filter by own_paths (#530) * kv: filter by own_paths * kv: finish --- basic/src/rbum/helper/rbum_scope_helper.rs | 3 + spi/spi-kv/src/dto/kv_item_dto.rs | 9 +++ spi/spi-kv/src/serv/kv_item_serv.rs | 2 + spi/spi-kv/src/serv/pg/kv_pg_initializer.rs | 3 + spi/spi-kv/src/serv/pg/kv_pg_item_serv.rs | 67 ++++++++++++++++++--- spi/spi-kv/tests/test_kv_item.rs | 38 +++++++++--- 6 files changed, 105 insertions(+), 17 deletions(-) diff --git a/basic/src/rbum/helper/rbum_scope_helper.rs b/basic/src/rbum/helper/rbum_scope_helper.rs index 2cf3006fe..e6b37ae00 100644 --- a/basic/src/rbum/helper/rbum_scope_helper.rs +++ b/basic/src/rbum/helper/rbum_scope_helper.rs @@ -99,6 +99,9 @@ pub fn check_scope(record_own_paths: &str, record_scope_level: Option, filt return false; } if let Some(record_scope_level) = record_scope_level { + if record_scope_level == 0 { + return true; + } if let Some(p1) = get_pre_paths(1, filter_own_paths) { if record_scope_level == 1 { return record_own_paths.is_empty() || record_own_paths.contains(&p1); diff --git a/spi/spi-kv/src/dto/kv_item_dto.rs b/spi/spi-kv/src/dto/kv_item_dto.rs index 535cf61a2..92646813c 100644 --- a/spi/spi-kv/src/dto/kv_item_dto.rs +++ b/spi/spi-kv/src/dto/kv_item_dto.rs @@ -13,6 +13,7 @@ pub struct KvItemAddOrModifyReq { pub key: TrimString, pub value: Value, pub info: Option, + pub scope_level: Option, } #[derive(poem_openapi::Object, Serialize, Deserialize, Debug, sea_orm::FromQueryResult)] @@ -21,6 +22,9 @@ pub struct KvItemDetailResp { pub key: String, pub value: Value, pub info: String, + pub owner: String, + pub own_paths: String, + pub scope_level: i16, pub create_time: DateTime, pub update_time: DateTime, } @@ -31,6 +35,9 @@ pub struct KvItemSummaryResp { pub key: String, pub value: Value, pub info: String, + pub owner: String, + pub own_paths: String, + pub scope_level: i16, pub create_time: DateTime, pub update_time: DateTime, } @@ -54,6 +61,7 @@ pub struct KvNameAddOrModifyReq { #[oai(validator(min_length = "2"))] pub key: TrimString, pub name: String, + pub scope_level: Option, } #[derive(poem_openapi::Object, Serialize, Deserialize, Debug)] @@ -69,6 +77,7 @@ pub struct KvTagAddOrModifyReq { #[oai(validator(min_length = "2"))] pub key: TrimString, pub items: Vec, + pub scope_level: Option, } #[derive(poem_openapi::Object, Serialize, Deserialize, Debug)] diff --git a/spi/spi-kv/src/serv/kv_item_serv.rs b/spi/spi-kv/src/serv/kv_item_serv.rs index d5e225496..9ac8ef2df 100644 --- a/spi/spi-kv/src/serv/kv_item_serv.rs +++ b/spi/spi-kv/src/serv/kv_item_serv.rs @@ -35,6 +35,7 @@ pub async fn add_or_modify_key_name(add_or_modify_req: &mut KvNameAddOrModifyReq let req = KvItemAddOrModifyReq { key: format!("{}{}", kv_constants::KEY_PREFIX_BY_KEY_NAME, add_or_modify_req.key).into(), value: json!(add_or_modify_req.name), + scope_level: add_or_modify_req.scope_level, info: None, }; let inst = funs.init(ctx, true, kv_initializer::init_fun).await?; @@ -72,6 +73,7 @@ pub async fn add_or_modify_tag(add_or_modify_req: &mut KvTagAddOrModifyReq, funs let req = KvItemAddOrModifyReq { key: format!("{}{}", kv_constants::KEY_PREFIX_BY_TAG, add_or_modify_req.key).into(), value: TardisFuns::json.obj_to_json(&add_or_modify_req.items)?, + scope_level: add_or_modify_req.scope_level, info: None, }; let inst = funs.init(ctx, true, kv_initializer::init_fun).await?; diff --git a/spi/spi-kv/src/serv/pg/kv_pg_initializer.rs b/spi/spi-kv/src/serv/pg/kv_pg_initializer.rs index ea7c17b7f..93daf7c4f 100644 --- a/spi/spi-kv/src/serv/pg/kv_pg_initializer.rs +++ b/spi/spi-kv/src/serv/pg/kv_pg_initializer.rs @@ -14,6 +14,9 @@ pub async fn init_table_and_conn(bs_inst: TypedSpiBsInst<'_, TardisRelDBClient>, r#"k character varying NOT NULL PRIMARY KEY, v jsonb NOT NULL, info character varying NOT NULL, + own_paths VARCHAR(255) NULL, + owner VARCHAR(255) NULL, + scope_level SMALLINT NULL, create_time timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP"#, vec![("k", "btree"), ("v", "gin")], diff --git a/spi/spi-kv/src/serv/pg/kv_pg_item_serv.rs b/spi/spi-kv/src/serv/pg/kv_pg_item_serv.rs index 35b683c95..fa8d77a34 100644 --- a/spi/spi-kv/src/serv/pg/kv_pg_item_serv.rs +++ b/spi/spi-kv/src/serv/pg/kv_pg_item_serv.rs @@ -1,4 +1,7 @@ -use bios_basic::spi::spi_funs::{SpiBsInst, SpiBsInstExtractor}; +use bios_basic::{ + rbum::{dto::rbum_filer_dto::RbumBasicFilterReq, helper::rbum_scope_helper}, + spi::spi_funs::{SpiBsInst, SpiBsInstExtractor}, +}; use tardis::{ basic::{dto::TardisContext, result::TardisResult}, db::{reldb_client::TardisRelDBClient, sea_orm::Value}, @@ -15,21 +18,29 @@ pub async fn add_or_modify_item(add_or_modify_req: &KvItemAddOrModifyReq, _funs: Value::from(add_or_modify_req.key.to_string()), Value::from(add_or_modify_req.value.clone()), Value::from(add_or_modify_req.info.as_ref().unwrap_or(&"".to_string()).as_str()), + Value::from(ctx.owner.clone()), + Value::from(ctx.own_paths.clone()), + Value::from(add_or_modify_req.scope_level.unwrap_or(-1)), ]; let mut update_opt_fragments: Vec<&str> = Vec::new(); update_opt_fragments.push("v = $2"); if add_or_modify_req.info.is_some() { update_opt_fragments.push("info = $3"); } + update_opt_fragments.push("owner = $4"); + update_opt_fragments.push("own_paths = $5"); + if add_or_modify_req.scope_level.is_some() { + update_opt_fragments.push("scope_level = $6"); + } let bs_inst = inst.inst::(); let (mut conn, table_name) = kv_pg_initializer::init_table_and_conn(bs_inst, ctx, true).await?; conn.begin().await?; conn.execute_one( &format!( r#"INSERT INTO {} - (k, v, info) + (k, v, info, owner, own_paths, scope_level) VALUES - ($1, $2, $3) + ($1, $2, $3, $4, $5, $6) ON CONFLICT (k) DO UPDATE SET {} @@ -48,9 +59,9 @@ pub async fn get_item(key: String, extract: Option, _funs: &TardisFunsIn let bs_inst = inst.inst::(); let (conn, table_name) = kv_pg_initializer::init_table_and_conn(bs_inst, ctx, true).await?; let result = conn - .get_dto_by_sql( + .get_dto_by_sql::( &format!( - r#"SELECT k AS key, v{} AS value, info, create_time, update_time + r#"SELECT k AS key, v{} AS value, info, owner, own_paths, scope_level, create_time, update_time FROM {} WHERE k = $1"#, @@ -60,6 +71,19 @@ WHERE vec![Value::from(key)], ) .await?; + if let Some(detail) = result.as_ref() { + if !rbum_scope_helper::check_scope( + &detail.own_paths, + Some(detail.scope_level), + &RbumBasicFilterReq { + ignore_scope: false, + ..Default::default() + }, + ctx, + ) { + return Ok(None); + } + } Ok(result) } @@ -77,9 +101,9 @@ pub async fn find_items(keys: Vec, extract: Option, funs: &Tardi let bs_inst = inst_arc.inst::(); let (conn, table_name) = kv_pg_initializer::init_table_and_conn(bs_inst, ctx, true).await?; let result = conn - .find_dtos_by_sql( + .find_dtos_by_sql::( &format!( - r#"SELECT k AS key, v{} AS value, info, create_time, update_time + r#"SELECT k AS key, v{} AS value, info, owner, own_paths, scope_level, create_time, update_time FROM {} WHERE k IN ({})"#, @@ -89,7 +113,20 @@ WHERE ), sql_vals, ) - .await?; + .await? + .into_iter() + .filter(|item| { + rbum_scope_helper::check_scope( + &item.own_paths, + Some(item.scope_level), + &RbumBasicFilterReq { + ignore_scope: false, + ..Default::default() + }, + ctx, + ) + }) + .collect(); Ok(result) } @@ -141,7 +178,7 @@ pub async fn match_items(match_req: KvItemMatchReq, _funs: &TardisFunsInst, ctx: let result = conn .query_all( &format!( - r#"SELECT k, v{} AS v, info, create_time, update_time, count(*) OVER() AS total + r#"SELECT k, v{} AS v, info, owner, own_paths, scope_level, create_time, update_time, count(*) OVER() AS total FROM {} WHERE {} @@ -171,10 +208,22 @@ WHERE key: item.try_get("", "k")?, value: item.try_get("", "v")?, info: item.try_get("", "info")?, + owner: item.try_get("", "owner")?, + own_paths: item.try_get("", "own_paths")?, + scope_level: item.try_get("", "scope_level")?, create_time: item.try_get("", "create_time")?, update_time: item.try_get("", "update_time")?, }) }) + .filter(|item| item.is_ok() && rbum_scope_helper::check_scope( + &item.as_ref().expect("invalid result").own_paths, + Some(item.as_ref().expect("invalid result").scope_level), + &RbumBasicFilterReq { + ignore_scope: false, + ..Default::default() + }, + ctx, + )) .collect::>>()?; Ok(TardisPage { page_size: match_req.page_size as u64, diff --git a/spi/spi-kv/tests/test_kv_item.rs b/spi/spi-kv/tests/test_kv_item.rs index 4ab646319..330c84f68 100644 --- a/spi/spi-kv/tests/test_kv_item.rs +++ b/spi/spi-kv/tests/test_kv_item.rs @@ -9,14 +9,15 @@ use tardis::tokio::time::sleep; use tardis::web::web_resp::{TardisPage, TardisResp, Void}; pub async fn test(client: &mut TestHttpClient) -> TardisResult<()> { - client.set_auth(&TardisContext { + let mut ctx = TardisContext { own_paths: "t1/app001".to_string(), ak: "".to_string(), roles: vec![], groups: vec![], owner: "app001".to_string(), ..Default::default() - })?; + }; + client.set_auth(&ctx)?; let _: Void = client .put( @@ -29,7 +30,7 @@ pub async fn test(client: &mut TestHttpClient) -> TardisResult<()> { ) .await; - let result: KvItemDetailResp = client.get("/ci/item/?key=db:url").await; + let result: KvItemDetailResp = client.get("/ci/item?key=db:url").await; assert_eq!(result.key, "db:url"); assert_eq!(result.value, "postgres://xxxx"); assert_eq!(result.info, "xx系统的数据库地址"); @@ -83,24 +84,24 @@ pub async fn test(client: &mut TestHttpClient) -> TardisResult<()> { ) .await; - let result: KvItemDetailResp = client.get("/ci/item/?key=db_info:002").await; + let result: KvItemDetailResp = client.get("/ci/item?key=db_info:002").await; assert_eq!(result.key, "db_info:002"); assert_eq!(result.info, "002系统的数据库信息"); assert_eq!(result.value.get("url").unwrap().as_str().unwrap(), "postgres://xxxx002"); assert!(result.create_time < result.update_time); - let result: KvItemDetailResp = client.get("/ci/item/?key=db_info:002&extract=url").await; + let result: KvItemDetailResp = client.get("/ci/item?key=db_info:002&extract=url").await; assert_eq!(result.key, "db_info:002"); assert_eq!(result.info, "002系统的数据库信息"); assert_eq!(result.value.as_str().unwrap(), "postgres://xxxx002"); - let result: Vec = client.get("/ci/items/?keys=db_info:002&keys=db_info:001").await; + let result: Vec = client.get("/ci/items?keys=db_info:002&keys=db_info:001").await; assert_eq!(result.len(), 2); assert_eq!(result[1].key, "db_info:002"); assert_eq!(result[1].info, "002系统的数据库信息"); assert_eq!(result[1].value.get("url").unwrap().as_str().unwrap(), "postgres://xxxx002"); - let result: Vec = client.get("/ci/items/?keys=db_info:002&keys=db_info:001&&extract=url").await; + let result: Vec = client.get("/ci/items?keys=db_info:002&keys=db_info:001&&extract=url").await; assert_eq!(result.len(), 2); assert_eq!(result[1].key, "db_info:002"); assert_eq!(result[1].info, "002系统的数据库信息"); @@ -158,7 +159,7 @@ pub async fn test(client: &mut TestHttpClient) -> TardisResult<()> { client.delete("/ci/item?key=db_info:001").await; - let result: TardisResp = client.get_resp("/ci/item/?key=db_info:001").await; + let result: TardisResp = client.get_resp("/ci/item?key=db_info:001").await; assert!(result.data.is_none()); // key-Name @@ -257,5 +258,26 @@ pub async fn test(client: &mut TestHttpClient) -> TardisResult<()> { assert_eq!(result.total_size, 2); assert_eq!(result.records[1].key, "feed:kind"); assert_eq!(result.records[1].items[1].code, "task"); + + // filter own_paths + let _: Void = client + .put( + "/ci/item", + &json!({ + "key":"db:url", + "value": "postgres://xxxx", + "info":"xx系统的数据库地址", + "scope_level": 0, + }), + ) + .await; + ctx.own_paths = "t1".to_string(); + client.set_auth(&ctx)?; + + let result: KvItemDetailResp = client.get("/ci/item?key=db:url").await; + assert_eq!(result.key, "db:url"); + assert_eq!(result.value, "postgres://xxxx"); + assert_eq!(result.info, "xx系统的数据库地址"); + Ok(()) }