EinsatzOnline/src/modules/event_management/check_position_requirements.rs

188 lines
6.8 KiB
Rust

use rocket::State;
use crate::helper::settings::Settings;
use crate::database::controller::events::get_eu_position;
use crate::modules::api::member_management::controller::parser::parse_uuid_string;
use serde_json::{Value, Map};
use std::fmt;
use crate::database::controller::member_licenses::check_license_for_member;
use crate::database::model::member_licenses::MemberDrivePermission;
use diesel::result::Error;
use crate::database::controller::member_qualifications::check_qualification_for_member;
use uuid::Uuid;
use crate::modules::api::model::api_outcome::ApiErrorWrapper;
use rocket::serde::json::Json;
pub fn check_position_requirements(settings: &State<Settings>, position_id: uuid::Uuid, member_id: uuid::Uuid) -> Result<bool, RequirementParserError>{
let position = match get_eu_position(settings, position_id){
Ok(pos) => pos,
Err(e) => return Err(RequirementParserError::from(e))
};
match position.requirements{
Some(req) => parse_requirements(req, settings, member_id),
None => Ok(true)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Operator {
AND,
OR
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum RequirementParserErrorKind {
InvalidJsonStart,
UnknownOperator,
UnknownConditionType,
UnexpectedType,
InvalidUUID,
}
#[derive(Debug)]
pub enum RequirementParserError {
Database(diesel::result::Error),
Parser(RequirementParserErrorKind),
}
impl RequirementParserErrorKind {
pub fn as_str(&self) -> &str {
match *self {
RequirementParserErrorKind::InvalidJsonStart => "requirements didn't start with conditions",
RequirementParserErrorKind::UnknownOperator => "operator not known",
RequirementParserErrorKind::UnknownConditionType => "condition not known",
RequirementParserErrorKind::UnexpectedType => "type unexpected",
RequirementParserErrorKind::InvalidUUID => "invalid, unparsable uuid",
}
}
}
impl fmt::Display for RequirementParserError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
RequirementParserError::Parser(ref err) => write!(f, "JSON parsing error: {:?}", err),
RequirementParserError::Database(ref err) => err.fmt(f),
}
}
}
impl From<diesel::result::Error> for RequirementParserError {
fn from(err: diesel::result::Error) -> RequirementParserError {
RequirementParserError::Database(err)
}
}
fn parse_requirements(req: serde_json::Value, settings: &State<Settings>, member_id: uuid::Uuid) -> Result<bool, RequirementParserError> {
match &req["conditions"]{
Value::Array(a) => parse_condition_group(a, settings, member_id),
_ => Err(RequirementParserError::Parser(RequirementParserErrorKind::InvalidJsonStart))
}
}
fn parse_condition_group(array: &Vec<Value>, settings: &State<Settings>, member_id: uuid::Uuid) -> Result<bool, RequirementParserError>{
let operator : Operator;
if array.len() >= 2 {
//Parse operator (first array item)
match &array[0]{
Value::String(o) => match parse_operator(o){
Ok(op) => operator = op,
Err(e) => return Err(e)
}
_ => return Err(RequirementParserError::Parser(RequirementParserErrorKind::InvalidJsonStart))
}
for i in 1..array.len(){
match &array[i]{
Value::Array(a) => match parse_condition_group(a, settings, member_id){
Ok(res) => {
if operator == Operator::AND{
if !res{
return Ok(false)
}
}else if operator == Operator::OR{
if res{
return Ok(true)
}
}
},
Err(e) => return Err(e)
},
Value::Object(o) => {
match parse_condition(o, settings, member_id){
Ok(res) => {
if operator == Operator::AND{
if !res{
return Ok(false)
}
}else if operator == Operator::OR{
if res{
return Ok(true)
}
}
},
Err(e) => return Err(e)
}
},
_ => return Err(RequirementParserError::Parser(RequirementParserErrorKind::UnexpectedType))
}
}
if operator == Operator::AND {
Ok(true)
}else{
Ok(false)
}
}else{
Ok(true)
}
}
fn parse_condition(condition: &Map<String, Value>, settings: &State<Settings>, member_id: uuid::Uuid) -> Result<bool, RequirementParserError>{
if condition.contains_key("license"){
let val = match condition.get("license").unwrap(){
Value::String(v) => v,
_ => return Err(RequirementParserError::Parser(RequirementParserErrorKind::UnexpectedType))
};
match check_member_license(settings, member_id, val.clone()){
Ok(res) => Ok(res),
Err(e) => Err(RequirementParserError::from(e))
}
}else if condition.contains_key("qualification"){
let val = match condition.get("qualification").unwrap(){
Value::String(v) => v,
_ => return Err(RequirementParserError::Parser(RequirementParserErrorKind::UnexpectedType))
};
let val = match parse_uuid_string(val.clone()){
Ok(val) => val,
Err(_) => return Err(RequirementParserError::Parser(RequirementParserErrorKind::InvalidUUID))
};
match check_qualification_for_member(settings, val,member_id){
Ok(res) => Ok(res),
Err(e) => Err(RequirementParserError::from(e))
}
}else{
Err(RequirementParserError::Parser(RequirementParserErrorKind::UnknownConditionType))
}
}
fn parse_operator(operator: &String) -> Result<Operator, RequirementParserError>{
if operator == "AND"{
Ok(Operator::AND)
}else if operator == "OR"{
Ok(Operator::OR)
}else{
Err(RequirementParserError::Parser(RequirementParserErrorKind::UnknownOperator))
}
}
fn check_member_license(settings: &State<Settings>, member_id: uuid::Uuid, license_id: String) -> Result<bool, diesel::result::Error>{
match check_license_for_member(settings, license_id, member_id){
Ok(res) => {
match res{
Some(_) => Ok(true),
None => Ok(false)
}
}
Err(e) => Err(e)
}
}