From 3b15caade07e8fbe351fed9aceb3f435bf58368e Mon Sep 17 00:00:00 2001 From: metamuffin Date: Mon, 26 May 2025 18:24:16 +0200 Subject: move all direct database access to logic crate --- server/src/api.rs | 26 +-- server/src/compat/jellyfin/mod.rs | 296 +++++++++++++++++------------------ server/src/compat/jellyfin/models.rs | 8 + server/src/compat/youtube.rs | 37 +++-- server/src/config.rs | 3 + server/src/helper/session.rs | 21 +-- server/src/logic/mod.rs | 1 - server/src/logic/stream.rs | 20 ++- server/src/logic/userdata.rs | 59 +++---- server/src/main.rs | 11 +- server/src/routes.rs | 7 +- server/src/ui/account/mod.rs | 24 +-- server/src/ui/account/settings.rs | 64 ++++---- server/src/ui/admin/mod.rs | 120 ++------------ server/src/ui/admin/user.rs | 54 +++---- server/src/ui/assets.rs | 129 +++------------ server/src/ui/home.rs | 7 +- server/src/ui/items.rs | 7 +- server/src/ui/node.rs | 8 +- server/src/ui/player.rs | 14 +- server/src/ui/search.rs | 7 +- server/src/ui/stats.rs | 7 +- 22 files changed, 336 insertions(+), 594 deletions(-) (limited to 'server/src') diff --git a/server/src/api.rs b/server/src/api.rs index 38bab08..d983548 100644 --- a/server/src/api.rs +++ b/server/src/api.rs @@ -5,15 +5,15 @@ */ use super::ui::error::MyResult; use crate::helper::{accept::AcceptJson, language::AcceptLanguage, A}; -use jellycommon::{user::CreateSessionParams, NodeID, Visibility}; +use jellycommon::{user::CreateSessionParams, NodeID}; use jellyimport::asset_token::AssetInner; use jellylogic::{ login::login_logic, + node::get_nodes_modified_since, session::{AdminSession, Session}, - Database, }; use jellyui::locale::get_translation_table; -use rocket::{get, post, response::Redirect, serde::json::Json, Either, State}; +use rocket::{get, post, response::Redirect, serde::json::Json, Either}; use serde_json::{json, Value}; use std::collections::HashMap; @@ -49,12 +49,8 @@ pub fn r_translations( } #[post("/api/create_session", data = "")] -pub fn r_api_account_login( - database: &State, - data: Json, -) -> MyResult { +pub fn r_api_account_login(data: Json) -> MyResult { let token = login_logic( - database, &data.username, &data.password, data.expire, @@ -69,17 +65,7 @@ pub fn r_api_asset_token_raw(_admin: A, token: &str) -> MyResult")] -pub fn r_nodes_modified_since( - _session: A, - database: &State, - since: u64, -) -> MyResult>> { - let mut nodes = database.get_nodes_modified_since(since)?; - nodes.retain(|id| { - database.get_node(*id).is_ok_and(|n| { - n.as_ref() - .is_some_and(|n| n.visibility >= Visibility::Reduced) - }) - }); +pub fn r_nodes_modified_since(session: A, since: u64) -> MyResult>> { + let nodes = get_nodes_modified_since(&session.0, since)?; Ok(Json(nodes)) } diff --git a/server/src/compat/jellyfin/mod.rs b/server/src/compat/jellyfin/mod.rs index e8a74d7..0a901b2 100644 --- a/server/src/compat/jellyfin/mod.rs +++ b/server/src/compat/jellyfin/mod.rs @@ -6,19 +6,22 @@ pub mod models; use crate::{helper::A, ui::error::MyResult}; -use anyhow::{anyhow, Context}; +use anyhow::anyhow; use jellycommon::{ - api::{FilterProperty, NodeFilterSort, SortOrder, SortProperty}, + api::{NodeFilterSort, SortOrder, SortProperty}, routes::{u_asset, u_node_slug_backdrop, u_node_slug_poster}, stream::{StreamContainer, StreamSpec}, user::{NodeUserData, WatchedState}, MediaInfo, Node, NodeID, NodeKind, SourceTrack, SourceTrackKind, Visibility, }; use jellylogic::{ - filter_sort::filter_and_sort_nodes, login::login_logic, node::DatabaseNodeUserDataExt, - session::Session, Database, + login::login_logic, + node::{get_node, update_node_userdata_watched_progress}, + search::search, + session::Session, }; use jellyui::{get_brand, get_slogan, node_page::aspect_class}; +use log::warn; use models::*; use rocket::{ get, @@ -26,16 +29,18 @@ use rocket::{ post, response::Redirect, serde::json::Json, - FromForm, State, + FromForm, }; use serde::Deserialize; use serde_json::{json, Value}; use std::{collections::BTreeMap, net::IpAddr}; +// these are both random values. idk what they are for const SERVER_ID: &str = "1694a95daf70708147f16103ce7b7566"; const USER_ID: &str = "33f772aae6c2495ca89fe00340dbd17c"; + const VERSION: &str = "10.10.0"; -const LOCAL_ADDRESS: &str = "http://127.0.0.1:8000"; +const LOCAL_ADDRESS: &str = "http://127.0.0.1:8000"; // TODO #[get("/System/Info/Public")] pub fn r_jellyfin_system_info_public_case() -> Json { @@ -182,24 +187,26 @@ pub fn r_jellyfin_items_images_backdrop( #[get("/Items/")] #[allow(private_interfaces)] -pub fn r_jellyfin_items_item( - session: A, - database: &State, - id: &str, -) -> MyResult> { - let (n, ud) = database.get_node_with_userdata(NodeID::from_slug(id), &session.0)?; - Ok(Json(item_object(&n, &ud))) +pub fn r_jellyfin_items_item(session: A, id: &str) -> MyResult> { + let r = get_node( + &session.0, + NodeID::from_slug(id), + false, + false, + NodeFilterSort::default(), + )?; + Ok(Json(item_object(&r.node, &r.userdata))) } + #[get("/Users//Items/")] #[allow(private_interfaces)] pub fn r_jellyfin_users_items_item( session: A, - database: &State, uid: &str, id: &str, ) -> MyResult> { let _ = uid; - r_jellyfin_items_item(session, database, id) + r_jellyfin_items_item(session, id) } #[derive(Debug, FromForm)] @@ -223,112 +230,118 @@ struct JellyfinItemQuery { #[allow(private_interfaces)] pub fn r_jellyfin_users_items( session: A, - database: &State, uid: &str, query: JellyfinItemQuery, -) -> MyResult> { +) -> MyResult> { let _ = uid; - r_jellyfin_items(session, database, query) + r_jellyfin_items(session, query) } #[get("/Artists?")] #[allow(private_interfaces)] pub fn r_jellyfin_artists( session: A, - database: &State, mut query: JellyfinItemQuery, -) -> MyResult> { +) -> MyResult> { query.internal_artists = true; - r_jellyfin_items(session, database, query)?; // TODO - Ok(Json(json!({ - "Items": [], - "TotalRecordCount": 0, - "StartIndex": 0 - }))) + r_jellyfin_items(session, query)?; // TODO + Ok(Json(JellyfinItemsResponse::default())) } #[get("/Persons?")] #[allow(private_interfaces)] pub fn r_jellyfin_persons( session: A, - database: &State, mut query: JellyfinItemQuery, -) -> MyResult> { +) -> MyResult> { query.internal_persons = true; - r_jellyfin_items(session, database, query)?; // TODO - Ok(Json(json!({ - "Items": [], - "TotalRecordCount": 0, - "StartIndex": 0 - }))) + r_jellyfin_items(session, query)?; // TODO + Ok(Json(JellyfinItemsResponse::default())) } #[get("/Items?")] #[allow(private_interfaces)] pub fn r_jellyfin_items( session: A, - database: &State, query: JellyfinItemQuery, -) -> MyResult> { - let (nodes, parent_kind) = if let Some(q) = query.search_term { - ( - database - .search(&q, query.limit, query.start_index.unwrap_or_default())? - .1, - None, - ) +) -> MyResult> { + // let (nodes, parent_kind) = if let Some(q) = query.search_term { + // ( + // database + // .search(&q, query.limit, query.start_index.unwrap_or_default())? + // .1, + // None, + // ) + // } else if let Some(parent) = query.parent_id { + // let parent = NodeID::from_slug(&parent); + // ( + // database + // .get_node_children(parent)? + // .into_iter() + // .skip(query.start_index.unwrap_or_default()) + // .take(query.limit) + // .collect(), + // database.get_node(parent)?.map(|n| n.kind), + // ) + // } else { + // (vec![], None) + // }; + + // let filter_kind = query + // .include_item_types + // .map(|n| match n.as_str() { + // "Movie" => vec![FilterProperty::KindMovie], + // "Audio" => vec![FilterProperty::KindMusic], + // "Video" => vec![FilterProperty::KindVideo], + // "TvChannel" => vec![FilterProperty::KindChannel], + // _ => vec![], + // }) + // .or(if query.internal_artists { + // Some(vec![]) + // } else { + // None + // }) + // .or(if query.internal_persons { + // Some(vec![]) + // } else { + // None + // }); + + // let mut nodes = nodes + // .into_iter() + // .map(|nid| database.get_node_with_userdata(nid, &session.0)) + // .collect::, anyhow::Error>>()?; + + // filter_and_sort_nodes( + // &NodeFilterSort { + // sort_by: None, + // filter_kind, + // sort_order: None, + // }, + // match parent_kind { + // Some(NodeKind::Channel) => (SortProperty::ReleaseDate, SortOrder::Descending), + // _ => (SortProperty::Title, SortOrder::Ascending), + // }, + // &mut nodes, + // ); + + let nodes = if let Some(q) = query.search_term { + search(&session.0, &q, query.start_index.map(|x| x / 50))?.results // TODO } else if let Some(parent) = query.parent_id { - let parent = NodeID::from_slug(&parent); - ( - database - .get_node_children(parent)? - .into_iter() - .skip(query.start_index.unwrap_or_default()) - .take(query.limit) - .collect(), - database.get_node(parent)?.map(|n| n.kind), - ) + get_node( + &session.0, + NodeID::from_slug(&parent), + true, + false, + NodeFilterSort::default(), + )? + .children } else { - (vec![], None) + warn!("unknown items request"); + vec![] }; - let filter_kind = query - .include_item_types - .map(|n| match n.as_str() { - "Movie" => vec![FilterProperty::KindMovie], - "Audio" => vec![FilterProperty::KindMusic], - "Video" => vec![FilterProperty::KindVideo], - "TvChannel" => vec![FilterProperty::KindChannel], - _ => vec![], - }) - .or(if query.internal_artists { - Some(vec![]) - } else { - None - }) - .or(if query.internal_persons { - Some(vec![]) - } else { - None - }); - - let mut nodes = nodes - .into_iter() - .map(|nid| database.get_node_with_userdata(nid, &session.0)) - .collect::, anyhow::Error>>()?; - - filter_and_sort_nodes( - &NodeFilterSort { - sort_by: None, - filter_kind, - sort_order: None, - }, - match parent_kind { - Some(NodeKind::Channel) => (SortProperty::ReleaseDate, SortOrder::Descending), - _ => (SortProperty::Title, SortOrder::Ascending), - }, - &mut nodes, - ); + // TODO reimplemnt filter behaviour let items = nodes .into_iter() @@ -336,37 +349,33 @@ pub fn r_jellyfin_items( .map(|(n, ud)| item_object(&n, &ud)) .collect::>(); - Ok(Json(json!({ - "Items": items, - "TotalRecordCount": items.len(), - "StartIndex": query.start_index.unwrap_or_default() - }))) + Ok(Json(JellyfinItemsResponse { + total_record_count: items.len(), + start_index: query.start_index.unwrap_or_default(), + items, + })) } #[get("/UserViews?")] #[allow(non_snake_case)] -pub fn r_jellyfin_users_views( - session: A, - database: &State, - userId: &str, -) -> MyResult> { +pub fn r_jellyfin_users_views(session: A, userId: &str) -> MyResult> { let _ = userId; - let mut toplevel = database - .get_node_children(NodeID::from_slug("library")) - .context("root node missing")? - .into_iter() - .map(|nid| database.get_node_with_userdata(nid, &session.0)) - .collect::, anyhow::Error>>()?; - - toplevel.sort_by_key(|(n, _)| n.index.unwrap_or(usize::MAX)); - - let mut items = Vec::new(); - for (n, ud) in toplevel { - if n.visibility >= Visibility::Reduced { - items.push(item_object(&n, &ud)) - } - } + let items = get_node( + &session.0, + NodeID::from_slug("library"), + false, + true, + NodeFilterSort { + sort_by: Some(SortProperty::Index), + sort_order: Some(SortOrder::Ascending), + filter_kind: None, + }, + )? + .children + .into_iter() + .map(|(node, udata)| item_object(&node, &udata)) + .collect::>(); Ok(Json(json!({ "Items": items, @@ -414,14 +423,15 @@ pub fn r_jellyfin_shows_nextup(_session: A) -> Json { } #[post("/Items//PlaybackInfo")] -pub fn r_jellyfin_items_playbackinfo( - _session: A, - database: &State, - id: &str, -) -> MyResult> { - let node = database - .get_node_slug(id)? - .ok_or(anyhow!("node does not exist"))?; +pub fn r_jellyfin_items_playbackinfo(session: A, id: &str) -> MyResult> { + let node = get_node( + &session.0, + NodeID::from_slug(id), + false, + false, + NodeFilterSort::default(), + )? + .node; let media = node.media.as_ref().ok_or(anyhow!("node has no media"))?; let ms = media_source_object(&node, media); Ok(Json(json!({ @@ -431,14 +441,15 @@ pub fn r_jellyfin_items_playbackinfo( } #[get("/Videos//stream.webm")] -pub fn r_jellyfin_video_stream( - _session: A, - database: &State, - id: &str, -) -> MyResult { - let node = database - .get_node_slug(id)? - .ok_or(anyhow!("node does not exist"))?; +pub fn r_jellyfin_video_stream(session: A, id: &str) -> MyResult { + let node = get_node( + &session.0, + NodeID::from_slug(id), + false, + false, + NodeFilterSort::default(), + )? + .node; let media = node.media.as_ref().ok_or(anyhow!("node has no media"))?; let params = StreamSpec::Remux { tracks: (0..media.tracks.len()).collect(), @@ -458,23 +469,10 @@ struct JellyfinProgressData { #[allow(private_interfaces)] pub fn r_jellyfin_sessions_playing_progress( session: A, - database: &State, data: Json, ) -> MyResult<()> { let position = data.position_ticks / 10_000_000.; - database.update_node_udata( - NodeID::from_slug(&data.item_id), - &session.0.user.name, - |udata| { - udata.watched = match udata.watched { - WatchedState::None | WatchedState::Pending | WatchedState::Progress(_) => { - WatchedState::Progress(position) - } - WatchedState::Watched => WatchedState::Watched, - }; - Ok(()) - }, - )?; + update_node_userdata_watched_progress(&session.0, NodeID::from_slug(&data.item_id), position)?; Ok(()) } @@ -501,22 +499,20 @@ struct AuthData { #[allow(private_interfaces)] pub fn r_jellyfin_users_authenticatebyname_case( client_addr: IpAddr, - database: &State, data: Json, jar: &CookieJar, ) -> MyResult> { - r_jellyfin_users_authenticatebyname(client_addr, database, data, jar) + r_jellyfin_users_authenticatebyname(client_addr, data, jar) } #[post("/Users/authenticatebyname", data = "")] #[allow(private_interfaces)] pub fn r_jellyfin_users_authenticatebyname( client_addr: IpAddr, - database: &State, data: Json, jar: &CookieJar, ) -> MyResult> { - let token = login_logic(database, &data.username, &data.pw, None, None)?; + let token = login_logic(&data.username, &data.pw, None, None)?; // setting the session cookie too because image requests carry no auth headers for some reason. // TODO find alternative, non-web clients might not understand cookies diff --git a/server/src/compat/jellyfin/models.rs b/server/src/compat/jellyfin/models.rs index 6a68455..9dbad9c 100644 --- a/server/src/compat/jellyfin/models.rs +++ b/server/src/compat/jellyfin/models.rs @@ -7,6 +7,14 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::BTreeMap; +#[derive(Debug, Serialize, Default)] +#[serde(rename_all = "PascalCase")] +pub(super) struct JellyfinItemsResponse { + pub items: Vec, + pub total_record_count: usize, + pub start_index: usize, +} + #[derive(Debug, Serialize, Deserialize)] pub(super) enum JellyfinItemType { AudioBook, diff --git a/server/src/compat/youtube.rs b/server/src/compat/youtube.rs index 0a69d14..7126781 100644 --- a/server/src/compat/youtube.rs +++ b/server/src/compat/youtube.rs @@ -6,48 +6,47 @@ use crate::{helper::A, ui::error::MyResult}; use anyhow::anyhow; use jellycommon::routes::{u_node_slug, u_node_slug_player}; -use jellylogic::{session::Session, Database}; -use rocket::{get, response::Redirect, State}; +use jellylogic::{ + node::{get_node_by_eid, node_id_to_slug}, + session::Session, +}; +use rocket::{get, response::Redirect}; #[get("/watch?")] -pub fn r_youtube_watch(_session: A, db: &State, v: &str) -> MyResult { +pub fn r_youtube_watch(session: A, v: &str) -> MyResult { if v.len() != 11 { Err(anyhow!("video id length incorrect"))? } - let Some(id) = db.get_node_external_id("youtube:video", v)? else { + let Some(id) = get_node_by_eid(&session.0, "youtube:video", v)? else { Err(anyhow!("element not found"))? }; - let node = db.get_node(id)?.ok_or(anyhow!("node missing"))?; - Ok(Redirect::to(u_node_slug_player(&node.slug))) + let slug = node_id_to_slug(&session.0, id)?; + Ok(Redirect::to(u_node_slug_player(&slug))) } #[get("/channel/")] -pub fn r_youtube_channel( - _session: A, - db: &State, - id: &str, -) -> MyResult { +pub fn r_youtube_channel(session: A, id: &str) -> MyResult { let Some(id) = (if id.starts_with("UC") { - db.get_node_external_id("youtube:channel", id)? + get_node_by_eid(&session.0, "youtube:channel", id)? } else if id.starts_with("@") { - db.get_node_external_id("youtube:channel-name", id)? + get_node_by_eid(&session.0, "youtube:channel-name", id)? } else { Err(anyhow!("unknown channel id format"))? }) else { Err(anyhow!("channel not found"))? }; - let node = db.get_node(id)?.ok_or(anyhow!("node missing"))?; - Ok(Redirect::to(u_node_slug(&node.slug))) + let slug = node_id_to_slug(&session.0, id)?; + Ok(Redirect::to(u_node_slug(&slug))) } #[get("/embed/")] -pub fn r_youtube_embed(_session: A, db: &State, v: &str) -> MyResult { +pub fn r_youtube_embed(session: A, v: &str) -> MyResult { if v.len() != 11 { Err(anyhow!("video id length incorrect"))? } - let Some(id) = db.get_node_external_id("youtube:video", v)? else { + let Some(id) = get_node_by_eid(&session.0, "youtube:video", v)? else { Err(anyhow!("element not found"))? }; - let node = db.get_node(id)?.ok_or(anyhow!("node missing"))?; - Ok(Redirect::to(u_node_slug_player(&node.slug))) + let slug = node_id_to_slug(&session.0, id)?; + Ok(Redirect::to(u_node_slug_player(&slug))) } diff --git a/server/src/config.rs b/server/src/config.rs index 202948a..28fcf90 100644 --- a/server/src/config.rs +++ b/server/src/config.rs @@ -5,6 +5,7 @@ */ use anyhow::{anyhow, Context, Result}; +use jellylogic::init_database; use serde::Deserialize; use std::env::{args, var}; use tokio::fs::read_to_string; @@ -41,5 +42,7 @@ pub async fn load_config() -> Result<()> { *crate::CONF_PRELOAD.lock().unwrap() = Some(config.server); *jellyui::CONF_PRELOAD.lock().unwrap() = Some(config.ui); + init_database()?; + Ok(()) } diff --git a/server/src/helper/session.rs b/server/src/helper/session.rs index d51acd3..090330b 100644 --- a/server/src/helper/session.rs +++ b/server/src/helper/session.rs @@ -6,24 +6,19 @@ use super::A; use crate::ui::error::MyError; use anyhow::anyhow; -use jellylogic::{ - session::{validate, AdminSession, Session}, - Database, -}; +use jellylogic::session::{bypass_auth_session, token_to_session, AdminSession, Session}; use log::warn; use rocket::{ async_trait, http::Status, outcome::Outcome, request::{self, FromRequest}, - Request, State, + Request, }; pub(super) async fn session_from_request(req: &Request<'_>) -> Result { - let username; - if cfg!(feature = "bypass-auth") { - username = "admin".to_string(); + Ok(bypass_auth_session()?) } else { let token = req .query_value("session") @@ -40,14 +35,8 @@ pub(super) async fn session_from_request(req: &Request<'_>) -> Result Option<&str> { diff --git a/server/src/logic/mod.rs b/server/src/logic/mod.rs index 26f45de..a7991f7 100644 --- a/server/src/logic/mod.rs +++ b/server/src/logic/mod.rs @@ -6,4 +6,3 @@ pub mod playersync; pub mod stream; pub mod userdata; - diff --git a/server/src/logic/stream.rs b/server/src/logic/stream.rs index c21edaa..1e518e2 100644 --- a/server/src/logic/stream.rs +++ b/server/src/logic/stream.rs @@ -5,9 +5,9 @@ */ use crate::{helper::A, ui::error::MyError}; use anyhow::{anyhow, Result}; -use jellycommon::{stream::StreamSpec, TrackSource}; +use jellycommon::{api::NodeFilterSort, stream::StreamSpec, NodeID, TrackSource}; use jellyimport::asset_token::AssetInner; -use jellylogic::{session::Session, Database}; +use jellylogic::{node::get_node, session::Session}; use jellystream::SMediaInfo; use log::{info, warn}; use rocket::{ @@ -15,7 +15,7 @@ use rocket::{ http::{Header, Status}, request::{self, FromRequest}, response::{self, Redirect, Responder}, - Either, Request, Response, State, + Either, Request, Response, }; use std::{ collections::{BTreeMap, BTreeSet}, @@ -42,17 +42,21 @@ pub async fn r_stream_head( #[get("/n//stream?")] pub async fn r_stream( - _session: A, - db: &State, + session: A, id: &str, range: Option, spec: BTreeMap, ) -> Result, MyError> { let spec = StreamSpec::from_query_kv(&spec).map_err(|x| anyhow!("spec invalid: {x}"))?; // TODO perm - let node = db - .get_node_slug(id)? - .ok_or(anyhow!("node does not exist"))?; + let node = get_node( + &session.0, + NodeID::from_slug(id), + false, + false, + NodeFilterSort::default(), + )? + .node; let media = Arc::new( node.media diff --git a/server/src/logic/userdata.rs b/server/src/logic/userdata.rs index ac3cb83..52c3688 100644 --- a/server/src/logic/userdata.rs +++ b/server/src/logic/userdata.rs @@ -5,13 +5,20 @@ */ use crate::{helper::A, ui::error::MyResult}; use jellycommon::{ + api::NodeFilterSort, routes::u_node_id, user::{NodeUserData, WatchedState}, NodeID, }; -use jellylogic::{session::Session, Database}; +use jellylogic::{ + node::{ + get_node, update_node_userdata_rating, update_node_userdata_watched, + update_node_userdata_watched_progress, + }, + session::Session, +}; use rocket::{ - form::Form, get, post, response::Redirect, serde::json::Json, FromForm, FromFormField, State, + form::Form, get, post, response::Redirect, serde::json::Json, FromForm, FromFormField, UriDisplayQuery, }; @@ -23,33 +30,26 @@ pub enum UrlWatchedState { } #[get("/n//userdata")] -pub fn r_node_userdata( - session: A, - db: &State, - id: A, -) -> MyResult> { - let u = db - .get_node_udata(id.0, &session.0.user.name)? - .unwrap_or_default(); +pub fn r_node_userdata(session: A, id: A) -> MyResult> { + let u = get_node(&session.0, id.0, false, false, NodeFilterSort::default())?.userdata; Ok(Json(u)) } #[post("/n//watched?")] pub async fn r_node_userdata_watched( session: A, - db: &State, id: A, state: UrlWatchedState, ) -> MyResult { - // TODO perm - db.update_node_udata(id.0, &session.0.user.name, |udata| { - udata.watched = match state { + update_node_userdata_watched( + &session.0, + id.0, + match state { UrlWatchedState::None => WatchedState::None, UrlWatchedState::Watched => WatchedState::Watched, UrlWatchedState::Pending => WatchedState::Pending, - }; - Ok(()) - })?; + }, + )?; Ok(Redirect::found(u_node_id(id.0))) } @@ -62,34 +62,15 @@ pub struct UpdateRating { #[post("/n//update_rating", data = "
")] pub async fn r_node_userdata_rating( session: A, - db: &State, id: A, form: Form, ) -> MyResult { - // TODO perm - db.update_node_udata(id.0, &session.0.user.name, |udata| { - udata.rating = form.rating; - Ok(()) - })?; + update_node_userdata_rating(&session.0, id.0, form.rating)?; Ok(Redirect::found(u_node_id(id.0))) } #[post("/n//progress?")] -pub async fn r_node_userdata_progress( - session: A, - db: &State, - id: A, - t: f64, -) -> MyResult<()> { - // TODO perm - db.update_node_udata(id.0, &session.0.user.name, |udata| { - udata.watched = match udata.watched { - WatchedState::None | WatchedState::Pending | WatchedState::Progress(_) => { - WatchedState::Progress(t) - } - WatchedState::Watched => WatchedState::Watched, - }; - Ok(()) - })?; +pub async fn r_node_userdata_progress(session: A, id: A, t: f64) -> MyResult<()> { + update_node_userdata_watched_progress(&session.0, id.0, t)?; Ok(()) } diff --git a/server/src/main.rs b/server/src/main.rs index 5113542..7c7bbd2 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -7,9 +7,7 @@ #![allow(clippy::needless_borrows_for_generic_args)] #![recursion_limit = "4096"] -use anyhow::Context; use config::load_config; -use jellylogic::Database; use jellylogic::{admin::log::enable_logging, login::create_admin_account}; use log::{error, info, warn}; use routes::build_rocket; @@ -28,7 +26,6 @@ pub mod ui; #[rustfmt::skip] #[derive(Debug, Deserialize, Serialize, Default)] pub struct Config { - database_path: PathBuf, asset_path: PathBuf, cookie_key: Option, tls:bool, @@ -56,15 +53,11 @@ async fn main() { #[cfg(feature = "bypass-auth")] log::warn!("authentification bypass enabled"); - let database = Database::open(&CONF.database_path) - .context("opening database") - .unwrap(); - - if let Err(e) = create_admin_account(&database) { + if let Err(e) = create_admin_account() { error!("failed to create admin account: {e:?}"); } - let r = build_rocket(database).launch().await; + let r = build_rocket().launch().await; match r { Ok(_) => warn!("server shutdown"), Err(e) => error!("server exited: {e}"), diff --git a/server/src/routes.rs b/server/src/routes.rs index e14eb44..3f3518b 100644 --- a/server/src/routes.rs +++ b/server/src/routes.rs @@ -13,7 +13,7 @@ use crate::ui::{ admin::{ log::{r_admin_log, r_admin_log_stream}, r_admin_dashboard, r_admin_import, r_admin_invite, r_admin_remove_invite, - r_admin_transcode_posters, r_admin_update_search, + r_admin_update_search, user::{r_admin_remove_user, r_admin_user, r_admin_user_permission, r_admin_users}, }, assets::{r_asset, r_item_backdrop, r_item_poster, r_node_thumbnail, r_person_asset}, @@ -61,7 +61,6 @@ use crate::{ }, }; use base64::Engine; -use jellylogic::Database; use log::warn; use rand::random; use rocket::{ @@ -76,7 +75,7 @@ macro_rules! uri { }; } -pub fn build_rocket(database: Database) -> Rocket { +pub fn build_rocket() -> Rocket { rocket::build() .configure(Config { address: std::env::var("BIND_ADDR") @@ -97,7 +96,6 @@ pub fn build_rocket(database: Database) -> Rocket { ip_header: Some("x-real-ip".into()), ..Default::default() }) - .manage(database) .manage(PlayersyncChannels::default()) .attach(AdHoc::on_response("set server header", |_req, res| { res.set_header(Header::new("server", "jellything")); @@ -133,7 +131,6 @@ pub fn build_rocket(database: Database) -> Rocket { r_admin_log, r_admin_remove_invite, r_admin_remove_user, - r_admin_transcode_posters, r_admin_update_search, r_admin_user_permission, r_admin_user, diff --git a/server/src/ui/account/mod.rs b/server/src/ui/account/mod.rs index 51da348..2a513a9 100644 --- a/server/src/ui/account/mod.rs +++ b/server/src/ui/account/mod.rs @@ -11,13 +11,8 @@ use crate::{ ui::{error::MyResult, home::rocket_uri_macro_r_home}, }; use anyhow::anyhow; -use jellycommon::user::User; use jellyimport::is_importing; -use jellylogic::{ - login::{hash_password, login_logic}, - session::Session, - Database, -}; +use jellylogic::{account::register_user, login::login_logic, session::Session}; use jellyui::{ account::{AccountLogin, AccountLogout, AccountRegister, AccountRegisterSuccess}, render_page, @@ -29,7 +24,7 @@ use rocket::{ http::{Cookie, CookieJar}, post, response::{content::RawHtml, Redirect}, - FromForm, State, + FromForm, }; use serde::{Deserialize, Serialize}; @@ -98,7 +93,6 @@ pub fn r_account_logout(session: Option>, lang: AcceptLanguage) -> Ra #[post("/account/register", data = "")] pub fn r_account_register_post<'a>( - database: &'a State, session: Option>, form: Form>, lang: AcceptLanguage, @@ -110,16 +104,7 @@ pub fn r_account_register_post<'a>( None => return Err(MyError(anyhow!(format_form_error(form)))), }; - database.register_user( - &form.invitation, - &form.username, - User { - display_name: form.username.clone(), - name: form.username.clone(), - password: hash_password(&form.username, &form.password), - ..Default::default() - }, - )?; + register_user(&form.invitation, &form.username, &form.password)?; Ok(RawHtml(render_page( &AccountRegisterSuccess { @@ -136,7 +121,6 @@ pub fn r_account_register_post<'a>( #[post("/account/login", data = "")] pub fn r_account_login_post( - database: &State, jar: &CookieJar, form: Form>, ) -> MyResult { @@ -147,7 +131,7 @@ pub fn r_account_login_post( jar.add( Cookie::build(( "session", - login_logic(database, &form.username, &form.password, None, None)?, + login_logic(&form.username, &form.password, None, None)?, )) .permanent() .build(), diff --git a/server/src/ui/account/settings.rs b/server/src/ui/account/settings.rs index f1a367d..7d1b7af 100644 --- a/server/src/ui/account/settings.rs +++ b/server/src/ui/account/settings.rs @@ -3,14 +3,20 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2025 metamuffin */ -use super::{format_form_error, hash_password}; +use super::format_form_error; use crate::{ helper::{language::AcceptLanguage, A}, ui::error::MyResult, }; use jellycommon::user::{PlayerKind, Theme}; use jellyimport::is_importing; -use jellylogic::{session::Session, Database}; +use jellylogic::{ + account::{ + update_user_display_name, update_user_native_secret, update_user_password, + update_user_player_preference, update_user_theme, + }, + session::Session, +}; use jellyui::{ account::settings::SettingsPage, locale::{tr, Language}, @@ -21,7 +27,7 @@ use rocket::{ form::{self, validate::len, Contextual, Form}, get, post, response::content::RawHtml, - FromForm, State, + FromForm, }; use std::ops::Range; @@ -70,7 +76,6 @@ pub fn r_account_settings(session: A, lang: AcceptLanguage) -> RawHtml< #[post("/account/settings", data = "")] pub fn r_account_settings_post( session: A, - database: &State, form: Form>, lang: AcceptLanguage, ) -> MyResult> { @@ -90,33 +95,30 @@ pub fn r_account_settings_post( let mut out = String::new(); - database.update_user(&session.user.name, |user| { - if let Some(password) = &form.password { - user.password = hash_password(&session.user.name, password); - out += &*tr(lang, "settings.account.password.changed"); - out += "\n"; - } - if let Some(display_name) = &form.display_name { - user.display_name = display_name.clone(); - out += &*tr(lang, "settings.account.display_name.changed"); - out += "\n"; - } - if let Some(theme) = form.theme { - user.theme = theme.0; - out += &*tr(lang, "settings.account.theme.changed"); - out += "\n"; - } - if let Some(player_preference) = form.player_preference { - user.player_preference = player_preference.0; - out += &*tr(lang, "settings.player_preference.changed"); - out += "\n"; - } - if let Some(native_secret) = &form.native_secret { - user.native_secret = native_secret.to_owned(); - out += "Native secret updated.\n"; - } - Ok(()) - })?; + if let Some(password) = &form.password { + update_user_password(&session, password)?; + out += &*tr(lang, "settings.account.password.changed"); + out += "\n"; + } + if let Some(display_name) = &form.display_name { + update_user_display_name(&session, display_name)?; + out += &*tr(lang, "settings.account.display_name.changed"); + out += "\n"; + } + if let Some(theme) = form.theme { + update_user_theme(&session, theme.0)?; + out += &*tr(lang, "settings.account.theme.changed"); + out += "\n"; + } + if let Some(player_preference) = form.player_preference { + update_user_player_preference(&session, player_preference.0)?; + out += &*tr(lang, "settings.player_preference.changed"); + out += "\n"; + } + if let Some(native_secret) = &form.native_secret { + update_user_native_secret(&session, native_secret)?; + out += "Native secret updated.\n"; + } Ok(settings_page( session, // using the old session here, results in outdated theme being displayed diff --git a/server/src/ui/admin/mod.rs b/server/src/ui/admin/mod.rs index 942f4f8..e3eb2d6 100644 --- a/server/src/ui/admin/mod.rs +++ b/server/src/ui/admin/mod.rs @@ -6,50 +6,42 @@ pub mod log; pub mod user; -use super::{ - assets::{resolve_asset, AVIF_QUALITY, AVIF_SPEED}, - error::MyResult, -}; +use super::error::MyResult; use crate::helper::{language::AcceptLanguage, A}; -use anyhow::{anyhow, Context}; use jellycommon::routes::u_admin_dashboard; -use jellyimport::{asset_token::AssetInner, import_wrap, is_importing}; +use jellyimport::is_importing; use jellylogic::{ - admin::{get_import_errors, list_invites}, + admin::{ + create_invite, delete_invite, do_import, get_import_errors, list_invites, + update_search_index, + }, session::AdminSession, - Database, }; use jellyui::{ admin::AdminDashboardPage, render_page, scaffold::{RenderInfo, SessionInfo}, }; -use rand::Rng; use rocket::{ form::Form, get, post, response::{content::RawHtml, Redirect}, - FromForm, State, + FromForm, }; -use std::time::Instant; -use tokio::{sync::Semaphore, task::spawn_blocking}; #[get("/admin/dashboard")] pub async fn r_admin_dashboard( session: A, - database: &State, lang: AcceptLanguage, ) -> MyResult> { let AcceptLanguage(lang) = lang; let flash = None; - let invites = list_invites(&session.0, database)?; + let invites = list_invites(&session.0)?; let last_import_err = get_import_errors(&session.0).await; let busy = if is_importing() { Some("An import is currently running.") - } else if is_transcoding() { - Some("Currently transcoding posters.") } else { None }; @@ -73,13 +65,8 @@ pub async fn r_admin_dashboard( } #[post("/admin/generate_invite")] -pub async fn r_admin_invite( - _session: A, - database: &State, -) -> MyResult { - let i = format!("{}", rand::rng().random::()); - database.create_invite(&i)?; - // admin_dashboard(database, Some(Ok(format!("Invite: {}", i)))).await +pub async fn r_admin_invite(session: A) -> MyResult { + let _ = create_invite(&session.0)?; Ok(Redirect::temporary(u_admin_dashboard())) } @@ -91,97 +78,20 @@ pub struct DeleteInvite { #[post("/admin/remove_invite", data = "")] pub async fn r_admin_remove_invite( session: A, - database: &State, form: Form, ) -> MyResult { - drop(session); - if !database.delete_invite(&form.invite)? { - Err(anyhow!("invite does not exist"))?; - }; - // admin_dashboard(database, Some(Ok("Invite invalidated".into()))).await + delete_invite(&session.0, &form.invite)?; Ok(Redirect::temporary(u_admin_dashboard())) } #[post("/admin/import?")] -pub async fn r_admin_import( - session: A, - database: &State, - incremental: bool, -) -> MyResult { - drop(session); - let t = Instant::now(); - if !incremental { - database.clear_nodes()?; - } - let r = import_wrap((*database).clone(), incremental).await; - // let flash = r - // .map_err(|e| e.into()) - // .map(|_| format!("Import successful; took {:?}", t.elapsed())); - // admin_dashboard(database, Some(flash)).await +pub async fn r_admin_import(session: A, incremental: bool) -> MyResult { + do_import(&session.0, incremental).await?.1?; Ok(Redirect::temporary(u_admin_dashboard())) } #[post("/admin/update_search")] -pub async fn r_admin_update_search( - _session: A, - database: &State, -) -> MyResult { - let db2 = (*database).clone(); - let r = spawn_blocking(move || db2.search_create_index()) - .await - .unwrap(); - // admin_dashboard( - // database, - // Some( - // r.map_err(|e| e.into()) - // .map(|_| "Search index updated".to_string()), - // ), - // ) - // .await - Ok(Redirect::temporary(u_admin_dashboard())) -} - -static SEM_TRANSCODING: Semaphore = Semaphore::const_new(1); -fn is_transcoding() -> bool { - SEM_TRANSCODING.available_permits() == 0 -} - -#[post("/admin/transcode_posters")] -pub async fn r_admin_transcode_posters( - session: A, - database: &State, -) -> MyResult { - drop(session); - let _permit = SEM_TRANSCODING - .try_acquire() - .context("transcoding in progress")?; - - let t = Instant::now(); - - { - let nodes = database.list_nodes_with_udata("")?; - for (node, _) in nodes { - if let Some(poster) = &node.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, - // Some(Ok(format!( - // "All posters pre-transcoded; took {:?}", - // t.elapsed() - // ))), - // ) - // .await +pub async fn r_admin_update_search(session: A) -> MyResult { + update_search_index(&session.0).await?; Ok(Redirect::temporary(u_admin_dashboard())) } diff --git a/server/src/ui/admin/user.rs b/server/src/ui/admin/user.rs index 939ee83..27d5256 100644 --- a/server/src/ui/admin/user.rs +++ b/server/src/ui/admin/user.rs @@ -7,25 +7,24 @@ use crate::{ helper::{language::AcceptLanguage, A}, ui::error::MyResult, }; -use anyhow::{anyhow, Context}; +use anyhow::Context; use jellycommon::user::UserPermission; use jellyimport::is_importing; -use jellylogic::{admin::user::admin_users, session::AdminSession, Database}; +use jellylogic::{ + admin::user::{admin_users, delete_user, get_user, update_user_perms, GrantState}, + session::AdminSession, +}; use jellyui::{ admin::user::{AdminUserPage, AdminUsersPage}, render_page, scaffold::{RenderInfo, SessionInfo}, }; -use rocket::{form::Form, get, post, response::content::RawHtml, FromForm, FromFormField, State}; +use rocket::{form::Form, get, post, response::content::RawHtml, FromForm, FromFormField}; #[get("/admin/users")] -pub fn r_admin_users( - session: A, - database: &State, - lang: AcceptLanguage, -) -> MyResult> { +pub fn r_admin_users(session: A, lang: AcceptLanguage) -> MyResult> { let AcceptLanguage(lang) = lang; - let r = admin_users(database, &session.0)?; + let r = admin_users(&session.0)?; Ok(RawHtml(render_page( &AdminUsersPage { flash: None, @@ -45,14 +44,11 @@ pub fn r_admin_users( #[get("/admin/user/")] pub fn r_admin_user<'a>( session: A, - database: &State, name: &'a str, lang: AcceptLanguage, ) -> MyResult> { let AcceptLanguage(lang) = lang; - let user = database - .get_user(&name)? - .ok_or(anyhow!("user does not exist"))?; + let user = get_user(&session.0, name)?; Ok(RawHtml(render_page( &AdminUserPage { @@ -73,11 +69,11 @@ pub fn r_admin_user<'a>( #[derive(FromForm)] pub struct UserPermissionForm { permission: String, - action: GrantState, + action: UrlGrantState, } #[derive(FromFormField)] -pub enum GrantState { +pub enum UrlGrantState { Grant, Revoke, Unset, @@ -86,7 +82,6 @@ pub enum GrantState { #[post("/admin/user//update_permission", data = "")] pub fn r_admin_user_permission( session: A, - database: &State, form: Form, name: &str, lang: AcceptLanguage, @@ -95,18 +90,18 @@ pub fn r_admin_user_permission( let perm = serde_json::from_str::(&form.permission) .context("parsing provided permission")?; - database.update_user(name, |user| { + update_user_perms( + &session.0, + name, + perm, 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(()) - })?; + UrlGrantState::Grant => GrantState::Grant, + UrlGrantState::Revoke => GrantState::Revoke, + UrlGrantState::Unset => GrantState::Unset, + }, + )?; - let user = database - .get_user(&name)? - .ok_or(anyhow!("user does not exist"))?; + let user = get_user(&session.0, name)?; Ok(RawHtml(render_page( &AdminUserPage { @@ -127,15 +122,12 @@ pub fn r_admin_user_permission( #[post("/admin//remove")] pub fn r_admin_remove_user( session: A, - database: &State, name: &str, lang: AcceptLanguage, ) -> MyResult> { let AcceptLanguage(lang) = lang; - if !database.delete_user(&name)? { - Err(anyhow!("user did not exist"))?; - } - let r = admin_users(database, &session.0)?; + delete_user(&session.0, name)?; + let r = admin_users(&session.0)?; Ok(RawHtml(render_page( &AdminUsersPage { diff --git a/server/src/ui/assets.rs b/server/src/ui/assets.rs index 4e09417..97fd9c7 100644 --- a/server/src/ui/assets.rs +++ b/server/src/ui/assets.rs @@ -4,13 +4,19 @@ Copyright (C) 2025 metamuffin */ use super::error::MyResult; -use crate::{helper::{cache::CacheControlFile, A}, CONF}; +use crate::{ + helper::{cache::CacheControlFile, A}, + CONF, +}; use anyhow::{anyhow, bail, Context}; -use jellycommon::{LocalTrack, NodeID, PeopleGroup, SourceTrackKind, TrackSource}; +use jellycommon::{NodeID, PeopleGroup}; use jellyimport::asset_token::AssetInner; -use jellylogic::{session::Session, Database}; +use jellylogic::{ + assets::{get_node_backdrop, get_node_person_asset, get_node_poster, get_node_thumbnail}, + session::Session, +}; use log::info; -use rocket::{get, http::ContentType, response::Redirect, State}; +use rocket::{get, http::ContentType, response::Redirect}; use std::path::PathBuf; pub const AVIF_QUALITY: f32 = 50.; @@ -25,7 +31,6 @@ pub async fn r_asset( let width = width.unwrap_or(2048); let asset = AssetInner::deser(token)?; - let path = // if let AssetInner::Federated { host, asset } = asset { // let session = fed.get_session(&host).await?; @@ -35,7 +40,7 @@ pub async fn r_asset( // }) // .await? // } else - { + let path = { let source = resolve_asset(asset).await.context("resolving asset")?; // fit the resolution into a finite set so the maximum cache is finite too. @@ -62,136 +67,44 @@ pub async fn resolve_asset(asset: AssetInner) -> anyhow::Result { #[get("/n//poster?")] pub async fn r_item_poster( - _session: A, - db: &State, + session: A, id: A, width: Option, ) -> MyResult { - // TODO perm - let node = db.get_node(id.0)?.ok_or(anyhow!("node does not exist"))?; - - let mut asset = node.poster.clone(); - if asset.is_none() { - if let Some(parent) = node.parents.last().copied() { - let parent = db.get_node(parent)?.ok_or(anyhow!("node does not exist"))?; - asset = parent.poster.clone(); - } - }; - let asset = asset.unwrap_or_else(|| { - AssetInner::Assets(format!("fallback-{:?}.avif", node.kind).into()).ser() - }); + let asset = get_node_poster(&session.0, id.0)?; Ok(Redirect::permanent(rocket::uri!(r_asset(asset.0, width)))) } #[get("/n//backdrop?")] pub async fn r_item_backdrop( - _session: A, - db: &State, + session: A, id: A, width: Option, ) -> MyResult { - // TODO perm - let node = db.get_node(id.0)?.ok_or(anyhow!("node does not exist"))?; - - let mut asset = node.backdrop.clone(); - if asset.is_none() { - if let Some(parent) = node.parents.last().copied() { - let parent = db.get_node(parent)?.ok_or(anyhow!("node does not exist"))?; - asset = parent.backdrop.clone(); - } - }; - let asset = asset.unwrap_or_else(|| { - AssetInner::Assets(format!("fallback-{:?}.avif", node.kind).into()).ser() - }); + let asset = get_node_backdrop(&session.0, id.0)?; Ok(Redirect::permanent(rocket::uri!(r_asset(asset.0, width)))) } #[get("/n//person//asset?&")] pub async fn r_person_asset( - _session: A, - db: &State, + session: A, id: A, index: usize, group: String, width: Option, ) -> MyResult { - // TODO perm - - let node = db.get_node(id.0)?.ok_or(anyhow!("node does not exist"))?; - let app = node - .people - .get(&PeopleGroup::from_str_opt(&group).ok_or(anyhow!("unknown people group"))?) - .ok_or(anyhow!("group has no members"))? - .get(index) - .ok_or(anyhow!("person does not exist"))?; - - let asset = app - .person - .headshot - .to_owned() - .unwrap_or(AssetInner::Assets("fallback-Person.avif".into()).ser()); + let group = PeopleGroup::from_str_opt(&group).ok_or(anyhow!("unknown people group"))?; + let asset = get_node_person_asset(&session.0, id.0, group, index)?; Ok(Redirect::permanent(rocket::uri!(r_asset(asset.0, width)))) } #[get("/n//thumbnail?&")] pub async fn r_node_thumbnail( - _session: A, - db: &State, + session: A, id: A, t: f64, width: Option, ) -> MyResult { - let node = db.get_node(id.0)?.ok_or(anyhow!("node does not exist"))?; - - let media = node.media.as_ref().ok_or(anyhow!("no media"))?; - let (thumb_track_index, _thumb_track) = media - .tracks - .iter() - .enumerate() - .find(|(_i, t)| matches!(t.kind, SourceTrackKind::Video { .. })) - .ok_or(anyhow!("no video track to create a thumbnail of"))?; - let source = media - .tracks - .get(thumb_track_index) - .ok_or(anyhow!("no source"))?; - let thumb_track_source = source.source.clone(); - - if t < 0. || t > media.duration { - Err(anyhow!("thumbnail instant not within media duration"))? - } - - let step = 8.; - let t = (t / step).floor() * step; - - let asset = match thumb_track_source { - TrackSource::Local(a) => { - let AssetInner::LocalTrack(LocalTrack { path, .. }) = AssetInner::deser(&a.0)? else { - return Err(anyhow!("track set to wrong asset type").into()); - }; - // the track selected might be different from thumb_track - jellytranscoder::thumbnail::create_thumbnail(&path, t).await? - } - TrackSource::Remote(_) => { - // // TODO in the new system this is preferrably a property of node ext for regular fed - // let session = fed - // .get_session( - // thumb_track - // .federated - // .last() - // .ok_or(anyhow!("federation broken"))?, - // ) - // .await?; - - // async_cache_file("fed-thumb", (id.0, t as i64), |out| { - // session.node_thumbnail(out, id.0.into(), 2048, t) - // }) - // .await? - todo!() - } - }; - - Ok(Redirect::temporary(rocket::uri!(r_asset( - AssetInner::Cache(asset).ser().0, - width - )))) + let asset = get_node_thumbnail(&session.0, id.0, t).await?; + Ok(Redirect::temporary(rocket::uri!(r_asset(asset.0, width)))) } diff --git a/server/src/ui/home.rs b/server/src/ui/home.rs index 555b654..4a423cf 100644 --- a/server/src/ui/home.rs +++ b/server/src/ui/home.rs @@ -8,24 +8,23 @@ use super::error::MyResult; use crate::helper::{accept::AcceptJson, language::AcceptLanguage, A}; use jellycommon::api::ApiHomeResponse; use jellyimport::is_importing; -use jellylogic::{session::Session, Database}; +use jellylogic::session::Session; use jellyui::{ home::HomePage, render_page, scaffold::{RenderInfo, SessionInfo}, }; -use rocket::{get, response::content::RawHtml, serde::json::Json, Either, State}; +use rocket::{get, response::content::RawHtml, serde::json::Json, Either}; #[get("/home")] pub fn r_home( session: A, - db: &State, aj: AcceptJson, lang: AcceptLanguage, ) -> MyResult, Json>> { let AcceptLanguage(lang) = lang; - let r = jellylogic::home::home(&db, &session.0)?; + let r = jellylogic::home::home(&session.0)?; Ok(if *aj { Either::Right(Json(r)) diff --git a/server/src/ui/items.rs b/server/src/ui/items.rs index ed16c61..1ac2c09 100644 --- a/server/src/ui/items.rs +++ b/server/src/ui/items.rs @@ -7,18 +7,17 @@ use super::error::MyError; use crate::helper::{accept::AcceptJson, language::AcceptLanguage, A}; use jellycommon::api::{ApiItemsResponse, NodeFilterSort}; use jellyimport::is_importing; -use jellylogic::{items::all_items, session::Session, Database}; +use jellylogic::{items::all_items, session::Session}; use jellyui::{ items::ItemsPage, render_page, scaffold::{RenderInfo, SessionInfo}, }; -use rocket::{get, response::content::RawHtml, serde::json::Json, Either, State}; +use rocket::{get, response::content::RawHtml, serde::json::Json, Either}; #[get("/items?&")] pub fn r_items( session: A, - db: &State, aj: AcceptJson, page: Option, filter: A, @@ -26,7 +25,7 @@ pub fn r_items( ) -> Result, Json>, MyError> { let AcceptLanguage(lang) = lang; - let r = all_items(db, &session.0, page, filter.0.clone())?; + let r = all_items(&session.0, page, filter.0.clone())?; Ok(if *aj { Either::Right(Json(r)) diff --git a/server/src/ui/node.rs b/server/src/ui/node.rs index 00445a9..0b1a92f 100644 --- a/server/src/ui/node.rs +++ b/server/src/ui/node.rs @@ -10,19 +10,18 @@ use jellycommon::{ NodeID, }; use jellyimport::is_importing; -use jellylogic::{node::get_node, session::Session, Database}; +use jellylogic::{node::get_node, session::Session}; use jellyui::{ node_page::NodePage, render_page, scaffold::{RenderInfo, SessionInfo}, }; -use rocket::{get, response::content::RawHtml, serde::json::Json, Either, State}; +use rocket::{get, response::content::RawHtml, serde::json::Json, Either}; #[get("/n/?&&")] pub async fn r_node<'a>( session: A, id: A, - db: &'a State, aj: AcceptJson, filter: Option>, lang: AcceptLanguage, @@ -33,9 +32,8 @@ pub async fn r_node<'a>( let filter = filter.unwrap_or_default(); let r = get_node( - &db, - id.0, &session.0, + id.0, !*aj || children, !*aj || parents, filter.0.clone(), diff --git a/server/src/ui/player.rs b/server/src/ui/player.rs index 1fd9e07..ae4468d 100644 --- a/server/src/ui/player.rs +++ b/server/src/ui/player.rs @@ -15,7 +15,7 @@ use jellycommon::{ NodeID, }; use jellyimport::is_importing; -use jellylogic::{node::get_node, session::Session, Database}; +use jellylogic::{node::get_node, session::Session}; use jellyui::{ node_page::NodePage, render_page, @@ -24,7 +24,7 @@ use jellyui::{ use rocket::{ get, response::{content::RawHtml, Redirect}, - Either, State, + Either, }; use std::time::Duration; @@ -46,20 +46,12 @@ fn jellynative_url(action: &str, seek: f64, secret: &str, node: &str, session: & pub fn r_player( session: A, lang: AcceptLanguage, - db: &State, t: Option, id: A, ) -> MyResult, Redirect>> { let AcceptLanguage(lang) = lang; - let r = get_node( - &db, - id.0, - &session.0, - false, - true, - NodeFilterSort::default(), - )?; + let r = get_node(&session.0, id.0, false, true, NodeFilterSort::default())?; let native_session = |action: &str| { Ok(Either::Right(Redirect::temporary(jellynative_url( diff --git a/server/src/ui/search.rs b/server/src/ui/search.rs index 750c8bd..e4afdd8 100644 --- a/server/src/ui/search.rs +++ b/server/src/ui/search.rs @@ -8,18 +8,17 @@ use crate::helper::{accept::AcceptJson, language::AcceptLanguage, A}; use anyhow::anyhow; use jellycommon::api::ApiSearchResponse; use jellyimport::is_importing; -use jellylogic::{search::search, session::Session, Database}; +use jellylogic::{search::search, session::Session}; use jellyui::{ render_page, scaffold::{RenderInfo, SessionInfo}, search::SearchPage, }; -use rocket::{get, response::content::RawHtml, serde::json::Json, Either, State}; +use rocket::{get, response::content::RawHtml, serde::json::Json, Either}; #[get("/search?&")] pub async fn r_search<'a>( session: A, - db: &State, aj: AcceptJson, query: Option<&str>, page: Option, @@ -28,7 +27,7 @@ pub async fn r_search<'a>( let AcceptLanguage(lang) = lang; let r = query - .map(|query| search(db, &session.0, query, page)) + .map(|query| search(&session.0, query, page)) .transpose()?; Ok(if *aj { diff --git a/server/src/ui/stats.rs b/server/src/ui/stats.rs index b6e9321..4ae592e 100644 --- a/server/src/ui/stats.rs +++ b/server/src/ui/stats.rs @@ -7,23 +7,22 @@ use super::error::MyError; use crate::helper::{accept::AcceptJson, language::AcceptLanguage, A}; use jellycommon::api::ApiStatsResponse; use jellyimport::is_importing; -use jellylogic::{session::Session, stats::stats, Database}; +use jellylogic::{session::Session, stats::stats}; use jellyui::{ render_page, scaffold::{RenderInfo, SessionInfo}, stats::StatsPage, }; -use rocket::{get, response::content::RawHtml, serde::json::Json, Either, State}; +use rocket::{get, response::content::RawHtml, serde::json::Json, Either}; #[get("/stats")] pub fn r_stats( session: A, - db: &State, aj: AcceptJson, lang: AcceptLanguage, ) -> Result, Json>, MyError> { let AcceptLanguage(lang) = lang; - let r = stats(db, &session.0)?; + let r = stats(&session.0)?; Ok(if *aj { Either::Right(Json(r)) -- cgit v1.2.3-70-g09d2