aboutsummaryrefslogtreecommitdiff
path: root/server/src/routes/ui/admin
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/routes/ui/admin')
-rw-r--r--server/src/routes/ui/admin/mod.rs170
-rw-r--r--server/src/routes/ui/admin/user.rs67
2 files changed, 95 insertions, 142 deletions
diff --git a/server/src/routes/ui/admin/mod.rs b/server/src/routes/ui/admin/mod.rs
index 1fba6c0..160999b 100644
--- a/server/src/routes/ui/admin/mod.rs
+++ b/server/src/routes/ui/admin/mod.rs
@@ -6,12 +6,9 @@
pub mod log;
pub mod user;
-use super::{
- account::session::AdminSession,
- assets::{resolve_asset, AVIF_QUALITY, AVIF_SPEED},
-};
+use super::account::session::AdminSession;
use crate::{
- database::DataAcid,
+ database::Database,
routes::ui::{
admin::log::rocket_uri_macro_r_admin_log,
error::MyResult,
@@ -20,16 +17,7 @@ use crate::{
uri,
};
use anyhow::{anyhow, Context};
-use humansize::{format_size, DECIMAL};
-use jellybase::{
- assetfed::AssetInner,
- database::{
- redb::{ReadableTable, ReadableTableMetadata},
- tantivy::query::Bm25StatisticsProvider,
- TableExt, T_INVITE, T_NODE, T_USER_NODE,
- },
- CONF,
-};
+use jellybase::CONF;
use markup::DynRender;
use rand::Rng;
use rocket::{form::Form, get, post, FromForm, State};
@@ -40,28 +28,16 @@ use user::rocket_uri_macro_r_admin_users;
#[get("/admin/dashboard")]
pub async fn r_admin_dashboard(
_session: AdminSession,
- database: &State<DataAcid>,
+ database: &State<Database>,
) -> MyResult<DynLayoutPage<'static>> {
admin_dashboard(database, None).await
}
pub async fn admin_dashboard<'a>(
- database: &DataAcid,
+ database: &Database,
flash: Option<MyResult<String>>,
) -> MyResult<DynLayoutPage<'a>> {
- let invites = {
- let txn = database.begin_read()?;
- let table = txn.open_table(T_INVITE)?;
- let i = table
- .iter()?
- .map(|a| {
- let (x, _) = a.unwrap();
- x.value().to_owned()
- })
- .collect::<Vec<_>>();
- drop(table);
- i
- };
+ let invites = database.list_invites()?;
let flash = flash.map(|f| f.map_err(|e| format!("{e:?}")));
// let last_import_err = IMPORT_ERRORS.read().await.to_owned();
@@ -129,11 +105,10 @@ pub async fn admin_dashboard<'a>(
#[post("/admin/generate_invite")]
pub async fn r_admin_invite(
_session: AdminSession,
- database: &State<DataAcid>,
+ database: &State<Database>,
) -> MyResult<DynLayoutPage<'static>> {
let i = format!("{}", rand::rng().random::<u128>());
- T_INVITE.insert(database, &*i, ())?;
-
+ database.create_invite(&i)?;
admin_dashboard(database, Some(Ok(format!("Invite: {}", i)))).await
}
@@ -145,14 +120,13 @@ pub struct DeleteInvite {
#[post("/admin/remove_invite", data = "<form>")]
pub async fn r_admin_remove_invite(
session: AdminSession,
- database: &State<DataAcid>,
+ database: &State<Database>,
form: Form<DeleteInvite>,
) -> MyResult<DynLayoutPage<'static>> {
drop(session);
- T_INVITE
- .remove(database, form.invite.as_str())?
- .ok_or(anyhow!("invite did not exist"))?;
-
+ if !database.delete_invite(&form.invite)? {
+ Err(anyhow!("invite does not exist"))?;
+ };
admin_dashboard(database, Some(Ok("Invite invalidated".into()))).await
}
@@ -178,7 +152,7 @@ pub async fn r_admin_remove_invite(
#[post("/admin/delete_cache")]
pub async fn r_admin_delete_cache(
session: AdminSession,
- database: &State<DataAcid>,
+ database: &State<Database>,
) -> MyResult<DynLayoutPage<'static>> {
drop(session);
let t = Instant::now();
@@ -202,7 +176,7 @@ fn is_transcoding() -> bool {
#[post("/admin/transcode_posters")]
pub async fn r_admin_transcode_posters(
session: AdminSession,
- database: &State<DataAcid>,
+ database: &State<Database>,
) -> MyResult<DynLayoutPage<'static>> {
drop(session);
let _permit = SEM_TRANSCODING
@@ -211,24 +185,25 @@ pub async fn r_admin_transcode_posters(
let t = Instant::now();
- {
- let txn = database.begin_read()?;
- let nodes = txn.open_table(T_NODE)?;
- for node in nodes.iter()? {
- let (_, node) = node?;
- if let Some(poster) = &node.value().0.poster {
- let asset = AssetInner::deser(&poster.0)?;
- if asset.is_federated() {
- continue;
- }
- let source = resolve_asset(asset).await.context("resolving asset")?;
- jellytranscoder::image::transcode(source, AVIF_QUALITY, AVIF_SPEED, 1024)
- .await
- .context("transcoding asset")?;
- }
- }
- }
- drop(_permit);
+ // TODO
+ // {
+ // let txn = database.begin_read()?;
+ // let nodes = txn.open_table(T_NODE)?;
+ // for node in nodes.iter()? {
+ // let (_, node) = node?;
+ // if let Some(poster) = &node.value().0.poster {
+ // let asset = AssetInner::deser(&poster.0)?;
+ // if asset.is_federated() {
+ // continue;
+ // }
+ // let source = resolve_asset(asset).await.context("resolving asset")?;
+ // jellytranscoder::image::transcode(source, AVIF_QUALITY, AVIF_SPEED, 1024)
+ // .await
+ // .context("transcoding asset")?;
+ // }
+ // }
+ // }
+ // drop(_permit);
admin_dashboard(
database,
@@ -240,47 +215,48 @@ pub async fn r_admin_transcode_posters(
.await
}
-fn db_stats(db: &DataAcid) -> anyhow::Result<DynRender> {
- let txn = db.inner.begin_read()?;
- let stats = [
- ("node", txn.open_table(T_NODE)?.stats()?),
- ("user", txn.open_table(T_USER_NODE)?.stats()?),
- ("user-node", txn.open_table(T_USER_NODE)?.stats()?),
- ("invite", txn.open_table(T_INVITE)?.stats()?),
- ];
+fn db_stats(_db: &Database) -> anyhow::Result<DynRender> {
+ // TODO
+ // let txn = db.inner.begin_read()?;
+ // let stats = [
+ // ("node", txn.open_table(T_NODE)?.stats()?),
+ // ("user", txn.open_table(T_USER_NODE)?.stats()?),
+ // ("user-node", txn.open_table(T_USER_NODE)?.stats()?),
+ // ("invite", txn.open_table(T_INVITE)?.stats()?),
+ // ];
- let cache_stats = db.node_index.reader.searcher().doc_store_cache_stats();
- let ft_total_docs = db.node_index.reader.searcher().total_num_docs()?;
+ // let cache_stats = db.node_index.reader.searcher().doc_store_cache_stats();
+ // let ft_total_docs = db.node_index.reader.searcher().total_num_docs()?;
Ok(markup::new! {
- h3 { "Key-Value-Store Statistics" }
- table.border {
- tbody {
- tr {
- th { "table name" }
- th { "tree height" }
- th { "stored bytes" }
- th { "metadata bytes" }
- th { "fragmented bytes" }
- th { "branch pages" }
- th { "leaf pages" }
- }
- @for (name, stats) in &stats { tr {
- td { @name }
- td { @stats.tree_height() }
- td { @format_size(stats.stored_bytes(), DECIMAL) }
- td { @format_size(stats.metadata_bytes(), DECIMAL) }
- td { @format_size(stats.fragmented_bytes(), DECIMAL) }
- td { @stats.branch_pages() }
- td { @stats.leaf_pages() }
- }}
- }
- }
- h3 { "Search Engine Statistics" }
- ul {
- li { "Total documents: " @ft_total_docs }
- li { "Cache misses: " @cache_stats.cache_misses }
- li { "Cache hits: " @cache_stats.cache_hits }
- }
+ // h3 { "Key-Value-Store Statistics" }
+ // table.border {
+ // tbody {
+ // tr {
+ // th { "table name" }
+ // th { "tree height" }
+ // th { "stored bytes" }
+ // th { "metadata bytes" }
+ // th { "fragmented bytes" }
+ // th { "branch pages" }
+ // th { "leaf pages" }
+ // }
+ // @for (name, stats) in &stats { tr {
+ // td { @name }
+ // td { @stats.tree_height() }
+ // td { @format_size(stats.stored_bytes(), DECIMAL) }
+ // td { @format_size(stats.metadata_bytes(), DECIMAL) }
+ // td { @format_size(stats.fragmented_bytes(), DECIMAL) }
+ // td { @stats.branch_pages() }
+ // td { @stats.leaf_pages() }
+ // }}
+ // }
+ // }
+ // h3 { "Search Engine Statistics" }
+ // ul {
+ // li { "Total documents: " @ft_total_docs }
+ // li { "Cache misses: " @cache_stats.cache_misses }
+ // li { "Cache hits: " @cache_stats.cache_hits }
+ // }
})
}
diff --git a/server/src/routes/ui/admin/user.rs b/server/src/routes/ui/admin/user.rs
index 524f849..7ba6d4e 100644
--- a/server/src/routes/ui/admin/user.rs
+++ b/server/src/routes/ui/admin/user.rs
@@ -4,7 +4,7 @@
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
use crate::{
- database::DataAcid,
+ database::Database,
routes::ui::{
account::session::AdminSession,
error::MyResult,
@@ -13,36 +13,23 @@ use crate::{
uri,
};
use anyhow::{anyhow, Context};
-use jellybase::database::{redb::ReadableTable, Ser, TableExt, T_USER};
use jellycommon::user::{PermissionSet, UserPermission};
use rocket::{form::Form, get, post, FromForm, FromFormField, State};
#[get("/admin/users")]
pub fn r_admin_users(
_session: AdminSession,
- database: &State<DataAcid>,
+ database: &State<Database>,
) -> MyResult<DynLayoutPage<'static>> {
user_management(database, None)
}
fn user_management<'a>(
- database: &DataAcid,
+ database: &Database,
flash: Option<MyResult<String>>,
) -> MyResult<DynLayoutPage<'a>> {
// TODO this doesnt scale, pagination!
- let users = {
- let txn = database.begin_read()?;
- let table = txn.open_table(T_USER)?;
- let i = table
- .iter()?
- .map(|a| {
- let (x, y) = a.unwrap();
- (x.value().to_owned(), y.value().0)
- })
- .collect::<Vec<_>>();
- drop(table);
- i
- };
+ let users = database.list_users()?;
let flash = flash.map(|f| f.map_err(|e| format!("{e:?}")));
Ok(LayoutPage {
@@ -51,7 +38,7 @@ fn user_management<'a>(
h1 { "User Management" }
@FlashDisplay { flash: flash.clone() }
h2 { "All Users" }
- ul { @for (_, u) in &users {
+ ul { @for u in &users {
li {
a[href=uri!(r_admin_user(&u.name))] { @format!("{:?}", u.display_name) " (" @u.name ")" }
}
@@ -64,19 +51,19 @@ fn user_management<'a>(
#[get("/admin/user/<name>")]
pub fn r_admin_user<'a>(
_session: AdminSession,
- database: &State<DataAcid>,
+ database: &State<Database>,
name: &'a str,
) -> MyResult<DynLayoutPage<'a>> {
manage_single_user(database, None, name.to_string())
}
fn manage_single_user<'a>(
- database: &DataAcid,
+ database: &Database,
flash: Option<MyResult<String>>,
name: String,
) -> MyResult<DynLayoutPage<'a>> {
- let user = T_USER
- .get(database, &*name)?
+ let user = database
+ .get_user(&name)?
.ok_or(anyhow!("user does not exist"))?;
let flash = flash.map(|f| f.map_err(|e| format!("{e:?}")));
@@ -152,31 +139,21 @@ pub enum GrantState {
#[post("/admin/update_user_permission", data = "<form>")]
pub fn r_admin_user_permission(
session: AdminSession,
- database: &State<DataAcid>,
+ database: &State<Database>,
form: Form<UserPermissionForm>,
) -> MyResult<DynLayoutPage<'static>> {
drop(session);
let perm = serde_json::from_str::<UserPermission>(&form.permission)
.context("parsing provided permission")?;
- let txn = database.begin_write()?;
- let mut users = txn.open_table(T_USER)?;
-
- let mut user = users
- .get(&*form.name)?
- .ok_or(anyhow!("user missing"))?
- .value()
- .0;
-
- match form.action {
- GrantState::Grant => drop(user.permissions.0.insert(perm.clone(), true)),
- GrantState::Revoke => drop(user.permissions.0.insert(perm.clone(), false)),
- GrantState::Unset => drop(user.permissions.0.remove(&perm)),
- }
-
- users.insert(&*form.name, Ser(user))?;
- drop(users);
- txn.commit()?;
+ database.update_user(&form.name, |user| {
+ match form.action {
+ GrantState::Grant => drop(user.permissions.0.insert(perm.clone(), true)),
+ GrantState::Revoke => drop(user.permissions.0.insert(perm.clone(), false)),
+ GrantState::Unset => drop(user.permissions.0.remove(&perm)),
+ }
+ Ok(())
+ })?;
manage_single_user(
database,
@@ -188,12 +165,12 @@ pub fn r_admin_user_permission(
#[post("/admin/remove_user", data = "<form>")]
pub fn r_admin_remove_user(
session: AdminSession,
- database: &State<DataAcid>,
+ database: &State<Database>,
form: Form<DeleteUser>,
) -> MyResult<DynLayoutPage<'static>> {
drop(session);
- T_USER
- .remove(database, form.name.as_str())?
- .ok_or(anyhow!("user did not exist"))?;
+ if !database.delete_user(&form.name)? {
+ Err(anyhow!("user did not exist"))?;
+ }
user_management(database, Some(Ok("User removed".into())))
}