update
This commit is contained in:
parent
dcf546fa9c
commit
1e67f223f7
10 changed files with 164 additions and 92 deletions
|
@ -11,6 +11,7 @@ use walkdir::WalkDir;
|
|||
pub mod album;
|
||||
pub mod artist;
|
||||
pub mod metadata;
|
||||
pub mod playlist;
|
||||
pub mod track;
|
||||
pub mod user;
|
||||
|
||||
|
@ -52,7 +53,7 @@ impl Libary {
|
|||
|
||||
pub async fn add_path_to_library(&self, path: &str) {
|
||||
// search for path already present
|
||||
if let Some(_) = Track::find_one_partial(doc! { "path": path }, &json!({})).await {
|
||||
if let Some(_) = Track::find_one_partial(doc! { "path": path }, json!({})).await {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -109,7 +110,7 @@ impl Libary {
|
|||
}
|
||||
|
||||
pub async fn get_artists(&self) -> Vec<Artist> {
|
||||
Artist::find(doc! {}).await.unwrap()
|
||||
Artist::find(doc! {}, None).await.unwrap()
|
||||
}
|
||||
|
||||
pub async fn get_artist_by_id(&self, id: &str) -> Option<Artist> {
|
||||
|
@ -118,7 +119,9 @@ impl Libary {
|
|||
|
||||
pub async fn get_albums_by_artist(&self, artist: &str) -> Vec<Album> {
|
||||
let artist = format!("artist::{artist}");
|
||||
Album::find(doc! { "artist_id": artist}).await.unwrap()
|
||||
Album::find(doc! { "artist_id": artist}, None)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub async fn get_album_by_id(&self, album: &str) -> Option<Album> {
|
||||
|
@ -126,7 +129,7 @@ impl Libary {
|
|||
}
|
||||
|
||||
pub async fn get_tracks_of_album(&self, album: &str) -> Vec<Track> {
|
||||
Track::find(doc! { "album_id": album}).await.unwrap()
|
||||
Track::find(doc! { "album_id": album}, None).await.unwrap()
|
||||
}
|
||||
|
||||
pub async fn get_track_by_id(&self, track_id: &str) -> Option<Track> {
|
||||
|
|
35
src/library/playlist.rs
Normal file
35
src/library/playlist.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use mongod::{
|
||||
assert_reference_of,
|
||||
derive::{Model, Referencable},
|
||||
Referencable, Reference, Validate,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::library::{track::Track, user::User};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)]
|
||||
pub struct Playlist {
|
||||
pub _id: String,
|
||||
pub owner: Reference,
|
||||
pub title: String,
|
||||
pub visibility: Visibility,
|
||||
pub tracks: Vec<Reference>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum Visibility {
|
||||
Private,
|
||||
Public,
|
||||
}
|
||||
|
||||
impl Validate for Playlist {
|
||||
async fn validate(&self) -> Result<(), String> {
|
||||
assert_reference_of!(self.owner, User);
|
||||
|
||||
for track in &self.tracks {
|
||||
assert_reference_of!(track, Track);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -4,8 +4,9 @@ use mongod::{
|
|||
Model, Referencable, Reference, Validate,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::library::artist::Artist;
|
||||
use crate::library::{album::Album, artist::Artist};
|
||||
|
||||
use super::metadata::AudioMetadata;
|
||||
|
||||
|
@ -34,6 +35,36 @@ impl Track {
|
|||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub async fn api(&self) -> serde_json::Value {
|
||||
let album_title = if let Some(album_ref) = &self.album_id {
|
||||
album_ref
|
||||
.get_partial::<Album>(json!({"title": 1}))
|
||||
.await
|
||||
.title
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let artist_title = if let Some(artist_ref) = &self.artist_id {
|
||||
artist_ref
|
||||
.get_partial::<Artist>(json!({"name": 1}))
|
||||
.await
|
||||
.name
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
json!({
|
||||
"id": self._id,
|
||||
"title": self.title,
|
||||
"meta": serde_json::to_value(&self.meta).unwrap(),
|
||||
"album_id": self.album_id.as_ref().map(|x| x.id().to_string()),
|
||||
"album": album_title,
|
||||
"artist_id": self.artist_id.as_ref().map(|x| x.id().to_string()),
|
||||
"artist": artist_title
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Validate for Track {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use data_encoding::HEXUPPER;
|
||||
use mongod::{
|
||||
assert_reference_of, derive::{Model, Referencable}, Model, Referencable, Reference, Validate
|
||||
assert_reference_of,
|
||||
derive::{Model, Referencable},
|
||||
Model, Referencable, Reference, Validate,
|
||||
};
|
||||
use mongodb::bson::doc;
|
||||
use rand::RngCore;
|
||||
|
@ -20,13 +22,13 @@ pub struct User {
|
|||
pub _id: String,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub role: UserRole
|
||||
pub role: UserRole,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum UserRole {
|
||||
Regular,
|
||||
Admin
|
||||
Admin,
|
||||
}
|
||||
|
||||
impl Validate for User {
|
||||
|
@ -37,15 +39,18 @@ impl Validate for User {
|
|||
|
||||
impl User {
|
||||
pub async fn create(username: &str, password: &str, role: UserRole) -> Option<Self> {
|
||||
if User::find_one_partial(doc! { "username": username }, &json!({})).await.is_some() {
|
||||
if User::find_one_partial(doc! { "username": username }, json!({}))
|
||||
.await
|
||||
.is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let u = User{
|
||||
let u = User {
|
||||
_id: uuid::Uuid::new_v4().to_string(),
|
||||
username: username.to_string(),
|
||||
password: bcrypt::hash(password, bcrypt::DEFAULT_COST).unwrap(),
|
||||
role
|
||||
role,
|
||||
};
|
||||
|
||||
u.insert().await.unwrap();
|
||||
|
@ -64,10 +69,10 @@ impl User {
|
|||
}
|
||||
|
||||
pub async fn session(&self) -> Session {
|
||||
let s = Session{
|
||||
let s = Session {
|
||||
_id: uuid::Uuid::new_v4().to_string(),
|
||||
token: gen_token(60),
|
||||
user: self.reference()
|
||||
user: self.reference(),
|
||||
};
|
||||
|
||||
s.insert().await.unwrap();
|
||||
|
@ -88,7 +93,7 @@ impl User {
|
|||
pub struct Session {
|
||||
pub _id: String,
|
||||
pub token: String,
|
||||
pub user: Reference
|
||||
pub user: Reference,
|
||||
}
|
||||
|
||||
impl Validate for Session {
|
||||
|
@ -97,4 +102,4 @@ impl Validate for Session {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use super::api_error;
|
||||
use super::FallibleApiResponse;
|
||||
use mongod::Referencable;
|
||||
use mongodb::bson::doc;
|
||||
use rocket::fs::NamedFile;
|
||||
use rocket::*;
|
||||
use serde_json::json;
|
||||
use rocket::fs::NamedFile;
|
||||
use mongod::Referencable;
|
||||
use super::FallibleApiResponse;
|
||||
use super::api_error;
|
||||
|
||||
use crate::library::Libary;
|
||||
|
||||
|
@ -80,4 +80,4 @@ pub async fn album_route(album_id: &str, lib: &State<Libary>) -> FallibleApiResp
|
|||
.insert("tracks".into(), tracks.into());
|
||||
|
||||
Ok(album)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::api_error;
|
||||
use super::FallibleApiResponse;
|
||||
use mongodb::bson::doc;
|
||||
use rocket::*;
|
||||
use super::FallibleApiResponse;
|
||||
use super::api_error;
|
||||
|
||||
use crate::library::Libary;
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use rocket::response::status::BadRequest;
|
||||
use serde_json::json;
|
||||
|
||||
pub mod artist;
|
||||
pub mod album;
|
||||
pub mod artist;
|
||||
pub mod track;
|
||||
pub mod user;
|
||||
|
||||
|
||||
type ApiError = BadRequest<serde_json::Value>;
|
||||
type FallibleApiResponse = Result<serde_json::Value, ApiError>;
|
||||
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
use rocket::*;
|
||||
use super::api_error;
|
||||
use super::FallibleApiResponse;
|
||||
use fs::NamedFile;
|
||||
use mongodb::bson::doc;
|
||||
use super::FallibleApiResponse;
|
||||
use super::api_error;
|
||||
use rocket::*;
|
||||
|
||||
use crate::library::Libary;
|
||||
|
||||
#[get("/track/<track_id>")]
|
||||
pub async fn track_route(track_id: &str, lib: &State<Libary>) -> FallibleApiResponse {
|
||||
Ok(serde_json::to_value(
|
||||
&lib.get_track_by_id(track_id)
|
||||
.await
|
||||
.ok_or_else(|| api_error("No track with that ID found"))?,
|
||||
)
|
||||
.unwrap())
|
||||
Ok(lib
|
||||
.get_track_by_id(track_id)
|
||||
.await
|
||||
.ok_or_else(|| api_error("No track with that ID found"))?
|
||||
.api()
|
||||
.await)
|
||||
}
|
||||
|
||||
#[get("/track/<track_id>/audio")]
|
||||
|
@ -22,4 +22,4 @@ pub async fn track_audio_route(track_id: &str, lib: &State<Libary>) -> Option<Na
|
|||
NamedFile::open(std::path::Path::new(&track.path))
|
||||
.await
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
|
||||
use rocket::http::Status;
|
||||
use crate::library::user::Session;
|
||||
use crate::library::user::User;
|
||||
use mongod::Model;
|
||||
use mongodb::bson::doc;
|
||||
use rocket::http::Status;
|
||||
use rocket::outcome::Outcome;
|
||||
use rocket::post;
|
||||
use rocket::request::FromRequest;
|
||||
use rocket::Request;
|
||||
use serde_json::json;
|
||||
use serde::Deserialize;
|
||||
use rocket::serde::json::Json;
|
||||
use crate::library::user::Session;
|
||||
use crate::library::user::User;
|
||||
use rocket::Request;
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
|
||||
use super::FallibleApiResponse;
|
||||
use super::api_error;
|
||||
use super::FallibleApiResponse;
|
||||
|
||||
#[rocket::async_trait]
|
||||
impl<'r> FromRequest<'r> for User {
|
||||
|
@ -22,13 +21,13 @@ impl<'r> FromRequest<'r> for User {
|
|||
async fn from_request(request: &'r Request<'_>) -> rocket::request::Outcome<Self, Self::Error> {
|
||||
match request.headers().get_one("token") {
|
||||
Some(key) => {
|
||||
if let Some(session) = Session::find_one(doc! { "token": key} ).await {
|
||||
if let Some(session) = Session::find_one(doc! { "token": key}).await {
|
||||
let user = session.user.get().await;
|
||||
Outcome::Success(user)
|
||||
} else {
|
||||
Outcome::Error((Status::Unauthorized, ()))
|
||||
}
|
||||
},
|
||||
}
|
||||
None => Outcome::Error((Status::Unauthorized, ())),
|
||||
}
|
||||
}
|
||||
|
@ -37,15 +36,16 @@ impl<'r> FromRequest<'r> for User {
|
|||
#[derive(Deserialize)]
|
||||
pub struct LoginData {
|
||||
pub username: String,
|
||||
pub password: String
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[post("/login", data = "<login>")]
|
||||
pub async fn login_route(login: Json<LoginData>) -> FallibleApiResponse {
|
||||
let ses = User::login(&login.username, &login.password).await.ok_or_else(|| api_error("Login failed"))?;
|
||||
let ses = User::login(&login.username, &login.password)
|
||||
.await
|
||||
.ok_or_else(|| api_error("Login failed"))?;
|
||||
|
||||
Ok(json!({
|
||||
"token": ses.token
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue