web synchronized with the new changes
This commit is contained in:
160
web/src/pages/admin/permissions/logic.rs
Normal file
160
web/src/pages/admin/permissions/logic.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
use axum::{
|
||||
extract::{Query, State},
|
||||
http::{HeaderMap, HeaderValue, StatusCode, header},
|
||||
response::{Html, IntoResponse, Redirect, Response},
|
||||
};
|
||||
use axum_extra::extract::Form;
|
||||
|
||||
use crate::{
|
||||
AppState,
|
||||
auth::{
|
||||
AddRoleRequest, AssignUserRoleRequest, GrantPermissionRequest, RemoveRoleRequest,
|
||||
RevokePermissionRequest,
|
||||
},
|
||||
services::{authenticated_request, reject_cross_site},
|
||||
};
|
||||
|
||||
use super::{
|
||||
loader,
|
||||
state::{AddRoleForm, AssignRoleForm, LoadError, PermissionForm, RoleForm, Selection},
|
||||
ui,
|
||||
};
|
||||
|
||||
pub(crate) async fn page(
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Query(selection): Query<Selection>,
|
||||
) -> Response {
|
||||
match loader::load_page(state, &headers, selection).await {
|
||||
Ok(page) => Html(ui::render_page(&page)).into_response(),
|
||||
Err(error) => load_error(error),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn add_role(
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Form(form): Form<AddRoleForm>,
|
||||
) -> Response {
|
||||
let request_headers = headers.clone();
|
||||
mutate(&headers, async move {
|
||||
let mut auth = state.auth;
|
||||
auth.add_role(authenticated_request(&request_headers, AddRoleRequest {
|
||||
name: form.name.trim().to_string(),
|
||||
parent: form.parent.trim().to_string(),
|
||||
}).map_err(|_| "Missing session".to_string())?)
|
||||
.await.map_err(|error| error.message().to_string())?;
|
||||
Ok("Role created. Sign in again to continue.")
|
||||
}).await
|
||||
}
|
||||
|
||||
pub(crate) async fn remove_role(
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Form(form): Form<RoleForm>,
|
||||
) -> Response {
|
||||
let request_headers = headers.clone();
|
||||
mutate(&headers, async move {
|
||||
let mut auth = state.auth;
|
||||
auth.remove_role(authenticated_request(&request_headers, RemoveRoleRequest {
|
||||
name: form.role,
|
||||
}).map_err(|_| "Missing session".to_string())?)
|
||||
.await.map_err(|error| error.message().to_string())?;
|
||||
Ok("Role removed. Sign in again to continue.")
|
||||
}).await
|
||||
}
|
||||
|
||||
pub(crate) async fn grant(
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Form(form): Form<PermissionForm>,
|
||||
) -> Response {
|
||||
let request_headers = headers.clone();
|
||||
mutate(&headers, async move {
|
||||
let mut auth = state.auth;
|
||||
auth.grant_permission(authenticated_request(&request_headers, GrantPermissionRequest {
|
||||
role: form.role,
|
||||
object: form.object,
|
||||
action: form.action,
|
||||
}).map_err(|_| "Missing session".to_string())?)
|
||||
.await.map_err(|error| error.message().to_string())?;
|
||||
Ok("Permission granted. Sign in again to continue.")
|
||||
}).await
|
||||
}
|
||||
|
||||
pub(crate) async fn revoke(
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Form(form): Form<PermissionForm>,
|
||||
) -> Response {
|
||||
let request_headers = headers.clone();
|
||||
mutate(&headers, async move {
|
||||
let mut auth = state.auth;
|
||||
auth.revoke_permission(authenticated_request(&request_headers, RevokePermissionRequest {
|
||||
role: form.role,
|
||||
object: form.object,
|
||||
action: form.action,
|
||||
}).map_err(|_| "Missing session".to_string())?)
|
||||
.await.map_err(|error| error.message().to_string())?;
|
||||
Ok("Permission revoked. Sign in again to continue.")
|
||||
}).await
|
||||
}
|
||||
|
||||
pub(crate) async fn assign_user_role(
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Form(form): Form<AssignRoleForm>,
|
||||
) -> Response {
|
||||
let request_headers = headers.clone();
|
||||
mutate(&headers, async move {
|
||||
let mut auth = state.auth;
|
||||
auth.assign_user_role(authenticated_request(&request_headers, AssignUserRoleRequest {
|
||||
username: form.username,
|
||||
role: form.role,
|
||||
}).map_err(|_| "Missing session".to_string())?)
|
||||
.await.map_err(|error| error.message().to_string())?;
|
||||
Ok("User role changed. Sign in again to continue.")
|
||||
}).await
|
||||
}
|
||||
|
||||
async fn mutate<F>(headers: &HeaderMap, operation: F) -> Response
|
||||
where
|
||||
F: std::future::Future<Output = Result<&'static str, String>>,
|
||||
{
|
||||
if let Some(rejection) = reject_cross_site(headers) {
|
||||
return rejection;
|
||||
}
|
||||
match operation.await {
|
||||
Ok(_) => stale_session_response(),
|
||||
Err(message) => (
|
||||
StatusCode::UNPROCESSABLE_ENTITY,
|
||||
Html(ui::render_mutation_error(&message)),
|
||||
).into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
fn stale_session_response() -> Response {
|
||||
let mut response = StatusCode::SEE_OTHER.into_response();
|
||||
response.headers_mut().insert(
|
||||
header::SET_COOKIE,
|
||||
HeaderValue::from_static("analytics_token=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0"),
|
||||
);
|
||||
response.headers_mut().insert(
|
||||
header::LOCATION,
|
||||
HeaderValue::from_static("/login?permissions_changed=1"),
|
||||
);
|
||||
response.headers_mut().insert(
|
||||
"hx-redirect",
|
||||
HeaderValue::from_static("/login?permissions_changed=1"),
|
||||
);
|
||||
response
|
||||
}
|
||||
|
||||
fn load_error(error: LoadError) -> Response {
|
||||
match error {
|
||||
LoadError::Unauthenticated => Redirect::to("/login").into_response(),
|
||||
LoadError::Forbidden => (StatusCode::FORBIDDEN, Html(ui::render_error("You do not have role or user management permission."))).into_response(),
|
||||
LoadError::InvalidSelection(message) => (StatusCode::BAD_REQUEST, Html(ui::render_error(&message))).into_response(),
|
||||
LoadError::Backend(message) => (StatusCode::BAD_GATEWAY, Html(ui::render_error(&message))).into_response(),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user