aboutsummaryrefslogtreecommitdiff
path: root/server/src/routes/ui
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-02-07 14:08:20 +0100
committermetamuffin <metamuffin@disroot.org>2025-02-07 14:08:20 +0100
commit346095d20e3d817d150cbea49e87a49fbcaa2304 (patch)
tree1fc3868fa68287e916e511c8f5b43b62087f0ff9 /server/src/routes/ui
parent976bdd8e2d14049c766a654a7575f9f5109c7395 (diff)
downloadjellything-346095d20e3d817d150cbea49e87a49fbcaa2304.tar
jellything-346095d20e3d817d150cbea49e87a49fbcaa2304.tar.bz2
jellything-346095d20e3d817d150cbea49e87a49fbcaa2304.tar.zst
nodeid guard
Diffstat (limited to 'server/src/routes/ui')
-rw-r--r--server/src/routes/ui/assets.rs31
-rw-r--r--server/src/routes/ui/layout.rs1
-rw-r--r--server/src/routes/ui/node.rs35
-rw-r--r--server/src/routes/ui/player.rs18
4 files changed, 38 insertions, 47 deletions
diff --git a/server/src/routes/ui/assets.rs b/server/src/routes/ui/assets.rs
index bd48f35..a925e31 100644
--- a/server/src/routes/ui/assets.rs
+++ b/server/src/routes/ui/assets.rs
@@ -9,7 +9,7 @@ use base64::Engine;
use jellybase::{
assetfed::AssetInner, cache::async_cache_file, database::Database, federation::Federation, CONF,
};
-use jellycommon::{LocalTrack, PeopleGroup, SourceTrackKind, TrackSource};
+use jellycommon::{LocalTrack, NodeID, PeopleGroup, SourceTrackKind, TrackSource};
use log::info;
use rocket::{get, http::ContentType, response::Redirect, State};
use std::{path::PathBuf, str::FromStr};
@@ -64,13 +64,11 @@ pub async fn resolve_asset(asset: AssetInner) -> anyhow::Result<PathBuf> {
pub async fn r_item_poster(
_session: Session,
db: &State<Database>,
- id: &str,
+ id: NodeID,
width: Option<usize>,
) -> MyResult<Redirect> {
// TODO perm
- let node = db
- .get_node_slug(id)?
- .ok_or(anyhow!("node does not exist"))?;
+ let node = db.get_node(id)?.ok_or(anyhow!("node does not exist"))?;
let mut asset = node.poster.clone();
if asset.is_none() {
@@ -84,17 +82,16 @@ pub async fn r_item_poster(
});
Ok(Redirect::permanent(rocket::uri!(r_asset(asset.0, width))))
}
+
#[get("/n/<id>/backdrop?<width>")]
pub async fn r_item_backdrop(
_session: Session,
db: &State<Database>,
- id: &str,
+ id: NodeID,
width: Option<usize>,
) -> MyResult<Redirect> {
// TODO perm
- let node = db
- .get_node_slug(id)?
- .ok_or(anyhow!("node does not exist"))?;
+ let node = db.get_node(id)?.ok_or(anyhow!("node does not exist"))?;
let mut asset = node.backdrop.clone();
if asset.is_none() {
@@ -113,16 +110,14 @@ pub async fn r_item_backdrop(
pub async fn r_person_asset(
_session: Session,
db: &State<Database>,
- id: &str,
+ id: NodeID,
index: usize,
group: String,
width: Option<usize>,
) -> MyResult<Redirect> {
// TODO perm
- let node = db
- .get_node_slug(id)?
- .ok_or(anyhow!("node does not exist"))?;
+ let node = db.get_node(id)?.ok_or(anyhow!("node does not exist"))?;
let app = node
.people
.get(&PeopleGroup::from_str(&group).map_err(|()| anyhow!("unknown people group"))?)
@@ -146,13 +141,11 @@ pub async fn r_node_thumbnail(
_session: Session,
db: &State<Database>,
fed: &State<Federation>,
- id: &str,
+ id: NodeID,
t: f64,
width: Option<usize>,
) -> MyResult<Redirect> {
- let node = db
- .get_node_slug(id)?
- .ok_or(anyhow!("node does not exist"))?;
+ let node = db.get_node(id)?.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
@@ -190,8 +183,8 @@ pub async fn r_node_thumbnail(
)
.await?;
- async_cache_file(&["fed-thumb", id, &format!("{t}")], |out| {
- session.node_thumbnail(out, id, 2048, t)
+ async_cache_file(&["fed-thumb", &format!("{id} {t}")], |out| {
+ session.node_thumbnail(out, id.into(), 2048, t)
})
.await?
}
diff --git a/server/src/routes/ui/layout.rs b/server/src/routes/ui/layout.rs
index eb22854..3b2db28 100644
--- a/server/src/routes/ui/layout.rs
+++ b/server/src/routes/ui/layout.rs
@@ -20,6 +20,7 @@ use crate::{
use futures::executor::block_on;
use jellybase::CONF;
use jellycommon::user::Theme;
+use jellycommon::NodeID;
use jellyimport::is_importing;
use markup::{DynRender, Render};
use rocket::{
diff --git a/server/src/routes/ui/node.rs b/server/src/routes/ui/node.rs
index 365182c..ebd21db 100644
--- a/server/src/routes/ui/node.rs
+++ b/server/src/routes/ui/node.rs
@@ -40,21 +40,20 @@ use std::sync::Arc;
/// This function is a stub and only useful for use in the uri! macro.
#[get("/n/<id>")]
-pub fn r_library_node(id: String) {
- drop(id)
+pub fn r_library_node(id: NodeID) {
+ id.0[0];
}
-#[get("/n/<slug>?<parents>&<children>&<filter..>")]
+#[get("/n/<id>?<parents>&<children>&<filter..>")]
pub async fn r_library_node_filter<'a>(
session: Session,
- slug: &'a str,
+ id: NodeID,
db: &'a State<Database>,
aj: AcceptJson,
filter: NodeFilterSort,
parents: bool,
children: bool,
) -> MyResult<Either<DynLayoutPage<'a>, Json<ApiNodeResponse>>> {
- let id = NodeID::from_slug(slug);
let (node, udata) = db.get_node_with_userdata(id, &session)?;
let mut children = if !*aj || children {
@@ -99,7 +98,7 @@ pub async fn r_library_node_filter<'a>(
Either::Left(LayoutPage {
title: node.title.clone().unwrap_or_default(),
content: markup::new! {
- @NodePage { node: &node, id: slug, udata: &udata, children: &children, parents: &parents, filter: &filter }
+ @NodePage { node: &node, udata: &udata, children: &children, parents: &parents, filter: &filter }
},
..Default::default()
})
@@ -152,43 +151,43 @@ markup::define! {
}
}
}
- NodePage<'a>(id: &'a str, node: &'a Node, udata: &'a NodeUserData, children: &'a [(Arc<Node>, NodeUserData)], parents: &'a [(Arc<Node>, NodeUserData)], filter: &'a NodeFilterSort) {
+ NodePage<'a>(node: &'a Node, udata: &'a NodeUserData, children: &'a [(Arc<Node>, NodeUserData)], parents: &'a [(Arc<Node>, NodeUserData)], filter: &'a NodeFilterSort) {
@if !matches!(node.kind, NodeKind::Collection) {
- img.backdrop[src=uri!(r_item_backdrop(id, Some(2048))), loading="lazy"];
+ img.backdrop[src=uri!(r_item_backdrop(&node.slug, Some(2048))), loading="lazy"];
}
.page.node {
@if !matches!(node.kind, NodeKind::Collection) {
@let cls = format!("bigposter {}", aspect_class(node.kind));
- div[class=cls] { img[src=uri!(r_item_poster(id, Some(2048))), loading="lazy"]; }
+ div[class=cls] { img[src=uri!(r_item_poster(&node.slug, Some(2048))), loading="lazy"]; }
}
.title {
h1 { @node.title }
ul.parents { @for (node, _) in *parents { li {
a.component[href=uri!(r_library_node(&node.slug))] { @node.title }
}}}
- @if node.media.is_some() { a.play[href=&uri!(r_player(id, PlayerConfig::default()))] { "Watch now" }}
+ @if node.media.is_some() { a.play[href=&uri!(r_player(&node.slug, PlayerConfig::default()))] { "Watch now" }}
@if !matches!(node.kind, NodeKind::Collection | NodeKind::Channel) {
@if matches!(udata.watched, WatchedState::None | WatchedState::Pending | WatchedState::Progress(_)) {
- form.mark_watched[method="POST", action=uri!(r_node_userdata_watched(id, UrlWatchedState::Watched))] {
+ form.mark_watched[method="POST", action=uri!(r_node_userdata_watched(&node.slug, UrlWatchedState::Watched))] {
input[type="submit", value="Mark Watched"];
}
}
@if matches!(udata.watched, WatchedState::Watched) {
- form.mark_unwatched[method="POST", action=uri!(r_node_userdata_watched(id, UrlWatchedState::None))] {
+ form.mark_unwatched[method="POST", action=uri!(r_node_userdata_watched(&node.slug, UrlWatchedState::None))] {
input[type="submit", value="Mark Unwatched"];
}
}
@if matches!(udata.watched, WatchedState::None) {
- form.mark_unwatched[method="POST", action=uri!(r_node_userdata_watched(id, UrlWatchedState::Pending))] {
+ form.mark_unwatched[method="POST", action=uri!(r_node_userdata_watched(&node.slug, UrlWatchedState::Pending))] {
input[type="submit", value="Add to Watchlist"];
}
}
@if matches!(udata.watched, WatchedState::Pending) {
- form.mark_unwatched[method="POST", action=uri!(r_node_userdata_watched(id, UrlWatchedState::None))] {
+ form.mark_unwatched[method="POST", action=uri!(r_node_userdata_watched(&node.slug, UrlWatchedState::None))] {
input[type="submit", value="Remove from Watchlist"];
}
}
- form.rating[method="POST", action=uri!(r_node_userdata_rating(id))] {
+ form.rating[method="POST", action=uri!(r_node_userdata_rating(&node.slug))] {
input[type="range", name="rating", min=-10, max=10, step=1, value=udata.rating];
input[type="submit", value="Update Rating"];
}
@@ -207,8 +206,8 @@ markup::define! {
@let (inl, sub) = format_chapter(chap);
li { .card."aspect-thumb" {
.poster {
- a[href=&uri!(r_player(id, PlayerConfig::seek(chap.time_start.unwrap_or(0.))))] {
- img[src=&uri!(r_node_thumbnail(id, chapter_key_time(chap, media.duration), Some(1024))), loading="lazy"];
+ a[href=&uri!(r_player(&node.slug, PlayerConfig::seek(chap.time_start.unwrap_or(0.))))] {
+ img[src=&uri!(r_node_thumbnail(&node.slug, chapter_key_time(chap, media.duration), Some(1024))), loading="lazy"];
}
.cardhover { .props { p { @inl } } }
}
@@ -225,7 +224,7 @@ markup::define! {
li { .card."aspect-port" {
.poster {
a[href="#"] {
- img[src=&uri!(r_person_asset(id, i, group.to_string(), Some(1024))), loading="lazy"];
+ img[src=&uri!(r_person_asset(&node.slug, i, group.to_string(), Some(1024))), loading="lazy"];
}
}
.title {
diff --git a/server/src/routes/ui/player.rs b/server/src/routes/ui/player.rs
index b24e5e9..f680a45 100644
--- a/server/src/routes/ui/player.rs
+++ b/server/src/routes/ui/player.rs
@@ -20,7 +20,7 @@ use jellybase::{permission::PermissionSetExt, CONF};
use jellycommon::{
stream::{StreamFormat, StreamSpec},
user::{PermissionSet, PlayerKind, UserPermission},
- Node, SourceTrackKind, TrackID,
+ Node, NodeID, SourceTrackKind, TrackID,
};
use markup::DynRender;
use rocket::{get, response::Redirect, Either, FromForm, State, UriDisplayQuery};
@@ -61,12 +61,10 @@ fn jellynative_url(action: &str, seek: f64, secret: &str, node: &str, session: &
pub fn r_player<'a>(
sess: Session,
db: &'a State<Database>,
- id: &'a str,
+ id: NodeID,
conf: PlayerConfig,
) -> MyResult<Either<DynLayoutPage<'a>, Redirect>> {
- let item = db
- .get_node_slug(id)?
- .ok_or(anyhow!("node does not exist"))?;
+ let node = db.get_node(id)?.ok_or(anyhow!("node does not exist"))?;
let native_session = |action: &str| {
let perm = [
@@ -81,7 +79,7 @@ pub fn r_player<'a>(
action,
conf.t.unwrap_or(0.),
&sess.user.native_secret,
- id,
+ &id.to_string(),
&token::create(
sess.user.name,
PermissionSet(perm.map(|e| (e, true)).into()),
@@ -114,15 +112,15 @@ pub fn r_player<'a>(
let playing = !spec.track.is_empty();
- let conf = player_conf(item.clone(), playing)?;
+ let conf = player_conf(node.clone(), playing)?;
Ok(Either::Left(LayoutPage {
- title: item.title.to_owned().unwrap_or_default(),
+ title: node.title.to_owned().unwrap_or_default(),
class: Some("player"),
content: markup::new! {
@if playing {
- video[src=uri!(r_stream(&id, &spec)), controls, preload="auto"]{}
+ video[src=uri!(r_stream(&node.slug, &spec)), controls, preload="auto"]{}
} else {
- img.backdrop[src=uri!(r_item_backdrop(&id, Some(2048))).to_string()];
+ img.backdrop[src=uri!(r_item_backdrop(&node.slug, Some(2048))).to_string()];
}
@conf
},