Skip to content

Commit

Permalink
Improve handling of secret attributes.
Browse files Browse the repository at this point in the history
  • Loading branch information
gudaoxuri committed May 13, 2024
1 parent 56dcc75 commit 0050768
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 75 deletions.
4 changes: 2 additions & 2 deletions backend/basic/src/rbum/dto/rbum_item_attr_dto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ pub struct RbumItemAttrsAddOrModifyReq {
///
/// 添加或修改的值集合
///
/// Format: ``{ "field name": "field value" }``
/// Format: ``{ "attribute name": "attribute value" }``
///
/// ``field name``: [`crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp::name`]
/// ``attribute name``: [`crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrDetailResp::name`]
pub values: HashMap<String, String>,
/// Associated [resource item](crate::rbum::dto::rbum_item_dto::RbumItemDetailResp) id
///
Expand Down
128 changes: 63 additions & 65 deletions backend/basic/src/rbum/serv/rbum_item_serv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1415,15 +1415,15 @@ impl RbumCrudOperation<rbum_item_attr::ActiveModel, RbumItemAttrAddReq, RbumItem
}

impl RbumItemAttrServ {
/// Get all attribute definitions of the resource item corresponding to the resource kind
/// Get resource kind id and resource kind attribute definitions corresponding to resource item id
///
/// 获取资源项对应资源类型的所有属性定义
pub async fn find_item_attr_defs_by_item_id(
/// 获取资源项对应资源类型id及资源类型所有属性定义
async fn find_res_kind_id_and_res_kind_attrs_by_item_id(
rbum_item_id: &str,
secret: Option<bool>,
funs: &TardisFunsInst,
ctx: &TardisContext,
) -> TardisResult<Vec<RbumKindAttrSummaryResp>> {
) -> TardisResult<(String, Vec<RbumKindAttrSummaryResp>)> {
let rel_rbum_kind_id = RbumItemServ::peek_rbum(
rbum_item_id,
&RbumBasicFilterReq {
Expand All @@ -1435,10 +1435,10 @@ impl RbumItemAttrServ {
)
.await?
.rel_rbum_kind_id;
RbumKindAttrServ::find_rbums(
let rbum_kind_attrs = RbumKindAttrServ::find_rbums(
&RbumKindAttrFilterReq {
basic: RbumBasicFilterReq {
rbum_kind_id: Some(rel_rbum_kind_id),
rbum_kind_id: Some(rel_rbum_kind_id.clone()),
..Default::default()
},
secret,
Expand All @@ -1449,29 +1449,35 @@ impl RbumItemAttrServ {
funs,
ctx,
)
.await
.await?;
Ok((rel_rbum_kind_id, rbum_kind_attrs))
}

/// Add or modify resource item extended attributes
///
/// 添加或修改资源项扩展属性
pub async fn add_or_modify_item_attrs(add_req: &RbumItemAttrsAddOrModifyReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
// Implicit rel_rbum_kind_attr scope check
let rbum_kind_attrs = Self::find_item_attr_defs_by_item_id(&add_req.rel_rbum_item_id, None, funs, ctx).await?;
let in_main_table_attrs = rbum_kind_attrs.iter().filter(|i| add_req.values.contains_key(&i.name) && i.main_column && !i.secret).collect::<Vec<&RbumKindAttrSummaryResp>>();
let in_ext_table_attrs = rbum_kind_attrs.iter().filter(|i| add_req.values.contains_key(&i.name) && !i.main_column && !i.secret).collect::<Vec<&RbumKindAttrSummaryResp>>();
let in_secret_table_attrs = rbum_kind_attrs.iter().filter(|i| i.secret).collect::<Vec<&RbumKindAttrSummaryResp>>();
let (rel_rbum_kind_id, rbum_kind_attrs) = Self::find_res_kind_id_and_res_kind_attrs_by_item_id(&add_req.rel_rbum_item_id, None, funs, ctx).await?;
let in_main_table_attrs = rbum_kind_attrs.iter().filter(|i| add_req.values.contains_key(&i.name) && i.main_column).collect::<Vec<&RbumKindAttrSummaryResp>>();
let in_ext_table_attrs = rbum_kind_attrs.iter().filter(|i| add_req.values.contains_key(&i.name) && !i.main_column).collect::<Vec<&RbumKindAttrSummaryResp>>();
if !in_main_table_attrs.is_empty() {
// Implicit rel_rbum_item scope check
let rel_rbum_kind_id = RbumItemServ::peek_rbum(&add_req.rel_rbum_item_id, &RbumBasicFilterReq::default(), funs, ctx).await?.rel_rbum_kind_id;
let main_table_name = RbumKindServ::peek_rbum(&rel_rbum_kind_id, &RbumKindFilterReq::default(), funs, ctx).await?.ext_table_name;

let mut update_statement = Query::update();
update_statement.table(Alias::new(&main_table_name));

for in_main_table_attr in in_main_table_attrs {
let column_val = if in_main_table_attr.secret && !in_main_table_attr.dyn_default_value.is_empty() {
Self::replace_url_placeholder(&in_main_table_attr.dyn_default_value, &add_req.values, funs).await?
} else if in_main_table_attr.secret {
in_main_table_attr.default_value.clone()
} else {
add_req.values.get(&in_main_table_attr.name).expect("ignore").clone()
};

let column_name = Alias::new(&in_main_table_attr.name);
let column_val = add_req.values.get(&in_main_table_attr.name).expect("ignore").clone();
update_statement.value(column_name, Value::from(column_val));
}
update_statement.and_where(Expr::col(ID_FIELD.clone()).eq(add_req.rel_rbum_item_id.as_str()));
Expand All @@ -1480,7 +1486,14 @@ impl RbumItemAttrServ {

if !in_ext_table_attrs.is_empty() {
for in_ext_table_attr in in_ext_table_attrs {
let column_val = add_req.values.get(&in_ext_table_attr.name).expect("ignore").clone();
let column_val = if in_ext_table_attr.secret && !in_ext_table_attr.dyn_default_value.is_empty() {
Self::replace_url_placeholder(&in_ext_table_attr.dyn_default_value, &add_req.values, funs).await?
} else if in_ext_table_attr.secret {
in_ext_table_attr.default_value.clone()
} else {
add_req.values.get(&in_ext_table_attr.name).expect("ignore").clone()
};

let exist_item_attr_ids = Self::find_id_rbums(
&RbumItemAttrFilterReq {
basic: Default::default(),
Expand Down Expand Up @@ -1510,66 +1523,23 @@ impl RbumItemAttrServ {
}
}

if !in_secret_table_attrs.is_empty() {
for in_secret_table_attr in in_secret_table_attrs {
let secret_item_attr_ids = Self::find_id_rbums(
&RbumItemAttrFilterReq {
basic: Default::default(),
rel_rbum_item_id: Some(add_req.rel_rbum_item_id.to_string()),
rel_rbum_kind_attr_id: Some(in_secret_table_attr.id.to_string()),
},
None,
None,
funs,
ctx,
)
.await?;
let result = if !in_secret_table_attr.dyn_default_value.is_empty() {
if RbumKindAttrServ::url_match(&in_secret_table_attr.dyn_default_value).unwrap() {
let url = RbumKindAttrServ::url_replace(&in_secret_table_attr.dyn_default_value, add_req.values.clone()).unwrap();
if RbumKindAttrServ::url_match(&url).unwrap() {
return Err(funs.err().bad_request(
&Self::get_obj_name(),
"add_or_modify_item_attrs",
"url processing failure",
"400-rbum-kind-attr-dyn-url-illegal",
));
}
funs.web_client().get_to_str(&url, None).await.unwrap().body.unwrap()
} else {
funs.web_client().get_to_str(&in_secret_table_attr.dyn_default_value, None).await.unwrap().body.unwrap()
}
} else {
in_secret_table_attr.default_value.clone()
};
if secret_item_attr_ids.is_empty() {
Self::add_rbum(
&mut RbumItemAttrAddReq {
value: result.clone(),
rel_rbum_item_id: add_req.rel_rbum_item_id.to_string(),
rel_rbum_kind_attr_id: in_secret_table_attr.id.to_string(),
},
funs,
ctx,
)
.await?;
} else {
Self::modify_rbum(secret_item_attr_ids.first().expect("ignore"), &mut RbumItemAttrModifyReq { value: result }, funs, ctx).await?;
}
}
}

Ok(())
}

/// Get resource item extended attributes
///
/// 获取资源项扩展属性集合
///
/// # Returns
///
/// The key is the attribute name, and the value is the attribute value.
pub async fn find_item_attr_values(rbum_item_id: &str, secret: Option<bool>, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<HashMap<String, String>> {
let rbum_kind_attrs = Self::find_item_attr_defs_by_item_id(rbum_item_id, secret, funs, ctx).await?;
let (rel_rbum_kind_id, rbum_kind_attrs) = Self::find_res_kind_id_and_res_kind_attrs_by_item_id(rbum_item_id, secret, funs, ctx).await?;
let in_main_table_attrs = rbum_kind_attrs.iter().filter(|i| i.main_column).collect::<Vec<&RbumKindAttrSummaryResp>>();
let has_in_ext_table_attrs = rbum_kind_attrs.iter().any(|i| !i.main_column);

let mut values: HashMap<String, String> = HashMap::new();
if !in_main_table_attrs.is_empty() {
let rel_rbum_kind_id = RbumItemServ::peek_rbum(rbum_item_id, &RbumBasicFilterReq::default(), funs, ctx).await?.rel_rbum_kind_id;
let ext_table_name = RbumKindServ::peek_rbum(&rel_rbum_kind_id, &RbumKindFilterReq::default(), funs, ctx).await?.ext_table_name;

let mut select_statement = Query::select();
Expand Down Expand Up @@ -1606,6 +1576,34 @@ impl RbumItemAttrServ {
}
Ok(values)
}

async fn replace_url_placeholder(url: &str, values: &HashMap<String, String>, funs: &TardisFunsInst) -> TardisResult<String> {
let resp = if RbumKindAttrServ::url_has_placeholder(url)? {
let url: String = RbumKindAttrServ::url_replace(url, values)?;
if RbumKindAttrServ::url_has_placeholder(&url)? {
return Err(funs.err().bad_request(
&Self::get_obj_name(),
"replace_url_placeholder",
"url processing failure",
"400-rbum-kind-attr-dyn-url-illegal",
));
}
funs.web_client().get_to_str(&url, None).await
} else {
funs.web_client().get_to_str(url, None).await
};
match resp {
Ok(resp) => Ok(resp.body.unwrap_or_else(|| "".to_string())),
Err(e) => {
return Err(funs.err().bad_request(
&Self::get_obj_name(),
"replace_url_placeholder",
&format!("url processing failure: {}", e),
"400-rbum-kind-attr-dyn-url-illegal",
));
}
}
}
}

#[derive(Debug, sea_orm::FromQueryResult)]
Expand Down
17 changes: 14 additions & 3 deletions backend/basic/src/rbum/serv/rbum_kind_serv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ impl RbumCrudOperation<rbum_kind::ActiveModel, RbumKindAddReq, RbumKindModifyReq
if !R_URL_PART_CODE.is_match(&add_req.code) {
return Err(funs.err().bad_request(&Self::get_obj_name(), "add", &format!("code {} is invalid", add_req.code), "400-rbum-*-code-illegal"));
}
if funs.db().count(Query::select().column(rbum_kind::Column::Id).from(rbum_kind::Entity).and_where(Expr::col(rbum_kind::Column::Code).eq(add_req.code.to_string()))).await? > 0
if funs.db().count(Query::select().column(rbum_kind::Column::Id).from(rbum_kind::Entity).and_where(Expr::col(rbum_kind::Column::Code).eq(add_req.code.to_string()))).await?
> 0
{
return Err(funs.err().conflict(&Self::get_obj_name(), "add", &format!("code {} already exists", add_req.code), "409-rbum-*-code-exist"));
}
Expand Down Expand Up @@ -346,7 +347,14 @@ impl RbumCrudOperation<rbum_kind_attr::ActiveModel, RbumKindAttrAddReq, RbumKind
}

impl RbumKindAttrServ {
pub fn url_replace(uri: &str, values: HashMap<String, String>) -> TardisResult<String> {
/// URL replace
///
/// URL替换
///
/// Replace ``{key}`` in the URL with the value in values.
///
/// 将URL中的 ``{key}`` 替换为values中的值。
pub fn url_replace(uri: &str, values: &HashMap<String, String>) -> TardisResult<String> {
let mut new_uri = uri.to_string();
for mat in EXTRACT_R.captures_iter(uri) {
let old_key = mat.get(0).expect("ignore").as_str();
Expand All @@ -358,7 +366,10 @@ impl RbumKindAttrServ {
Ok(new_uri)
}

pub fn url_match(uri: &str) -> TardisResult<bool> {
/// Whether the URL contains unreplaced placeholders
///
/// URL中是否包含未替换的占位符
pub fn url_has_placeholder(uri: &str) -> TardisResult<bool> {
Ok(!EXTRACT_R.is_match(uri))
}
}
1 change: 0 additions & 1 deletion backend/basic/src/rbum/serv/rbum_rel_serv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use itertools::Itertools;
use tardis::basic::dto::TardisContext;
use tardis::basic::result::TardisResult;
use tardis::db::reldb_client::IdResp;
use tardis::db::sea_orm;
use tardis::db::sea_orm::sea_query::*;
use tardis::db::sea_orm::IdenStatic;
use tardis::db::sea_orm::*;
Expand Down
8 changes: 4 additions & 4 deletions backend/basic/tests/test_rbum_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@ pub async fn test(context: &TardisContext) -> TardisResult<()> {
}

async fn test_rbum_kind_url() -> TardisResult<()> {
assert!(!RbumKindAttrServ::url_match("http://iam/{key}?{key}=1&{key2}=2").unwrap());
assert!(!RbumKindAttrServ::url_has_placeholder("http://iam/{key}?{key}=1&{key2}=2").unwrap());
assert_eq!(
"http://iam/t1?t1=1&t2=2",
RbumKindAttrServ::url_replace(
"http://iam/{key}?{key}=1&{key2}=2",
HashMap::from([("key".to_string(), "t1".to_string()), ("key2".to_string(), "t2".to_string())]),
&HashMap::from([("key".to_string(), "t1".to_string()), ("key2".to_string(), "t2".to_string())]),
)
.unwrap()
.as_str()
);
assert!(RbumKindAttrServ::url_match(
assert!(RbumKindAttrServ::url_has_placeholder(
RbumKindAttrServ::url_replace(
"http://iam/{key}?{key}=1&{key2}=2",
HashMap::from([("key".to_string(), "t1".to_string()), ("key2".to_string(), "t2".to_string())]),
&HashMap::from([("key".to_string(), "t1".to_string()), ("key2".to_string(), "t2".to_string())]),
)
.unwrap()
.as_str(),
Expand Down

0 comments on commit 0050768

Please sign in to comment.