aboutsummaryrefslogtreecommitdiff
path: root/server/src/ui/admin/users.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/ui/admin/users.rs')
-rw-r--r--server/src/ui/admin/users.rs120
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"),
+ ))
+}