use std::cmp::Ordering;
use crate::rbum::dto::rbum_filer_dto::RbumBasicFilterReq;
use crate::rbum::rbum_config::RbumConfigApi;
use itertools::Itertools;
use tardis::basic::dto::TardisContext;
use tardis::basic::error::TardisError;
use tardis::basic::result::TardisResult;
use tardis::{TardisFuns, TardisFunsInst};
use crate::rbum::rbum_enumeration::RbumScopeLevelKind;
pub fn get_pre_paths(scope_level: i16, own_paths: &str) -> Option<String> {
let own_paths = own_paths.trim();
let own_paths = own_paths.strip_suffix('/').unwrap_or(own_paths).to_string();
if scope_level == 0 {
return Some("".to_string());
}
let split_items = if own_paths.is_empty() { vec![] } else { own_paths.split('/').collect::<Vec<_>>() };
match split_items.len().cmp(&(scope_level as usize)) {
Ordering::Less => {
None
}
_ => Some(split_items.iter().take(scope_level as usize).join("/")),
}
}
pub fn get_path_item(scope_level: i16, own_paths: &str) -> Option<String> {
let own_paths = own_paths.trim();
let own_paths = own_paths.strip_suffix('/').unwrap_or(own_paths).to_string();
if scope_level == 0 || own_paths.is_empty() {
return None;
}
let split_items = own_paths.split('/').collect::<Vec<&str>>();
if split_items.len() < scope_level as usize {
return None;
}
split_items.get(scope_level as usize - 1).map(|s| s.to_string())
}
pub fn get_scope_level_by_context(ctx: &TardisContext) -> TardisResult<RbumScopeLevelKind> {
let own_paths = ctx.own_paths.trim();
let own_paths = own_paths.strip_suffix('/').unwrap_or(own_paths).to_string();
if own_paths == *"" {
return Ok(RbumScopeLevelKind::Root);
}
RbumScopeLevelKind::from_int(own_paths.split('/').count() as i16)
}
pub fn get_max_level_id_by_context(ctx: &TardisContext) -> Option<String> {
let own_paths = ctx.own_paths.trim();
if own_paths.is_empty() {
return None;
}
let own_paths = own_paths.strip_suffix('/').unwrap_or(own_paths).to_string();
own_paths.split('/').collect::<Vec<&str>>().last().map(|s| s.to_string())
}
pub fn degrade_own_paths(mut ctx: TardisContext, new_own_paths: &str) -> TardisResult<TardisContext> {
if !new_own_paths.starts_with(&ctx.own_paths) {
return Err(TardisError::conflict("not qualified for downgrade", "409-rbum-*-downgrade-error"));
}
ctx.own_paths = new_own_paths.to_string();
Ok(ctx)
}
pub fn check_scope(record_own_paths: &str, record_scope_level: Option<i16>, filter: &RbumBasicFilterReq, ctx_own_paths: &str) -> bool {
let standard_own_paths = if let Some(own_paths) = &filter.own_paths { own_paths.as_str() } else { ctx_own_paths };
if record_own_paths == standard_own_paths || filter.with_sub_own_paths && record_own_paths.starts_with(standard_own_paths) {
return true;
}
if filter.ignore_scope {
return false;
}
if let Some(record_scope_level) = record_scope_level {
if let Some(standard_sub_paths) = get_pre_paths(record_scope_level, standard_own_paths) {
let record_sub_paths = if record_own_paths.len() <= standard_sub_paths.len() {
record_own_paths
} else {
&record_own_paths[0..standard_sub_paths.len()]
};
return standard_sub_paths.starts_with(record_sub_paths);
}
}
false
}
fn do_unsafe_fill_ctx<F>(request: &tardis::web::poem::Request, f: F, funs: &TardisFunsInst, ctx: &mut TardisContext) -> TardisResult<()>
where
F: FnOnce(TardisContext, &mut TardisContext),
{
let bios_ctx = if let Some(bios_ctx) = request.header(funs.rbum_head_key_bios_ctx()).or_else(|| request.header(funs.rbum_head_key_bios_ctx().to_lowercase())) {
TardisFuns::json.str_to_obj::<TardisContext>(&TardisFuns::crypto.base64.decode_to_string(bios_ctx)?)?
} else if ctx.owner.is_empty() && ctx.ak.is_empty() && ctx.own_paths.is_empty() && ctx.roles.is_empty() && ctx.groups.is_empty() {
return Err(TardisError::unauthorized(
&format!("[Basic] Request is not legal, missing header [{}]", funs.rbum_head_key_bios_ctx()),
"404-rbum-req-ctx-not-exist",
));
} else {
return Ok(());
};
if bios_ctx.own_paths.starts_with(&ctx.own_paths) {
f(bios_ctx, ctx);
Ok(())
} else {
Err(TardisError::forbidden(
&format!("[Basic] Request is not legal from head [{}]", funs.rbum_head_key_bios_ctx()),
"401-rbum-req-ctx-permission-denied",
))
}
}
pub fn check_without_owner_and_unsafe_fill_ctx(request: &tardis::web::poem::Request, funs: &TardisFunsInst, ctx: &mut TardisContext) -> TardisResult<()> {
if ctx.ak.is_empty() {
return Err(TardisError::forbidden("[Basic] Request contex ak is not empty", "403-rbum-req-ctx-ak-is-not-empty"));
}
unsafe_fill_ctx(request, funs, ctx)
}
pub fn unsafe_fill_ctx(request: &tardis::web::poem::Request, funs: &TardisFunsInst, ctx: &mut TardisContext) -> TardisResult<()> {
do_unsafe_fill_ctx(
request,
|bios_ctx, ctx| {
let mut roles = bios_ctx.roles.clone();
for role in bios_ctx.roles.clone() {
if role.contains(':') {
let extend_role = role.split(':').collect::<Vec<_>>()[0];
roles.push(extend_role.to_string());
}
}
ctx.owner.clone_from(&bios_ctx.owner);
ctx.roles = roles;
ctx.groups = bios_ctx.groups;
ctx.own_paths = bios_ctx.own_paths;
},
funs,
ctx,
)
}
pub fn unsafe_fill_owner_only(request: &tardis::web::poem::Request, funs: &TardisFunsInst, ctx: &mut TardisContext) -> TardisResult<()> {
do_unsafe_fill_ctx(
request,
|bios_ctx, ctx| {
ctx.owner.clone_from(&bios_ctx.owner);
},
funs,
ctx,
)
}
pub fn unsafe_fill_own_paths_only(request: &tardis::web::poem::Request, funs: &TardisFunsInst, ctx: &mut TardisContext) -> TardisResult<()> {
do_unsafe_fill_ctx(
request,
|bios_ctx, ctx| {
ctx.own_paths = bios_ctx.own_paths;
},
funs,
ctx,
)
}
pub fn unsafe_fill_roles_only(request: &tardis::web::poem::Request, funs: &TardisFunsInst, ctx: &mut TardisContext) -> TardisResult<()> {
do_unsafe_fill_ctx(
request,
|bios_ctx, ctx| {
let mut roles = bios_ctx.roles.clone();
for role in bios_ctx.roles.clone() {
if role.contains(':') {
let extend_role = role.split(':').collect::<Vec<_>>()[0];
roles.push(extend_role.to_string());
}
}
ctx.roles = roles;
},
funs,
ctx,
)
}
pub fn unsafe_fill_groups_only(request: &tardis::web::poem::Request, funs: &TardisFunsInst, ctx: &mut TardisContext) -> TardisResult<()> {
do_unsafe_fill_ctx(
request,
|bios_ctx, ctx| {
ctx.groups = bios_ctx.groups;
},
funs,
ctx,
)
}