playlists
This commit is contained in:
parent
428aa6e066
commit
82c330cc13
4 changed files with 112 additions and 18 deletions
|
@ -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,
|
||||||
|
@ -43,4 +69,4 @@ impl ToAPI for Playlist {
|
||||||
"tracks": self.tracks.iter().map(|x| x.id()).collect::<Vec<_>>()
|
"tracks": self.tracks.iter().map(|x| x.id()).collect::<Vec<_>>()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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}))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue