playlists

This commit is contained in:
JMARyA 2024-08-11 21:56:55 +02:00
parent 428aa6e066
commit 82c330cc13
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
4 changed files with 112 additions and 18 deletions

View file

@ -1,11 +1,14 @@
use mongod::{ use mongod::{
assert_reference_of, assert_reference_of,
derive::{Model, Referencable}, derive::{Model, Referencable},
Referencable, Reference, Validate, reference_of, Model, Referencable, Reference, Validate,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{library::{track::Track, user::User}, route::ToAPI}; use crate::{
library::{track::Track, user::User},
route::ToAPI,
};
#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)] #[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)]
pub struct Playlist { pub struct Playlist {
@ -16,6 +19,29 @@ pub struct Playlist {
pub tracks: Vec<Reference>, pub tracks: Vec<Reference>,
} }
impl Playlist {
pub async fn create(
owner: User,
title: &str,
visibility: Visibility,
tracks: &[String],
) -> Option<Self> {
let mut tracks_ref = vec![];
for track in tracks {
tracks_ref.push(reference_of!(Track, track)?);
}
Some(Self {
_id: uuid::Uuid::new_v4().to_string(),
owner: owner.reference(),
title: title.to_string(),
visibility,
tracks: tracks_ref,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum Visibility { pub enum Visibility {
Private, Private,

View file

@ -61,7 +61,9 @@ async fn rocket() -> _ {
route::user::users_route, route::user::users_route,
route::track::track_audio_opus128_route, route::track::track_audio_opus128_route,
route::playlist::playlists_route, route::playlist::playlists_route,
route::playlist::playlist_route route::playlist::playlist_route,
route::playlist::playlist_add_route,
route::playlist::playlist_edit_route
], ],
) )
.manage(lib) .manage(lib)

View file

@ -7,9 +7,9 @@ use serde_json::json;
pub mod album; pub mod album;
pub mod artist; pub mod artist;
pub mod playlist;
pub mod track; pub mod track;
pub mod user; pub mod user;
pub mod playlist;
// todo : rework api // todo : rework api

View file

@ -1,27 +1,34 @@
use super::api_error; use crate::library::track::Track;
use super::FallibleApiResponse; use crate::library::user::User;
use super::ToAPI; use mongod::reference_of;
use mongod::Model; use mongod::Model;
use mongod::Referencable; use mongod::Referencable;
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::*; use rocket::get;
use rocket::post;
use rocket::serde::json::Json;
use serde_json::json; use serde_json::json;
use crate::library::playlist::Playlist; use crate::library::playlist::Playlist;
use crate::library::playlist::Visibility; use crate::library::playlist::Visibility;
use crate::library::user::User; use crate::route::FallibleApiResponse;
use super::api_error;
use super::ToAPI;
#[get("/playlists")] #[get("/playlists")]
pub async fn playlists_route(u: User) -> FallibleApiResponse { pub async fn playlists_route(u: User) -> FallibleApiResponse {
let mut playlists = vec![ let mut playlists = vec![json!({"id": "recent", "name": "Recently Played"})];
"recent".to_string()
];
let own_playlists = Playlist::find(doc! { "owner": u.reference()}, None).await.unwrap(); let own_playlists = Playlist::find(doc! { "owner": u.reference()}, None)
.await
.unwrap();
for playlist in own_playlists { for playlist in own_playlists {
playlists.push(playlist._id); playlists.push(json!({
"id": playlist._id,
"name": playlist.title
}));
} }
Ok(json!(playlists)) Ok(json!(playlists))
@ -33,11 +40,70 @@ pub async fn playlist_route(id: &str, u: User) -> FallibleApiResponse {
// todo : recently played // todo : recently played
} }
let playlist = Playlist::get(id).await.ok_or_else(|| api_error("No playlist with that ID found"))?; let playlist = Playlist::get(id)
.await
.ok_or_else(|| api_error("No playlist with that ID found"))?;
if matches!(playlist.visibility, Visibility::Private) && u.username != playlist.owner.get::<User>().await.username { if matches!(playlist.visibility, Visibility::Private)
&& u.username != playlist.owner.get::<User>().await.username
{
return Err(api_error("Forbidden")); return Err(api_error("Forbidden"));
} }
Ok(playlist.api().await) Ok(playlist.api().await)
} }
#[derive(rocket::serde::Deserialize)]
pub struct PlaylistData {
pub title: String,
pub visibility: Visibility,
pub tracks: Vec<String>,
}
#[post("/playlist", data = "<playlist>")]
pub async fn playlist_add_route(playlist: Json<PlaylistData>, u: User) -> FallibleApiResponse {
let playlist = Playlist::create(
u,
&playlist.title,
playlist.visibility.clone(),
&playlist.tracks,
)
.await
.ok_or_else(|| api_error("Failed to create playlist"))?;
playlist.insert().await.unwrap();
Ok(json!({"created": playlist._id}))
}
#[post("/playlist/<id>", data = "<edit>")]
pub async fn playlist_edit_route(
id: &str,
edit: Json<PlaylistData>,
u: User,
) -> FallibleApiResponse {
let mut playlist = Playlist::get(id)
.await
.ok_or_else(|| api_error("No playlist with that ID found"))?;
if playlist.owner.id() != u._id {
return Err(api_error("Forbidden"));
}
let mut tracks_ref = vec![];
for track in &edit.tracks {
tracks_ref
.push(reference_of!(Track, track).ok_or_else(|| api_error("Invalid tracks found"))?);
}
playlist
.update(&json!({
"title": edit.title,
"visibility": edit.visibility,
"tracks": tracks_ref
}))
.await
.unwrap();
Ok(json!({"edited": playlist._id}))
}