aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-02-20 01:23:38 +0100
committermetamuffin <metamuffin@disroot.org>2026-02-20 01:23:38 +0100
commit5caf1f1db721d6dee2ddb5d0613e8c9914ccf879 (patch)
tree7816c2a9e1a5222f8068ab2cf941df55743ba6d3
parent62984a7250c8998556e0258d67964e8e481b243c (diff)
downloadjellything-5caf1f1db721d6dee2ddb5d0613e8c9914ccf879.tar
jellything-5caf1f1db721d6dee2ddb5d0613e8c9914ccf879.tar.bz2
jellything-5caf1f1db721d6dee2ddb5d0613e8c9914ccf879.tar.zst
admin log
-rw-r--r--Cargo.lock2
-rw-r--r--common/Cargo.toml2
-rw-r--r--common/src/api.rs4
-rw-r--r--common/src/internal.rs31
-rw-r--r--common/src/routes.rs3
-rw-r--r--server/src/logger.rs23
-rw-r--r--server/src/routes.rs5
-rw-r--r--server/src/ui/admin/log.rs62
-rw-r--r--server/src/ui/admin/mod.rs1
-rw-r--r--ui/client-scripts/src/log_live.ts4
-rw-r--r--ui/src/components/admin_log.rs (renamed from ui/src/old/admin/log.rs)20
-rw-r--r--ui/src/components/mod.rs1
-rw-r--r--ui/src/lib.rs5
-rw-r--r--ui/src/scaffold.rs4
14 files changed, 95 insertions, 72 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3ded137..859a981 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1788,6 +1788,8 @@ version = "0.1.0"
dependencies = [
"jellyobject",
"jellystream-types",
+ "serde",
+ "serde_json",
]
[[package]]
diff --git a/common/Cargo.toml b/common/Cargo.toml
index 4eae9f8..fabd3d2 100644
--- a/common/Cargo.toml
+++ b/common/Cargo.toml
@@ -6,3 +6,5 @@ edition = "2024"
[dependencies]
jellystream-types = { path = "../stream/types" }
jellyobject = { path = "object", features = ["json"] }
+serde_json = "1.0.149"
+serde = { version = "1.0.228", features = ["derive"] }
diff --git a/common/src/api.rs b/common/src/api.rs
index 3c4e958..12d9243 100644
--- a/common/src/api.rs
+++ b/common/src/api.rs
@@ -26,11 +26,13 @@ fields! {
VIEW_ADMIN_DASHBOARD: () = b"adda";
VIEW_ADMIN_IMPORT: Object = b"adim";
VIEW_ADMIN_INFO: Object = b"adin";
+ VIEW_ADMIN_LOG: Object = b"adlo";
ADMIN_IMPORT_BUSY: () = b"busy";
ADMIN_IMPORT_ERROR: &str = b"erro"; // multi
ADMIN_INFO_TITLE: &str = b"aiti";
ADMIN_INFO_TEXT: &str = b"aite";
+ ADMIN_LOG_MESSAGE: &str = b"aite";
NKU_NODE: Object = b"node";
NKU_UDATA: Object = b"udat";
@@ -38,7 +40,7 @@ fields! {
NODELIST_TITLE: &str = b"titl";
NODELIST_DISPLAYSTYLE: Tag = b"dsty";
- NODELIST_ITEM: Object = b"item";
+ NODELIST_ITEM: Object = b"item"; // multi
MESSAGE_KIND: &str = b"kind";
MESSAGE_TEXT: &str = b"text";
diff --git a/common/src/internal.rs b/common/src/internal.rs
index 58a2dae..5aedfc7 100644
--- a/common/src/internal.rs
+++ b/common/src/internal.rs
@@ -4,9 +4,40 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
+use std::fmt::Display;
+
use jellyobject::fields;
+use serde::{Deserialize, Serialize};
fields! {
IM_PATH: &str = b"Ipth";
IM_MTIME: u64 = b"Imtm";
}
+
+#[derive(Serialize, Deserialize, Clone)]
+pub struct LogLine {
+ pub time: String,
+ pub module: Option<&'static str>,
+ pub level: LogLevel,
+ pub message: String,
+}
+
+#[derive(Serialize, Deserialize, Clone, Copy, PartialEq)]
+pub enum LogLevel {
+ Trace,
+ Debug,
+ Info,
+ Warn,
+ Error,
+}
+impl Display for LogLevel {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(match self {
+ LogLevel::Trace => "trace",
+ LogLevel::Debug => "debug",
+ LogLevel::Info => "info",
+ LogLevel::Warn => "warn",
+ LogLevel::Error => "error",
+ })
+ }
+} \ No newline at end of file
diff --git a/common/src/routes.rs b/common/src/routes.rs
index fcef144..82a6f45 100644
--- a/common/src/routes.rs
+++ b/common/src/routes.rs
@@ -73,9 +73,6 @@ pub fn u_admin_import_post(incremental: bool) -> String {
pub fn u_admin_update_search() -> String {
"/admin/update_search".to_string()
}
-pub fn u_account_register() -> String {
- "/account/register".to_owned()
-}
pub fn u_account_login() -> String {
"/account/login".to_owned()
}
diff --git a/server/src/logger.rs b/server/src/logger.rs
index e7419ba..8ba572f 100644
--- a/server/src/logger.rs
+++ b/server/src/logger.rs
@@ -4,9 +4,9 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-use chrono::{DateTime, Utc};
+use chrono::Utc;
+use jellycommon::internal::{LogLevel, LogLine};
use log::Level;
-use serde::{Deserialize, Serialize};
use std::{
collections::VecDeque,
sync::{Arc, LazyLock, RwLock},
@@ -14,7 +14,6 @@ use std::{
use tokio::sync::broadcast;
const MAX_LOG_LEN: usize = 4096;
-
static LOGGER: LazyLock<Log> = LazyLock::new(Log::default);
pub fn setup_logger() {
@@ -22,22 +21,6 @@ pub fn setup_logger() {
log::set_max_level(log::LevelFilter::Debug);
}
-pub struct LogLine {
- pub time: DateTime<Utc>,
- pub module: Option<&'static str>,
- pub level: LogLevel,
- pub message: String,
-}
-
-#[derive(Serialize, Deserialize, Clone, Copy, PartialEq)]
-pub enum LogLevel {
- Trace,
- Debug,
- Info,
- Warn,
- Error,
-}
-
type LogBuffer = VecDeque<Arc<LogLine>>;
pub struct Log {
@@ -92,7 +75,7 @@ impl Log {
fn do_log(&self, record: &log::Record) {
let time = Utc::now();
let line = Arc::new(LogLine {
- time,
+ time: time.to_rfc3339(),
module: record.module_path_static(),
level: match record.level() {
Level::Error => LogLevel::Error,
diff --git a/server/src/routes.rs b/server/src/routes.rs
index acf6ffd..4a875f4 100644
--- a/server/src/routes.rs
+++ b/server/src/routes.rs
@@ -15,6 +15,7 @@ use crate::{
account::{r_account_login, r_account_login_post, r_account_logout, r_account_logout_post},
admin::{
import::{r_admin_import, r_admin_import_post, r_admin_import_stream},
+ log::{r_admin_log, r_admin_log_stream},
r_admin_dashboard,
},
assets::r_image,
@@ -84,8 +85,8 @@ pub(super) fn build_rocket(state: Arc<State>) -> Rocket<Build> {
r_admin_import_post,
r_admin_import_stream,
// r_admin_invite,
- // r_admin_log_stream,
- // r_admin_log,
+ r_admin_log_stream,
+ r_admin_log,
// r_admin_remove_invite,
// r_admin_remove_user,
// r_admin_update_search,
diff --git a/server/src/ui/admin/log.rs b/server/src/ui/admin/log.rs
index da70360..0965a25 100644
--- a/server/src/ui/admin/log.rs
+++ b/server/src/ui/admin/log.rs
@@ -3,50 +3,60 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-use crate::{request_info::RequestInfo, ui::error::MyResult};
+use crate::{
+ logger::{get_log_buffer, get_log_stream},
+ request_info::RequestInfo,
+ ui::error::MyResult,
+};
+use jellyui::{Scaffold, ServerLogPage, render_log_line};
use rocket::{get, response::content::RawHtml};
use rocket_ws::{Message, Stream, WebSocket};
use serde_json::json;
#[get("/admin/log?<warnonly>", rank = 2)]
pub fn r_admin_log(ri: RequestInfo, warnonly: bool) -> MyResult<RawHtml<String>> {
- ri.session.assert_admin()?;
+ ri.require_admin()?;
let messages = get_log_buffer(warnonly)
.into_iter()
.map(|l| render_log_line(&l))
.collect::<Vec<_>>();
- Ok(RawHtml(render_page(
- &ServerLogPage {
- messages: &messages,
- warnonly,
- },
- ri.render_info(),
- )))
+
+ Ok(RawHtml(
+ Scaffold {
+ class: "theme-purple",
+ main: ServerLogPage {
+ messages: &messages,
+ warnonly,
+ },
+ ri: &ri.render_info(),
+ title: "Admin Log",
+ }
+ .to_string(),
+ ))
}
#[get("/admin/log?stream&<warnonly>&<html>", rank = 1)]
pub fn r_admin_log_stream(
- session: A<Session>,
+ ri: RequestInfo,
ws: WebSocket,
warnonly: bool,
html: bool,
-) -> Stream!['static] {
- // TODO type problems
- let ok = session.0.assert_admin().is_ok();
+) -> MyResult<Stream!['static]> {
+ ri.require_admin()?;
let mut stream = get_log_stream(warnonly);
- Stream! { ws =>
- if !ok {
- yield Message::Text("unauthorized".to_string());
- } else if html {
- let _ = ws;
- while let Ok(line) = stream.recv().await {
- yield Message::Text(render_log_line(&line));
- }
- } else {
- let _ = ws;
- while let Ok(line) = stream.recv().await {
- yield Message::Text(json!(line).to_string());
+ Ok({
+ Stream! { ws =>
+ if html {
+ let _ = ws;
+ while let Ok(line) = stream.recv().await {
+ yield Message::Text(render_log_line(&line));
+ }
+ } else {
+ let _ = ws;
+ while let Ok(line) = stream.recv().await {
+ yield Message::Text(json!(line).to_string());
+ }
}
}
- }
+ })
}
diff --git a/server/src/ui/admin/mod.rs b/server/src/ui/admin/mod.rs
index 57f00db..8413ead 100644
--- a/server/src/ui/admin/mod.rs
+++ b/server/src/ui/admin/mod.rs
@@ -5,6 +5,7 @@
*/
pub mod import;
+pub mod log;
use super::error::MyResult;
use crate::{request_info::RequestInfo, ui_responder::UiResponse};
diff --git a/ui/client-scripts/src/log_live.ts b/ui/client-scripts/src/log_live.ts
index b8af11e..d16553c 100644
--- a/ui/client-scripts/src/log_live.ts
+++ b/ui/client-scripts/src/log_live.ts
@@ -5,8 +5,8 @@
*/
/// <reference lib="dom" />
globalThis.addEventListener("DOMContentLoaded", () => {
- if (!document.body.classList.contains("admin_log")) return
- const log = document.getElementById("log")!
+ const log = document.getElementById("log")
+ if (!log) return
const warnonly = new URL(globalThis.location.href).searchParams.get("warnonly") == "true"
const ws = new WebSocket(`/admin/log?stream&warnonly=${warnonly}&html=true`)
diff --git a/ui/src/old/admin/log.rs b/ui/src/components/admin_log.rs
index 637158f..abec7fe 100644
--- a/ui/src/old/admin/log.rs
+++ b/ui/src/components/admin_log.rs
@@ -4,23 +4,13 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-use crate::Page;
-use jellycommon::routes::u_admin_log;
+use jellycommon::{
+ internal::{LogLevel, LogLine},
+ routes::u_admin_log,
+};
use markup::raw;
use std::fmt::Write;
-impl Page for ServerLogPage<'_> {
- fn title(&self) -> String {
- "Server Log".to_string()
- }
- fn class(&self) -> Option<&'static str> {
- Some("admin_log")
- }
- fn to_render(&self) -> markup::DynRender<'_> {
- markup::new!(@self)
- }
-}
-
markup::define! {
ServerLogPage<'a>(warnonly: bool, messages: &'a [String]) {
h1 { "Server Log" }
@@ -33,7 +23,7 @@ markup::define! {
}
ServerLogLine<'a>(e: &'a LogLine) {
tr[class=format!("level-{}", e.level).to_ascii_lowercase()] {
- td.time { @e.time.to_rfc3339() }
+ td.time { @e.time }
td.loglevel { @format_level(e.level) }
td.module { @e.module }
td { @markup::raw(vt100_to_html(&e.message)) }
diff --git a/ui/src/components/mod.rs b/ui/src/components/mod.rs
index c3ba9b0..15b2ae2 100644
--- a/ui/src/components/mod.rs
+++ b/ui/src/components/mod.rs
@@ -12,6 +12,7 @@ pub mod node_list;
pub mod node_page;
pub mod props;
pub mod stats;
+pub mod admin_log;
use crate::{
RenderInfo,
diff --git a/ui/src/lib.rs b/ui/src/lib.rs
index 63a2d07..f32657d 100644
--- a/ui/src/lib.rs
+++ b/ui/src/lib.rs
@@ -10,9 +10,12 @@ mod scaffold;
pub use jellyui_client_scripts::*;
pub use jellyui_client_style::*;
+pub use components::admin_log::ServerLogPage;
+pub use components::admin_log::render_log_line;
pub use jellyui_locale::tr;
+pub use scaffold::Scaffold;
-use crate::{components::View, scaffold::Scaffold};
+use crate::components::View;
use jellycommon::{jellyobject::Object, *};
use serde::{Deserialize, Serialize};
diff --git a/ui/src/scaffold.rs b/ui/src/scaffold.rs
index 5a70460..f24550d 100644
--- a/ui/src/scaffold.rs
+++ b/ui/src/scaffold.rs
@@ -7,8 +7,8 @@
use crate::RenderInfo;
use jellycommon::{
routes::{
- u_account_login, u_account_logout, u_account_register, u_account_settings,
- u_admin_dashboard, u_home, u_items, u_node_slug, u_search, u_stats,
+ u_account_login, u_account_logout, u_account_settings, u_admin_dashboard, u_home, u_items,
+ u_node_slug, u_search, u_stats,
},
user::{USER_ADMIN, USER_NAME},
};