use crate::auth::permissions::{groupe, pull_groupes_db};
use crate::auth::session::CurrentUser;
use crate::errors::error::RuniqueError;
use crate::forms::prisme::rules::{GuardRules, evaluate_rules};
use crate::utils::aliases::{ADb, AEngine};
use crate::utils::trad::tf;
use axum::{
body::Body,
http::Request,
response::{IntoResponse, Response},
};
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QuerySelect};
pub fn sentinel(
req: &Request<Body>,
) -> impl Future<Output = Result<(), Box<Response>>> + Send + 'static {
let rules = req.extensions().get::<GuardRules>().cloned();
let user = rules
.as_ref()
.and_then(|_| req.extensions().get::<CurrentUser>().cloned());
let engine = req.extensions().get::<AEngine>().cloned();
async move {
let Some(rules) = rules else {
return Ok(());
};
let groupes = match &user {
Some(user) if !rules.roles.is_empty() && !user.is_superuser => {
group_names(user, engine.as_ref()).await
}
_ => Vec::new(),
};
let refusal = evaluate_rules(&rules, user.as_ref(), &groupes);
if refusal.is_err()
&& user.is_some()
&& !rules.roles.is_empty()
&& let Some(engine) = &engine
{
let unknown = unknown_groups(&engine.db, &rules.roles).await;
if !unknown.is_empty() {
let message = tf("forms.unknown_group", &[unknown.join(", ")]);
return Err(Box::new(
RuniqueError::Custom {
message,
source: None,
}
.into_response(),
));
}
}
refusal
}
}
async fn group_names(user: &CurrentUser, engine: Option<&AEngine>) -> Vec<String> {
let groupes = if !user.groupes.is_empty() {
user.groupes.clone()
} else if let Some(engine) = engine {
pull_groupes_db(&engine.db, user.id).await
} else {
Vec::new()
};
groupes.into_iter().map(|g| g.nom).collect()
}
async fn unknown_groups(db: &ADb, roles: &[String]) -> Vec<String> {
let existing: Vec<String> = match groupe::Entity::find()
.select_only()
.column(groupe::Column::Nom)
.filter(groupe::Column::Nom.is_in(roles.iter().cloned()))
.into_tuple()
.all(db)
.await
{
Ok(existing) => existing,
Err(e) => {
tracing::error!(error = %e, "GuardRules: checking the group names failed");
return Vec::new();
}
};
roles
.iter()
.filter(|role| !existing.contains(role))
.cloned()
.collect()
}