diff options
Diffstat (limited to 'server/src/ui/admin/users.rs')
| -rw-r--r-- | server/src/ui/admin/users.rs | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/server/src/ui/admin/users.rs b/server/src/ui/admin/users.rs new file mode 100644 index 0000000..654a6b9 --- /dev/null +++ b/server/src/ui/admin/users.rs @@ -0,0 +1,120 @@ +/* + This file is part of jellything (https://codeberg.org/metamuffin/jellything) + which is licensed under the GNU Affero General Public License (version 3); see /COPYING. + Copyright (C) 2026 metamuffin <metamuffin.org> +*/ + +use std::str::FromStr; + +use base64::{Engine, prelude::BASE64_URL_SAFE}; +use jellycommon::{ + jellyobject::{OBB, ObjectBufferBuilder, Path}, + routes::u_admin_users, + *, +}; +use jellydb::{Filter, Query, Sort}; +use jellyui::tr; +use rand::random; +use rocket::{ + FromForm, + form::Form, + get, post, + response::{Flash, Redirect}, +}; + +use crate::{ + auth::hash_password, request_info::RequestInfo, ui::error::MyResult, ui_responder::UiResponse, +}; + +#[get("/admin/users")] +pub fn r_admin_users(ri: RequestInfo) -> MyResult<UiResponse> { + ri.require_admin()?; + + let mut users = Vec::new(); + ri.state.database.transaction(&mut |txn| { + users.clear(); + let rows = txn + .query(Query::from_str("FILTER Ulgn")?)? + .collect::<Vec<_>>(); + for row in rows { + let (row, _) = row?; + users.push(txn.get(row)?.unwrap()); + } + Ok(()) + })?; + + let mut list = ObjectBufferBuilder::default(); + for u in users { + list.push(ADMIN_USER_LIST_ITEM, u.as_object()); + } + + let mut page = ObjectBufferBuilder::default(); + page.push(VIEW_TITLE, &*tr(ri.lang, "admin.users")); + page.push(VIEW_ADMIN_USER_LIST, list.finish().as_object()); + Ok(ri.respond_ui(page)) +} + +#[derive(FromForm)] +pub struct NewUser { + login: String, +} + +#[post("/admin/new_user", data = "<form>")] +pub fn r_admin_new_user(ri: RequestInfo, form: Form<NewUser>) -> MyResult<Flash<Redirect>> { + ri.require_admin()?; + + let password = BASE64_URL_SAFE.encode([(); 12].map(|()| random())); + let password_hashed = hash_password(&form.login, &password); + + ri.state.database.transaction(&mut |txn| { + let mut user = ObjectBufferBuilder::default(); + user.push(USER_LOGIN, &form.login); + user.push(USER_PASSWORD, &password_hashed); + user.push(USER_PASSWORD_REQUIRE_CHANGE, ()); + txn.insert(user.finish())?; + Ok(()) + })?; + + Ok(Flash::new( + Redirect::to(u_admin_users()), + "success", + format!("User created; password: {password}"), + )) +} + +#[get("/admin/user/<name>")] +pub fn r_admin_user(ri: RequestInfo<'_>, name: &str) -> MyResult<UiResponse> { + ri.require_admin()?; + let mut page = OBB::new(); + ri.state.database.transaction(&mut |txn| { + if let Some(row) = txn.query_single(Query { + sort: Sort::None, + filter: Filter::Match(Path(vec![USER_LOGIN.0]), name.into()), + })? { + let user = txn.get(row)?.unwrap(); + page = OBB::new(); + page.push(VIEW_ADMIN_USER, user.as_object()); + } + Ok(()) + })?; + + Ok(ri.respond_ui(page)) +} + +#[post("/admin/user/<name>/remove")] +pub fn r_admin_user_remove(ri: RequestInfo<'_>, name: &str) -> MyResult<Flash<Redirect>> { + ri.require_admin()?; + ri.state.database.transaction(&mut |txn| { + if let Some(row) = txn.query_single(Query { + sort: Sort::None, + filter: Filter::Match(Path(vec![USER_LOGIN.0]), name.into()), + })? { + txn.remove(row)?; + } + Ok(()) + })?; + Ok(Flash::success( + Redirect::to(u_admin_users()), + tr(ri.lang, "admin.users.remove_success"), + )) +} |