Files
komp_ac/web/src/pages/add_validation/logic.rs
2026-08-14 20:52:31 +02:00

296 lines
9.9 KiB
Rust

use axum::{
Form,
extract::State,
http::{HeaderMap, StatusCode},
response::{Html, IntoResponse, Redirect, Response},
};
use crate::{
AppState,
{i18n::Locale, tr},
services::authenticated_request,
};
use super::{
loader::{LoadError, load_page, load_set_page},
state::{ValidationForm, ValidationSetForm},
ui,
};
pub(crate) async fn new_field_validation_page(State(state): State<AppState>, headers: HeaderMap) -> Response {
render_loaded(&headers, load_page(state, &headers, ValidationForm::default(), false, None).await)
}
pub(crate) async fn new_validation_rule_page(State(state): State<AppState>, headers: HeaderMap) -> Response {
render_loaded(&headers, load_page(state, &headers, ValidationForm::default(), true, None).await)
}
pub(crate) async fn new_validation_set_page(State(state): State<AppState>, headers: HeaderMap) -> Response {
render_set_loaded(&headers, load_set_page(state, &headers, ValidationSetForm::default(), None).await)
}
pub(crate) async fn save_field_validation(
State(state): State<AppState>, headers: HeaderMap, Form(form): Form<ValidationForm>,
) -> Response {
let submitted = form.clone();
if let Err(error) = load_page(state.clone(), &headers, submitted.clone(), false, None).await {
return render_loaded(&headers, Err(error));
}
if cross_site(&headers) {
return (
StatusCode::FORBIDDEN,
tr!(
Locale::from_headers(&headers),
"services-cross-site-rejected"
),
)
.into_response();
}
if !form.validation_set_name.trim().is_empty() {
let request = match form.apply_set_request(Locale::from_headers(&headers)) {
Ok(request) => request,
Err(message) => {
return render_loaded(
&headers,
load_page(state, &headers, submitted, false, Some(message)).await,
)
}
};
let mut validations = state.validations;
let request = match authenticated_request(&headers, request) {
Ok(request) => request,
Err(_) => return Redirect::to("/login").into_response(),
};
return match validations.apply_validation_set(request).await {
Ok(response) if response.get_ref().success => Html(ui::render_success(
Locale::from_headers(&headers),
&response.get_ref().message,
))
.into_response(),
Ok(response) => (
StatusCode::UNPROCESSABLE_ENTITY,
Html(ui::render_error(
Locale::from_headers(&headers),
&response.get_ref().message,
)),
)
.into_response(),
Err(error) => (
StatusCode::UNPROCESSABLE_ENTITY,
Html(ui::render_error(
Locale::from_headers(&headers),
error.message(),
)),
)
.into_response(),
};
}
let request = match form.field_request(Locale::from_headers(&headers)) {
Ok(request) => request,
Err(message) => {
return render_loaded(
&headers,
load_page(state, &headers, submitted, false, Some(message)).await,
)
}
};
let mut validations = state.validations;
let request = match authenticated_request(&headers, request) {
Ok(request) => request,
Err(_) => return Redirect::to("/login").into_response(),
};
match validations.update_field_validation(request).await {
Ok(response) if response.get_ref().success => Html(ui::render_success(
Locale::from_headers(&headers),
&response.get_ref().message,
))
.into_response(),
Ok(response) => (
StatusCode::UNPROCESSABLE_ENTITY,
Html(ui::render_error(
Locale::from_headers(&headers),
&response.get_ref().message,
)),
)
.into_response(),
Err(error) => (
StatusCode::UNPROCESSABLE_ENTITY,
Html(ui::render_error(
Locale::from_headers(&headers),
error.message(),
)),
)
.into_response(),
}
}
pub(crate) async fn save_validation_rule(
State(state): State<AppState>, headers: HeaderMap, Form(form): Form<ValidationForm>,
) -> Response {
let submitted = form.clone();
if let Err(error) = load_page(state.clone(), &headers, submitted.clone(), true, None).await {
return render_loaded(&headers, Err(error));
}
if cross_site(&headers) {
return (
StatusCode::FORBIDDEN,
tr!(
Locale::from_headers(&headers),
"services-cross-site-rejected"
),
)
.into_response();
}
let request = match form.rule_request(Locale::from_headers(&headers)) {
Ok(request) => request,
Err(message) => {
return render_loaded(
&headers,
load_page(state, &headers, submitted, true, Some(message)).await,
)
}
};
let mut validations = state.validations;
let request = match authenticated_request(&headers, request) {
Ok(request) => request,
Err(_) => return Redirect::to("/login").into_response(),
};
match validations.upsert_validation_rule(request).await {
Ok(response) if response.get_ref().success => Html(ui::render_success(
Locale::from_headers(&headers),
&response.get_ref().message,
))
.into_response(),
Ok(response) => (
StatusCode::UNPROCESSABLE_ENTITY,
Html(ui::render_error(
Locale::from_headers(&headers),
&response.get_ref().message,
)),
)
.into_response(),
Err(error) => (
StatusCode::UNPROCESSABLE_ENTITY,
Html(ui::render_error(
Locale::from_headers(&headers),
error.message(),
)),
)
.into_response(),
}
}
pub(crate) async fn save_validation_set(
State(state): State<AppState>, headers: HeaderMap, Form(form): Form<ValidationSetForm>,
) -> Response {
let submitted = form.clone();
if let Err(error) = load_set_page(state.clone(), &headers, submitted.clone(), None).await {
return render_set_loaded(&headers, Err(error));
}
if cross_site(&headers) {
return (
StatusCode::FORBIDDEN,
tr!(
Locale::from_headers(&headers),
"services-cross-site-rejected"
),
)
.into_response();
}
let request = match form.request(Locale::from_headers(&headers)) {
Ok(request) => request,
Err(message) => {
return render_set_loaded(
&headers,
load_set_page(state, &headers, submitted, Some(message)).await,
)
}
};
let mut validations = state.validations;
let request = match authenticated_request(&headers, request) {
Ok(request) => request,
Err(_) => return Redirect::to("/login").into_response(),
};
match validations.upsert_validation_set(request).await {
Ok(response) if response.get_ref().success => Html(ui::render_success(
Locale::from_headers(&headers),
&response.get_ref().message,
))
.into_response(),
Ok(response) => (
StatusCode::UNPROCESSABLE_ENTITY,
Html(ui::render_error(
Locale::from_headers(&headers),
&response.get_ref().message,
)),
)
.into_response(),
Err(error) => (
StatusCode::UNPROCESSABLE_ENTITY,
Html(ui::render_error(
Locale::from_headers(&headers),
error.message(),
)),
)
.into_response(),
}
}
fn render_set_loaded(
headers: &HeaderMap,
result: Result<(crate::ui::Nav, ValidationSetForm, Option<String>), LoadError>,
) -> Response {
match result {
Ok((nav, form, error)) => {
Html(ui::render_set_page(nav, &form, error.as_deref())).into_response()
}
Err(LoadError::Unauthenticated) => Redirect::to("/login").into_response(),
Err(LoadError::Forbidden) => (
StatusCode::FORBIDDEN,
Html(ui::render_error(
Locale::from_headers(headers),
&tr!(
Locale::from_headers(headers),
"validation-err-permission"
),
)),
)
.into_response(),
Err(LoadError::Backend(message)) => (
StatusCode::BAD_GATEWAY,
Html(ui::render_error(Locale::from_headers(headers), &message)),
)
.into_response(),
}
}
fn render_loaded(
headers: &HeaderMap,
result: Result<super::state::ValidationPageState, LoadError>,
) -> Response {
match result {
Ok(page) => Html(ui::render_page(&page)).into_response(),
Err(LoadError::Unauthenticated) => Redirect::to("/login").into_response(),
Err(LoadError::Forbidden) => (
StatusCode::FORBIDDEN,
Html(ui::render_error(
Locale::from_headers(headers),
&tr!(
Locale::from_headers(headers),
"validation-err-permission"
),
)),
)
.into_response(),
Err(LoadError::Backend(message)) => (
StatusCode::BAD_GATEWAY,
Html(ui::render_error(Locale::from_headers(headers), &message)),
)
.into_response(),
}
}
fn cross_site(headers: &HeaderMap) -> bool {
headers.get("sec-fetch-site").is_some_and(|value| value == "cross-site")
}