diff options
author | metamuffin <metamuffin@disroot.org> | 2023-02-19 15:55:34 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2023-02-19 15:55:34 +0100 |
commit | 5a1ff49fe38451451a55266e86a9e9aedecfb44d (patch) | |
tree | fe9ff6f9e30e776c5e8dc5d6d69554cdc2375b1c /server/src | |
parent | 15d0a83247c3b6091f006df967f54f8399030cf6 (diff) | |
download | jellything-5a1ff49fe38451451a55266e86a9e9aedecfb44d.tar jellything-5a1ff49fe38451451a55266e86a9e9aedecfb44d.tar.bz2 jellything-5a1ff49fe38451451a55266e86a9e9aedecfb44d.tar.zst |
added api
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/library.rs | 6 | ||||
-rw-r--r-- | server/src/routes/api/error.rs | 57 | ||||
-rw-r--r-- | server/src/routes/api/mod.rs | 51 | ||||
-rw-r--r-- | server/src/routes/mod.rs | 9 | ||||
-rw-r--r-- | server/src/routes/ui/account/mod.rs | 32 | ||||
-rw-r--r-- | server/src/routes/ui/layout.rs | 3 | ||||
-rw-r--r-- | server/src/routes/ui/node.rs | 5 |
7 files changed, 145 insertions, 18 deletions
diff --git a/server/src/library.rs b/server/src/library.rs index 258569e..ea8b095 100644 --- a/server/src/library.rs +++ b/server/src/library.rs @@ -26,7 +26,7 @@ pub enum Node { pub struct Directory { pub lib_path: PathBuf, pub identifier: String, - pub data: DirectoryInfo, + pub info: DirectoryInfo, pub children: Vec<Arc<Node>>, } @@ -79,7 +79,7 @@ impl Node { } pub fn title(&self) -> &str { match self { - Node::Directory(d) => &d.data.name, + Node::Directory(d) => &d.info.name, Node::Item(i) => &i.info.title, } } @@ -130,7 +130,7 @@ impl Node { Node::Directory(Arc::new(Directory { lib_path, children, - data, + info: data, identifier, })) .into(), diff --git a/server/src/routes/api/error.rs b/server/src/routes/api/error.rs new file mode 100644 index 0000000..ef5374c --- /dev/null +++ b/server/src/routes/api/error.rs @@ -0,0 +1,57 @@ +// TODO: Slightâ„¢ code duplication with `ui/error.rs` + +use rocket::{ + response::{self, Responder}, + Request, +}; +use serde_json::{json, Value}; +use std::fmt::Display; + +use crate::routes::ui::error::MyError; + +pub type ApiResult<T> = Result<T, ApiError>; + +#[derive(Debug)] +pub struct ApiError(pub anyhow::Error); + +impl<'r> Responder<'r, 'static> for ApiError { + fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> { + json!({ "error": format!("{}", self.0) }).respond_to(req) + } +} + +impl Display for ApiError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} +impl From<anyhow::Error> for ApiError { + fn from(err: anyhow::Error) -> ApiError { + ApiError(err) + } +} +impl From<std::fmt::Error> for ApiError { + fn from(err: std::fmt::Error) -> ApiError { + ApiError(anyhow::anyhow!("{err}")) + } +} +impl From<std::io::Error> for ApiError { + fn from(err: std::io::Error) -> Self { + ApiError(anyhow::anyhow!("{err}")) + } +} +impl From<sled::Error> for ApiError { + fn from(err: sled::Error) -> Self { + ApiError(anyhow::anyhow!("{err}")) + } +} +impl From<serde_json::Error> for ApiError { + fn from(err: serde_json::Error) -> Self { + ApiError(anyhow::anyhow!("{err}")) + } +} +impl From<MyError> for ApiError { + fn from(value: MyError) -> Self { + Self(value.0) + } +} diff --git a/server/src/routes/api/mod.rs b/server/src/routes/api/mod.rs new file mode 100644 index 0000000..5f48873 --- /dev/null +++ b/server/src/routes/api/mod.rs @@ -0,0 +1,51 @@ +pub mod error; + +use std::path::PathBuf; + +use super::ui::account::{login_logic, LoginForm}; +use crate::{ + database::Database, + library::{Library, Node}, + routes::{api::error::ApiResult, ui::account::session::Session}, +}; +use anyhow::Context; +use rocket::{get, http::CookieJar, post, serde::json::Json, State}; +use serde_json::{json, Value}; + +#[get("/api/version")] +pub fn r_api_version() -> &'static str { + "1" +} + +#[post("/api/account/login", data = "<data>")] +pub fn r_api_account_login( + database: &State<Database>, + jar: &CookieJar, + data: Json<LoginForm>, +) -> ApiResult<Value> { + login_logic(jar, database, &data.username, &data.password)?; + Ok(json!({ "ok": true })) +} + +#[get("/api/library/<path..>")] +pub fn r_api_library_node( + _sess: Session, + path: PathBuf, + library: &State<Library>, +) -> ApiResult<Value> { + let node = library + .nested_path(&path) + .context("retrieving library node")?; + + match node.as_ref() { + Node::Directory(d) => Ok(json!({ + "identifier": d.identifier, + "info": d.info, + "children": d.children.iter().map(|c| c.identifier().to_string()).collect::<Vec<_>>() + })), + Node::Item(i) => Ok(json!({ + "identifier": i.identifier, + "info": i.info, + })), + } +} diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs index 98063da..421907b 100644 --- a/server/src/routes/mod.rs +++ b/server/src/routes/mod.rs @@ -4,6 +4,7 @@ Copyright (C) 2023 metamuffin <metamuffin.org> */ use crate::{database::Database, library::Library, routes::ui::error::MyResult, CONF}; +use api::{r_api_account_login, r_api_version, r_api_library_node}; use jellyremuxer::RemuxerContext; use rocket::{ catchers, config::SecretKey, fairing::AdHoc, fs::FileServer, get, http::Header, routes, Build, @@ -25,6 +26,7 @@ use ui::{ style::{r_assets_font, r_assets_js, r_assets_style}, }; +pub mod api; pub mod stream; pub mod ui; @@ -59,6 +61,8 @@ pub fn build_rocket( routes![ r_home, r_home_unpriv, + r_favicon, + r_item_assets, r_library_node, r_assets_style, r_assets_font, @@ -76,8 +80,9 @@ pub fn build_rocket( r_account_admin_remove_user, r_account_settings, r_account_settings_post, - r_favicon, - r_item_assets, + r_api_version, + r_api_account_login, + r_api_library_node, ], ) } diff --git a/server/src/routes/ui/account/mod.rs b/server/src/routes/ui/account/mod.rs index 9007558..8e6d054 100644 --- a/server/src/routes/ui/account/mod.rs +++ b/server/src/routes/ui/account/mod.rs @@ -24,6 +24,7 @@ use rocket::{ response::Redirect, uri, FromForm, State, }; +use serde::{Deserialize, Serialize}; #[derive(FromForm)] pub struct RegisterForm { @@ -57,7 +58,7 @@ pub async fn r_account_register() -> DynLayoutPage<'static> { } } -#[derive(FromForm)] +#[derive(FromForm, Serialize, Deserialize)] pub struct LoginForm { #[field(validate = len(4..32))] pub username: String, @@ -147,12 +148,29 @@ pub fn r_account_login_post( None => return Err(format_form_error(form)), }; + login_logic(jar, database, &form.username, &form.password)?; + + Ok(Redirect::found(uri!(r_home()))) +} + +#[post("/account/logout")] +pub fn r_account_logout_post(jar: &CookieJar) -> MyResult<Redirect> { + jar.remove_private(Cookie::named("user")); + Ok(Redirect::found(uri!(r_home()))) +} + +pub fn login_logic( + jar: &CookieJar, + database: &Database, + username: &str, + password: &str, +) -> MyResult<()> { // hashing the password regardless if the accounts exists to prevent timing attacks - let password = hash_password(&form.username, &form.password); + let password = hash_password(username, password); let user = database .users - .get(&form.username)? + .get(&username.to_string())? .ok_or(anyhow!("invalid password"))?; if user.password != password { @@ -168,13 +186,7 @@ pub fn r_account_login_post( .finish(), ); - Ok(Redirect::found(uri!(r_home()))) -} - -#[post("/account/logout")] -pub fn r_account_logout_post(jar: &CookieJar) -> MyResult<Redirect> { - jar.remove_private(Cookie::named("user")); - Ok(Redirect::found(uri!(r_home()))) + Ok(()) } pub fn format_form_error<T>(form: Form<Contextual<T>>) -> MyError { diff --git a/server/src/routes/ui/layout.rs b/server/src/routes/ui/layout.rs index 0d4e1ef..bc01c2e 100644 --- a/server/src/routes/ui/layout.rs +++ b/server/src/routes/ui/layout.rs @@ -38,10 +38,11 @@ markup::define! { div.account { @if let Some(session) = session { - span { "Logged in as " a[href=uri!(r_account_settings())] { @session.user.display_name } } + span { "Logged in as " @session.user.display_name } @if session.user.admin { a[href=uri!(r_account_admin_dashboard())] { "Administration" } } + a[href=uri!(r_account_settings())] { "Settings" } a[href=uri!(r_account_logout())] { "Log out" } } else { a[href=uri!(r_account_register())] { "Register" } diff --git a/server/src/routes/ui/node.rs b/server/src/routes/ui/node.rs index dd98a61..ad44410 100644 --- a/server/src/routes/ui/node.rs +++ b/server/src/routes/ui/node.rs @@ -43,11 +43,11 @@ markup::define! { } } DirectoryCard(dir: Arc<Directory>) { - div.card.dir { a[href=&uri!(r_library_node(&dir.lib_path)).to_string()] { @dir.data.name } } + div.card.dir { a[href=&uri!(r_library_node(&dir.lib_path)).to_string()] { @dir.info.name } } } DirectoryPage(dir: Arc<Directory>) { div.page.dir { - h1 { @dir.data.name } + h1 { @dir.info.name } ul.directorylisting { @for el in &dir.children { li { @match el.deref().to_owned() { @@ -82,6 +82,7 @@ markup::define! { } div.title { h1 { @item.info.title } + // TODO release date, duration, ratings a.play[href=&player_uri(&item.lib_path)] { "Watch now" } } div.details { |