diff options
| author | metamuffin <metamuffin@disroot.org> | 2026-01-25 15:01:38 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2026-01-25 15:01:38 +0100 |
| commit | 5075aede44cb8ab2df10e6debba38483e8d11e96 (patch) | |
| tree | f719e4b4a0c29f3a27b4fa7cf0a6ee6f7739125c | |
| parent | 53361f4c6027d1569a707ce58889bc2c2ea3749c (diff) | |
| download | jellything-5075aede44cb8ab2df10e6debba38483e8d11e96.tar jellything-5075aede44cb8ab2df10e6debba38483e8d11e96.tar.bz2 jellything-5075aede44cb8ab2df10e6debba38483e8d11e96.tar.zst | |
remove some unused imports; css reload; port login logic
| -rw-r--r-- | common/src/user.rs | 2 | ||||
| -rw-r--r-- | database/src/table.rs | 6 | ||||
| -rw-r--r-- | import/src/lib.rs | 6 | ||||
| -rw-r--r-- | logic/src/login.rs | 49 | ||||
| -rw-r--r-- | logic/src/permission.rs | 18 | ||||
| -rw-r--r-- | logic/src/session.rs | 0 | ||||
| -rw-r--r-- | logic/src/stats.rs | 42 | ||||
| -rw-r--r-- | server/src/api.rs | 14 | ||||
| -rw-r--r-- | server/src/auth.rs | 63 | ||||
| -rw-r--r-- | server/src/routes.rs | 3 | ||||
| -rw-r--r-- | server/src/ui/account/mod.rs | 15 | ||||
| -rw-r--r-- | server/src/ui/admin/import.rs | 10 | ||||
| -rw-r--r-- | server/src/ui/admin/log.rs | 13 | ||||
| -rw-r--r-- | server/src/ui/admin/mod.rs | 2 | ||||
| -rw-r--r-- | server/src/ui/admin/user.rs | 15 | ||||
| -rw-r--r-- | server/src/ui/assets.rs | 3 | ||||
| -rw-r--r-- | server/src/ui/error.rs | 2 | ||||
| -rw-r--r-- | server/src/ui/home.rs | 3 | ||||
| -rw-r--r-- | server/src/ui/items.rs | 6 | ||||
| -rw-r--r-- | server/src/ui/mod.rs | 12 | ||||
| -rw-r--r-- | server/src/ui/node.rs | 12 | ||||
| -rw-r--r-- | server/src/ui/player.rs | 19 | ||||
| -rw-r--r-- | server/src/ui/search.rs | 5 | ||||
| -rw-r--r-- | server/src/ui/stats.rs | 5 | ||||
| -rw-r--r-- | server/src/ui/style.rs | 47 | ||||
| -rw-r--r-- | tool/src/add.rs | 1 | ||||
| -rw-r--r-- | ui/client-style/Cargo.toml | 7 | ||||
| -rw-r--r-- | ui/client-style/src/lib.rs | 13 |
28 files changed, 114 insertions, 279 deletions
diff --git a/common/src/user.rs b/common/src/user.rs index 939438d..47716da 100644 --- a/common/src/user.rs +++ b/common/src/user.rs @@ -8,7 +8,7 @@ use jellyobject::fields; fields! { USER_LOGIN: &str = 1001 "login"; - USER_PASSWORD: &str = 1002 "password"; + USER_PASSWORD: &[u8] = 1002 "password"; USER_NAME: &str = 1003 "name"; USER_ADMIN: () = 1004 "admin"; diff --git a/database/src/table.rs b/database/src/table.rs index 0b6382a..a96f96c 100644 --- a/database/src/table.rs +++ b/database/src/table.rs @@ -93,11 +93,11 @@ impl Table { &self, txn: &dyn ReadTransaction, query: Query, - ) -> Box<dyn Iterator<Item = RowNum>> { + ) -> Box<dyn Iterator<Item = Result<RowNum>>> { todo!() } - pub fn query_single(&self, txn: &dyn ReadTransaction, query: Query) -> Option<RowNum> { - self.query(txn, query).next() + pub fn query_single(&self, txn: &dyn ReadTransaction, query: Query) -> Result<Option<RowNum>> { + self.query(txn, query).next().transpose() } } diff --git a/import/src/lib.rs b/import/src/lib.rs index bec5786..2e36c58 100644 --- a/import/src/lib.rs +++ b/import/src/lib.rs @@ -124,7 +124,7 @@ impl ImportConfig { ) -> Result<RowNum> { let mut row = 0; self.db.write_transaction(&mut |txn| { - row = match self.nodes.query_single(txn, node_slug_query(slug)) { + row = match self.nodes.query_single(txn, node_slug_query(slug))? { Some(r) => r, None => self .nodes @@ -462,7 +462,7 @@ fn compare_mtime(dba: &ImportConfig, path: &Path) -> Result<bool> { ), sort: Sort::None, }, - ) { + )? { None => was_changed = true, Some(row) => { let meta = dba.import_meta.get(txn, row)?.unwrap(); @@ -488,7 +488,7 @@ fn update_mtime(dba: &ImportConfig, path: &Path) -> Result<()> { ), sort: Sort::None, }, - ) { + )? { Some(row) => row, None => dba.import_meta.insert( txn, diff --git a/logic/src/login.rs b/logic/src/login.rs index f79fafc..0d616ff 100644 --- a/logic/src/login.rs +++ b/logic/src/login.rs @@ -21,52 +21,3 @@ pub fn create_admin_account() -> Result<()> { } Ok(()) } - -pub fn login_logic( - username: &str, - password: &str, - expire: Option<i64>, - drop_permissions: Option<HashSet<UserPermission>>, -) -> Result<String> { - // hashing the password regardless if the accounts exists to better resist timing attacks - let password = hash_password(username, password); - - let mut user = DATABASE - .get_user(username)? - .ok_or(anyhow!("invalid password"))?; - - if user.password != password { - Err(anyhow!("invalid password"))? - } - - if let Some(ep) = drop_permissions { - // remove all grant perms that are in `ep` - user.permissions - .0 - .retain(|p, val| if *val { !ep.contains(p) } else { true }) - } - - Ok(create( - user.name, - user.permissions, - Duration::from_days( - CONF.login_expire - .min(expire.unwrap_or(i64::MAX)) - .try_into() - .unwrap(), - ), - )) -} - -pub fn hash_password(username: &str, password: &str) -> Vec<u8> { - Argon2::default() - .hash_password( - format!("{username}\0{password}").as_bytes(), - <&str as TryInto<Salt>>::try_into("IYMa13osbNeLJKnQ1T8LlA").unwrap(), - ) - .unwrap() - .hash - .unwrap() - .as_bytes() - .to_vec() -} diff --git a/logic/src/permission.rs b/logic/src/permission.rs deleted file mode 100644 index 079d7c5..0000000 --- a/logic/src/permission.rs +++ /dev/null @@ -1,18 +0,0 @@ -/* - 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 crate::session::Session; -use anyhow::{Result, anyhow}; - -impl Session { - pub fn assert_admin(&self) -> Result<()> { - if self.user.admin { - Ok(()) - } else { - Err(anyhow!("Permission denied.")) - } - } -} diff --git a/logic/src/session.rs b/logic/src/session.rs deleted file mode 100644 index e69de29..0000000 --- a/logic/src/session.rs +++ /dev/null diff --git a/logic/src/stats.rs b/logic/src/stats.rs deleted file mode 100644 index 38a4c4e..0000000 --- a/logic/src/stats.rs +++ /dev/null @@ -1,42 +0,0 @@ -/* - 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 crate::{DATABASE, session::Session}; -use anyhow::Result; -use std::collections::BTreeMap; - -pub fn stats(session: &Session) -> Result<ApiStatsResponse> { - let mut items = DATABASE.list_nodes_with_udata(session.user.name.as_str())?; - items.retain(|(n, _)| n.visibility >= Visibility::Reduced); - - trait BinExt { - fn update(&mut self, node: &Node); - } - impl BinExt for StatsBin { - fn update(&mut self, node: &Node) { - self.count += 1; - self.size += node.storage_size; - if node.storage_size > self.max_size.0 { - self.max_size = (node.storage_size, node.slug.clone()) - } - if let Some(m) = &node.media { - self.runtime += m.duration; - if m.duration > self.max_runtime.0 { - self.max_runtime = (m.duration, node.slug.clone()) - } - } - } - } - - let mut total = StatsBin::default(); - let mut kinds = BTreeMap::<NodeKind, StatsBin>::new(); - for (i, _) in items { - total.update(&i); - kinds.entry(i.kind).or_default().update(&i); - } - - Ok(ApiStatsResponse { kinds, total }) -} diff --git a/server/src/api.rs b/server/src/api.rs index 45bcd90..2b3d016 100644 --- a/server/src/api.rs +++ b/server/src/api.rs @@ -4,8 +4,7 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ use super::ui::error::MyResult; -use rocket::{get, post, response::Redirect, serde::json::Json}; -use serde_json::{Value, json}; +use rocket::{get, response::Redirect, serde::json::Json}; #[get("/api")] pub fn r_api_root() -> Redirect { @@ -38,17 +37,6 @@ pub fn r_version() -> &'static str { // } // } -#[post("/api/create_session", data = "<data>")] -pub fn r_api_account_login(data: Json<CreateSessionParams>) -> MyResult<Value> { - let token = login_logic( - &data.username, - &data.password, - data.expire, - data.drop_permissions.clone(), - )?; - Ok(json!(token)) -} - #[get("/nodes_modified?<since>")] pub fn r_nodes_modified_since(session: A<Session>, since: u64) -> MyResult<Json<Vec<NodeID>>> { let nodes = get_nodes_modified_since(&session.0, since)?; diff --git a/server/src/auth.rs b/server/src/auth.rs index e84c4d1..0e523ed 100644 --- a/server/src/auth.rs +++ b/server/src/auth.rs @@ -5,8 +5,13 @@ */ use crate::State; -use anyhow::{Result, anyhow}; -use jellycommon::jellyobject::ObjectBuffer; +use anyhow::{Result, anyhow, bail}; +use argon2::{Argon2, PasswordHasher, password_hash::Salt}; +use jellycommon::{ + USER_LOGIN, USER_PASSWORD, + jellyobject::{ObjectBuffer, Path}, +}; +use jellydb::query::{Filter, Query, Sort}; pub fn token_to_user(state: &State, token: &str) -> Result<ObjectBuffer> { let user_row = token::validate(&state.session_key, token)?; @@ -20,6 +25,55 @@ pub fn token_to_user(state: &State, token: &str) -> Result<ObjectBuffer> { user.ok_or(anyhow!("user was deleted")) } +pub fn login(state: &State, username: &str, password: &str, expire: Option<i64>) -> Result<String> { + let password = hash_password(username, password); + + let mut user_row = None; + let mut user = None; + state.database.read_transaction(&mut |txn| { + user_row = state.users.query_single( + txn, + Query { + filter: Filter::Match(Path(vec![USER_LOGIN.0]), username.as_bytes().to_vec()), + sort: Sort::None, + }, + )?; + if let Some(ur) = user_row { + user = state.users.get(txn, ur)?; + } + Ok(()) + }); + + let (Some(user_row), Some(user)) = (user_row, user) else { + bail!("unknown user"); + }; + let Some(correct_pw) = user.as_object().get(USER_PASSWORD) else { + bail!("password login is disabled") + }; + if password != correct_pw { + bail!("incorrect password") + } + + Ok(token::create( + &state.session_key, + user_row, + expire.unwrap_or(60 * 60 * 24 * 30), + )) +} + +pub fn hash_password(username: &str, password: &str) -> Vec<u8> { + Argon2::default() + .hash_password( + format!("{username}\0{password}").as_bytes(), + <&str as TryInto<Salt>>::try_into("IYMa13osbNeLJKnQ1T8LlA").unwrap(), + ) + .unwrap() + .hash + .unwrap() + .as_bytes() + .to_vec() +} + pub mod token { use aes_gcm_siv::{ Aes256GcmSiv, KeyInit, @@ -32,7 +86,6 @@ pub mod token { }; use chrono::Utc; use jellydb::table::RowNum; - use std::time::Duration; pub struct SessionKey(Aes256GcmSiv); @@ -43,8 +96,8 @@ pub mod token { } } - pub fn create(sk: &SessionKey, user: RowNum, expire: Duration) -> String { - let expire_ts = Utc::now().timestamp() + expire.as_secs() as i64; + pub fn create(sk: &SessionKey, user: RowNum, expire: i64) -> String { + let expire_ts = Utc::now().timestamp() + expire; let mut plain = Vec::new(); plain.extend(user.to_be_bytes()); plain.extend(expire_ts.to_be_bytes()); diff --git a/server/src/routes.rs b/server/src/routes.rs index 62a70b7..19c76b2 100644 --- a/server/src/routes.rs +++ b/server/src/routes.rs @@ -5,7 +5,7 @@ */ use crate::{ State, - api::{r_api_account_login, r_api_root, r_nodes_modified_since, r_version}, + api::{r_api_root, r_nodes_modified_since, r_version}, compat::youtube::{r_youtube_channel, r_youtube_embed, r_youtube_watch}, logic::{ playersync::{PlayersyncChannels, r_playersync}, @@ -127,7 +127,6 @@ pub fn build_rocket(state: Arc<State>) -> Rocket<Build> { r_stats, r_stream, // API - r_api_account_login, r_nodes_modified_since, r_api_root, r_version, diff --git a/server/src/ui/account/mod.rs b/server/src/ui/account/mod.rs index 35cf52e..429b70a 100644 --- a/server/src/ui/account/mod.rs +++ b/server/src/ui/account/mod.rs @@ -6,25 +6,16 @@ pub mod settings; use super::error::MyError; -use crate::{ - request_info::{language::AcceptLanguage, A}, - ui::{error::MyResult, home::rocket_uri_macro_r_home}, -}; +use crate::ui::{error::MyResult, home::rocket_uri_macro_r_home}; use anyhow::anyhow; use jellyimport::is_importing; -use jellylogic::{account::register_user, login::login_logic, session::Session}; -use jellyui::{ - account::{AccountLogin, AccountLogout, AccountRegister, AccountRegisterSuccess}, - render_page, - scaffold::{RenderInfo, SessionInfo}, -}; use rocket::{ + FromForm, form::{Contextual, Form}, get, http::{Cookie, CookieJar}, post, - response::{content::RawHtml, Redirect}, - FromForm, + response::{Redirect, content::RawHtml}, }; use serde::{Deserialize, Serialize}; diff --git a/server/src/ui/admin/import.rs b/server/src/ui/admin/import.rs index fb33c67..79b8374 100644 --- a/server/src/ui/admin/import.rs +++ b/server/src/ui/admin/import.rs @@ -4,25 +4,19 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ -use std::time::Duration; - -use crate::{ - request_info::{A, RequestInfo}, - ui::error::MyResult, -}; +use crate::{request_info::RequestInfo, ui::error::MyResult}; use jellycommon::routes::u_admin_import; use jellyimport::{ is_importing, reporting::{IMPORT_ERRORS, IMPORT_PROGRESS}, }; -use jellylogic::{admin::do_import, session::Session}; -use jellyui::{admin::import::AdminImportPage, locale::tr, render_page}; use rocket::{ get, post, request::FlashMessage, response::{Flash, Redirect, content::RawHtml}, }; use rocket_ws::{Message, Stream, WebSocket}; +use std::time::Duration; use tokio::time::sleep; #[get("/admin/import", rank = 2)] diff --git a/server/src/ui/admin/log.rs b/server/src/ui/admin/log.rs index e948daa..da70360 100644 --- a/server/src/ui/admin/log.rs +++ b/server/src/ui/admin/log.rs @@ -3,18 +3,7 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2026 metamuffin <metamuffin.org> */ -use crate::{ - request_info::{A, RequestInfo}, - ui::error::MyResult, -}; -use jellylogic::{ - admin::log::{get_log_buffer, get_log_stream}, - session::Session, -}; -use jellyui::{ - admin::log::{ServerLogPage, render_log_line}, - render_page, -}; +use crate::{request_info::RequestInfo, ui::error::MyResult}; use rocket::{get, response::content::RawHtml}; use rocket_ws::{Message, Stream, WebSocket}; use serde_json::json; diff --git a/server/src/ui/admin/mod.rs b/server/src/ui/admin/mod.rs index 9759627..5ee05b7 100644 --- a/server/src/ui/admin/mod.rs +++ b/server/src/ui/admin/mod.rs @@ -11,8 +11,6 @@ use super::error::MyResult; use crate::request_info::RequestInfo; use jellycommon::routes::u_admin_dashboard; use jellyimport::is_importing; -use jellylogic::admin::{create_invite, delete_invite, list_invites, update_search_index}; -use jellyui::{admin::AdminDashboardPage, locale::tr, render_page}; use rocket::{ FromForm, form::Form, diff --git a/server/src/ui/admin/user.rs b/server/src/ui/admin/user.rs index 03950df..b4770c8 100644 --- a/server/src/ui/admin/user.rs +++ b/server/src/ui/admin/user.rs @@ -5,21 +5,12 @@ */ use crate::{request_info::RequestInfo, ui::error::MyResult}; use anyhow::Context; -use jellycommon::{ - routes::{u_admin_user, u_admin_users}, - user::UserPermission, -}; -use jellylogic::admin::user::{admin_users, delete_user, get_user, update_user_perms, GrantState}; -use jellyui::{ - admin::user::{AdminUserPage, AdminUsersPage}, - locale::tr, - render_page, -}; +use jellycommon::routes::{u_admin_user, u_admin_users}; use rocket::{ + FromForm, FromFormField, form::Form, get, post, - response::{content::RawHtml, Flash, Redirect}, - FromForm, FromFormField, + response::{Flash, Redirect, content::RawHtml}, }; #[get("/admin/users")] diff --git a/server/src/ui/assets.rs b/server/src/ui/assets.rs index 6dc6731..8f3fb4a 100644 --- a/server/src/ui/assets.rs +++ b/server/src/ui/assets.rs @@ -4,10 +4,7 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ use super::error::MyResult; -use crate::request_info::{A, cache::CacheControlImage}; use anyhow::{Context, anyhow}; -use jellycommon::{Asset, NodeID, PictureSlot, api::NodeFilterSort}; -use jellylogic::{assets::get_node_thumbnail, node::get_node, session::Session}; use rocket::{get, http::ContentType, response::Redirect}; use std::str::FromStr; diff --git a/server/src/ui/error.rs b/server/src/ui/error.rs index d94639a..0f279fc 100644 --- a/server/src/ui/error.rs +++ b/server/src/ui/error.rs @@ -3,8 +3,6 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2026 metamuffin <metamuffin.org> */ -use crate::CONF; -use jellyui::{error::ErrorPage, locale::Language, render_page, scaffold::RenderInfo}; use log::info; use rocket::{ catch, diff --git a/server/src/ui/home.rs b/server/src/ui/home.rs index 499c3cd..4e9fd28 100644 --- a/server/src/ui/home.rs +++ b/server/src/ui/home.rs @@ -5,9 +5,6 @@ */ use super::error::MyResult; -use crate::request_info::{accept::Accept, RequestInfo}; -use jellycommon::api::ApiHomeResponse; -use jellyui::{home::HomePage, render_page}; use rocket::{get, response::content::RawHtml, serde::json::Json, Either}; #[get("/home")] diff --git a/server/src/ui/items.rs b/server/src/ui/items.rs index 86aaf12..cc8c18f 100644 --- a/server/src/ui/items.rs +++ b/server/src/ui/items.rs @@ -4,11 +4,7 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ use super::error::MyError; -use crate::request_info::{accept::Accept, filter_sort::ANodeFilterSort, RequestInfo}; -use jellycommon::api::ApiItemsResponse; -use jellylogic::items::all_items; -use jellyui::{items::ItemsPage, render_page}; -use rocket::{get, response::content::RawHtml, serde::json::Json, Either}; +use rocket::{Either, get, response::content::RawHtml, serde::json::Json}; #[get("/items?<page>&<filter..>")] pub fn r_items( diff --git a/server/src/ui/mod.rs b/server/src/ui/mod.rs index 946401e..92b93fe 100644 --- a/server/src/ui/mod.rs +++ b/server/src/ui/mod.rs @@ -3,23 +3,17 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2026 metamuffin <metamuffin.org> */ -use crate::{ - request_info::{language::AcceptLanguage, A}, - CONF, -}; use error::MyResult; use home::rocket_uri_macro_r_home; -use jellylogic::session::Session; -use jellyui::{render_page, scaffold::RenderInfo, CustomPage}; use rocket::{ + Either, futures::FutureExt, get, - response::{content::RawHtml, Redirect}, - Either, + response::{Redirect, content::RawHtml}, }; use std::{future::Future, pin::Pin}; use tokio::{ - fs::{read_to_string, File}, + fs::{File, read_to_string}, io::AsyncRead, }; diff --git a/server/src/ui/node.rs b/server/src/ui/node.rs index fac1909..85beac6 100644 --- a/server/src/ui/node.rs +++ b/server/src/ui/node.rs @@ -4,18 +4,12 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ use super::error::MyResult; -use crate::request_info::{filter_sort::ANodeFilterSort, RequestInfo, A}; -use jellycommon::{ - api::{ApiNodeResponse, NodeFilterSort}, - NodeID, -}; -use jellylogic::node::get_node; -use jellyui::{node_page::NodePage, render_page}; -use rocket::{get, response::content::RawHtml, serde::json::Json, Either}; +use crate::request_info::RequestInfo; +use rocket::{Either, get, response::content::RawHtml, serde::json::Json}; #[get("/n/<id>?<parents>&<children>&<filter..>")] pub async fn r_node( - ri: RequestInfo, + ri: RequestInfo<'_>, id: A<NodeID>, filter: Option<ANodeFilterSort>, parents: bool, diff --git a/server/src/ui/player.rs b/server/src/ui/player.rs index d43f3ea..b9d7d2e 100644 --- a/server/src/ui/player.rs +++ b/server/src/ui/player.rs @@ -4,22 +4,11 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ use super::error::MyResult; -use crate::{ - request_info::{RequestInfo, A}, - CONF, -}; -use jellycommon::{ - api::NodeFilterSort, - stream::{StreamContainer, StreamSpec}, - user::{PermissionSet, PlayerKind}, - NodeID, -}; -use jellylogic::node::get_node; -use jellyui::{node_page::NodePage, render_page}; +use crate::request_info::RequestInfo; +use jellycommon::stream::{StreamContainer, StreamSpec}; use rocket::{ - get, - response::{content::RawHtml, Redirect}, - Either, + Either, get, + response::{Redirect, content::RawHtml}, }; use std::time::Duration; diff --git a/server/src/ui/search.rs b/server/src/ui/search.rs index 8a67672..fce79e3 100644 --- a/server/src/ui/search.rs +++ b/server/src/ui/search.rs @@ -6,10 +6,7 @@ use super::error::MyResult; use crate::request_info::RequestInfo; use anyhow::anyhow; -use jellycommon::api::ApiSearchResponse; -use jellylogic::search::search; -use jellyui::{render_page, search::SearchPage}; -use rocket::{get, response::content::RawHtml, serde::json::Json, Either}; +use rocket::{Either, get, response::content::RawHtml, serde::json::Json}; #[get("/search?<query>&<page>")] pub async fn r_search( diff --git a/server/src/ui/stats.rs b/server/src/ui/stats.rs index b0225e6..fc4ae64 100644 --- a/server/src/ui/stats.rs +++ b/server/src/ui/stats.rs @@ -5,10 +5,7 @@ */ use super::error::MyError; use crate::request_info::RequestInfo; -use jellycommon::api::ApiStatsResponse; -use jellylogic::stats::stats; -use jellyui::{render_page, stats::StatsPage}; -use rocket::{get, response::content::RawHtml, serde::json::Json, Either}; +use rocket::{Either, get, response::content::RawHtml, serde::json::Json}; #[get("/stats")] pub fn r_stats( diff --git a/server/src/ui/style.rs b/server/src/ui/style.rs index 5226b6a..2b7d2de 100644 --- a/server/src/ui/style.rs +++ b/server/src/ui/style.rs @@ -4,50 +4,13 @@ Copyright (C) 2026 metamuffin <metamuffin.org> Copyright (C) 2023 tpart */ +use jellyui::{css_bundle, js_bundle, js_bundle_map}; use rocket::{ get, http::{ContentType, Header}, response::Responder, }; - -macro_rules! concat_files { - ([$base: expr], $($files:literal),*) => {{ - #[cfg(any(debug_assertions, feature = "hot-css"))] - { - use std::{fs::read_to_string, path::PathBuf, str::FromStr}; - [ $($files),* ] - .into_iter() - .map(|n| { - read_to_string({ - let p = PathBuf::from_str(file!()).unwrap().parent().unwrap().join($base).join(n); - log::info!("load {p:?}"); - p - }) - .unwrap() - }) - .collect::<Vec<_>>() - .join("\n") - } - #[cfg(not(any(debug_assertions, feature = "hot-css")))] - concat!($(include_str!(concat!($base, "/", $files))),*).to_string() - }}; -} - -fn css_bundle() -> String { - concat_files!( - ["../../../web/style"], - "layout.css", - "player.css", - "nodepage.css", - "nodecard.css", - "js-player.css", - "js-transition.css", - "forms.css", - "props.css", - "themes.css", - "navbar.css" - ) -} +use std::borrow::Cow; pub struct CachedAsset<T>(pub T); impl<'r, 'o: 'r, T: Responder<'r, 'o>> Responder<'r, 'o> for CachedAsset<T> { @@ -61,7 +24,7 @@ impl<'r, 'o: 'r, T: Responder<'r, 'o>> Responder<'r, 'o> for CachedAsset<T> { } #[get("/assets/style.css")] -pub fn r_assets_style() -> CachedAsset<(ContentType, String)> { +pub fn r_assets_style() -> CachedAsset<(ContentType, Cow<'static, str>)> { CachedAsset((ContentType::CSS, css_bundle())) } @@ -74,10 +37,10 @@ pub fn r_assets_font() -> CachedAsset<(ContentType, &'static [u8])> { } #[get("/assets/bundle.js")] -pub fn r_assets_js() -> CachedAsset<(ContentType, String)> { +pub fn r_assets_js() -> CachedAsset<(ContentType, Cow<'static, str>)> { CachedAsset((ContentType::JavaScript, js_bundle())) } #[get("/assets/bundle.js.map")] -pub fn r_assets_js_map() -> CachedAsset<(ContentType, String)> { +pub fn r_assets_js_map() -> CachedAsset<(ContentType, Cow<'static, str>)> { CachedAsset((ContentType::JSON, js_bundle_map())) } diff --git a/tool/src/add.rs b/tool/src/add.rs index 212bfed..cd41bef 100644 --- a/tool/src/add.rs +++ b/tool/src/add.rs @@ -5,7 +5,6 @@ */ use crate::cli::Action; use dialoguer::{Confirm, FuzzySelect, Input, theme::ColorfulTheme}; -use jellycache::init_cache_dummy; use jellyimport::plugins::trakt::{Trakt, TraktKind}; use log::warn; use std::{ diff --git a/ui/client-style/Cargo.toml b/ui/client-style/Cargo.toml index a5db904..935c525 100644 --- a/ui/client-style/Cargo.toml +++ b/ui/client-style/Cargo.toml @@ -3,5 +3,12 @@ name = "jellyui-client-style" version = "0.1.0" edition = "2024" +[dependencies] +glob = { version = "0.3.3", optional = true } + [build-dependencies] glob = "0.3.3" + +[features] +# default = ["reload"] +reload = ["dep:glob"] diff --git a/ui/client-style/src/lib.rs b/ui/client-style/src/lib.rs index 06ddce4..f0c99cf 100644 --- a/ui/client-style/src/lib.rs +++ b/ui/client-style/src/lib.rs @@ -5,6 +5,19 @@ */ use std::borrow::Cow; +#[cfg(not(feature = "reload"))] pub fn css_bundle() -> Cow<'static, str> { include_str!(concat!(env!("OUT_DIR"), "/bundle.css")).into() } + +#[cfg(feature = "reload")] +pub fn css_bundle() -> Cow<'static, str> { + let mut out = String::new(); + for file in glob::glob("ui/client-style/src/**/*.css") + .unwrap() + .map(Result::unwrap) + { + out += &std::fs::read_to_string(file).unwrap(); + } + Cow::Owned(out) +} |