updatse
This commit is contained in:
parent
8a19a733d6
commit
52ef924f12
28 changed files with 577 additions and 170 deletions
|
@ -1,13 +1,18 @@
|
|||
use crate::utils::get_jwt_secret;
|
||||
use jwt::VerifyWithKey;
|
||||
use std::collections::BTreeMap;
|
||||
use crate::routes::auth::JWTClaims;
|
||||
use jsonwebtoken::errors::Error;
|
||||
use jsonwebtoken::{decode, DecodingKey, EncodingKey, TokenData, Validation};
|
||||
|
||||
pub fn get_token(token: &str) -> Result<BTreeMap<String, String>, &str> {
|
||||
let secret = get_jwt_secret().unwrap();
|
||||
let claims = token.verify_with_key(&secret);
|
||||
const JWT_SECRET: &str = "secret";
|
||||
|
||||
match claims {
|
||||
Ok(claims) => Ok(claims),
|
||||
Err(_e) => return Err("Error parsing token"),
|
||||
}
|
||||
pub fn get_token(token: &str) -> Result<TokenData<JWTClaims>, Error> {
|
||||
let token = decode::<JWTClaims>(&token, &get_decoding_key(), &Validation::default())?;
|
||||
Ok(token)
|
||||
}
|
||||
|
||||
pub fn get_encoding_key() -> EncodingKey {
|
||||
EncodingKey::from_secret(JWT_SECRET.as_ref())
|
||||
}
|
||||
|
||||
pub fn get_decoding_key() -> DecodingKey {
|
||||
DecodingKey::from_secret(JWT_SECRET.as_ref())
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
extern crate core;
|
||||
|
||||
mod helpers;
|
||||
mod middlewares;
|
||||
mod models;
|
||||
mod routes;
|
||||
mod schema;
|
||||
mod utils;
|
||||
|
||||
use crate::helpers::db;
|
||||
use actix_web::{web, App, HttpServer};
|
||||
|
@ -20,7 +21,7 @@ async fn main() -> std::io::Result<()> {
|
|||
.service(web::scope("/playlists").service(routes::playlists::get_playlist))
|
||||
.service(routes::auth::login)
|
||||
.service(routes::me::routes())
|
||||
.service(web::scope("/users").service(routes::users::get_user))
|
||||
.service(routes::users::routes())
|
||||
})
|
||||
.bind(("127.0.0.1", 9000))?
|
||||
.run()
|
||||
|
|
|
@ -9,18 +9,24 @@ pub fn get_user(req: HttpRequest) -> Result<Users, ErrorResponse> {
|
|||
|
||||
match authorization {
|
||||
Some(header) => {
|
||||
let claims = get_token(header.to_str().unwrap());
|
||||
let token_data = get_token(header.to_str().unwrap());
|
||||
|
||||
match claims {
|
||||
Ok(claims) => {
|
||||
let user = Users::find(claims["user_id"].as_str())?;
|
||||
match token_data {
|
||||
Ok(token_data) => {
|
||||
let user = Users::find(token_data.claims.user_id.as_str())?;
|
||||
|
||||
Ok(user)
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(ErrorResponse {
|
||||
message: e.to_string(),
|
||||
status: StatusCode::INTERNAL_SERVER_ERROR,
|
||||
return Err(match e.kind() {
|
||||
jsonwebtoken::errors::ErrorKind::ExpiredSignature => ErrorResponse {
|
||||
message: "Not Authorized".to_string(),
|
||||
status: StatusCode::UNAUTHORIZED,
|
||||
},
|
||||
_ => ErrorResponse {
|
||||
message: e.to_string(),
|
||||
status: StatusCode::INTERNAL_SERVER_ERROR,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
79
src/models/artists.rs
Normal file
79
src/models/artists.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
use crate::helpers::db;
|
||||
use crate::schema::{artists, artists_tracks};
|
||||
use chrono::NaiveDateTime;
|
||||
use diesel::result::Error;
|
||||
use diesel::{
|
||||
AsChangeset, ExpressionMethods, Insertable, QueryDsl, Queryable, RunQueryDsl, Selectable,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(AsChangeset, Insertable, Queryable, Selectable, Deserialize, Serialize)]
|
||||
#[diesel(table_name = crate::schema::artists)]
|
||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||
pub struct Artist {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
|
||||
created_at: NaiveDateTime,
|
||||
updated_at: Option<NaiveDateTime>,
|
||||
|
||||
pub spotify_id: Option<String>,
|
||||
pub tidal_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Queryable, Serialize)]
|
||||
pub struct Artists {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
|
||||
created_at: NaiveDateTime,
|
||||
updated_at: Option<NaiveDateTime>,
|
||||
|
||||
pub spotify_id: Option<String>,
|
||||
pub tidal_id: Option<String>,
|
||||
}
|
||||
|
||||
impl Artists {
|
||||
pub fn find(id: String) -> Result<Self, Error> {
|
||||
let conn = &mut db::connection()?;
|
||||
let playlist = artists::table.filter(artists::id.eq(id)).first(conn)?;
|
||||
Ok(playlist)
|
||||
}
|
||||
|
||||
pub fn create(artist: Artist) -> Result<Self, Error> {
|
||||
let conn = &mut db::connection()?;
|
||||
let playlist = diesel::insert_into(artists::table)
|
||||
.values(Artist::from(artist))
|
||||
.get_result(conn)?;
|
||||
Ok(playlist)
|
||||
}
|
||||
|
||||
pub fn find_by_track(track_id: &str) -> Result<Vec<Artists>, Error> {
|
||||
let conn = &mut db::connection()?;
|
||||
let tracks: Vec<(String, String)> = artists_tracks::table
|
||||
.filter(artists_tracks::track_id.eq(track_id))
|
||||
.get_results::<(String, String)>(conn)?;
|
||||
|
||||
let artists = tracks
|
||||
.into_iter()
|
||||
.map(|(artist_id, _)| Artists::find(artist_id).unwrap())
|
||||
.collect::<Vec<Artists>>();
|
||||
|
||||
Ok(artists)
|
||||
}
|
||||
}
|
||||
|
||||
impl Artist {
|
||||
fn from(artist: Artist) -> Artist {
|
||||
Artist {
|
||||
id: artist.id,
|
||||
name: artist.name,
|
||||
|
||||
created_at: artist.created_at,
|
||||
updated_at: artist.updated_at,
|
||||
|
||||
spotify_id: artist.spotify_id,
|
||||
tidal_id: artist.tidal_id,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod playlist;
|
||||
pub mod artists;
|
||||
pub mod playlists;
|
||||
pub mod tracks;
|
||||
pub mod user;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use crate::helpers::db;
|
||||
use crate::models::tracks::Tracks;
|
||||
use crate::models::tracks::{Track, Tracks, TracksWithArtists};
|
||||
use crate::models::user::Users;
|
||||
use crate::schema::playlists;
|
||||
use chrono::NaiveDateTime;
|
||||
use diesel::result::Error;
|
||||
use diesel::{
|
||||
AsChangeset, EqAll, ExpressionMethods, Insertable, QueryDsl, Queryable, RunQueryDsl, Selectable,
|
||||
AsChangeset, ExpressionMethods, Insertable, QueryDsl, Queryable, RunQueryDsl, Selectable,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -22,6 +22,7 @@ pub struct PlaylistCreator {
|
|||
pub struct Playlist {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub public: bool,
|
||||
pub creator_id: String,
|
||||
|
||||
pub created_at: NaiveDateTime,
|
||||
|
@ -32,6 +33,7 @@ pub struct Playlist {
|
|||
pub struct Playlists {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub public: bool,
|
||||
pub creator_id: String,
|
||||
|
||||
pub created_at: NaiveDateTime,
|
||||
|
@ -45,24 +47,36 @@ impl Playlists {
|
|||
Ok(playlist)
|
||||
}
|
||||
|
||||
pub fn create(playlist: Playlist) -> Result<Self, Error> {
|
||||
pub fn create(playlist: NewPlaylist) -> Result<Self, Error> {
|
||||
let conn = &mut db::connection()?;
|
||||
let playlist = diesel::insert_into(playlists::table)
|
||||
.values(Playlist::from(playlist))
|
||||
.values(playlist)
|
||||
.get_result(conn)?;
|
||||
Ok(playlist)
|
||||
}
|
||||
|
||||
pub fn find_for_user(user_id: &str) -> Result<Vec<Playlists>, Error> {
|
||||
pub fn find_for_user(user_id: &str, filter_public: bool) -> Result<Vec<Playlists>, Error> {
|
||||
let conn = &mut db::connection()?;
|
||||
let playlists = playlists::table
|
||||
|
||||
let mut playlists = playlists::table
|
||||
.filter(playlists::creator_id.eq(user_id))
|
||||
.get_results(conn)?;
|
||||
.into_boxed();
|
||||
|
||||
if filter_public {
|
||||
playlists = playlists.filter(playlists::public.eq(true));
|
||||
}
|
||||
|
||||
let playlists = playlists.get_results(conn)?;
|
||||
Ok(playlists)
|
||||
}
|
||||
|
||||
pub fn get_tracks(&self) -> Result<Vec<Tracks>, Error> {
|
||||
pub fn get_tracks(&self) -> Result<Vec<TracksWithArtists>, Error> {
|
||||
let tracks = Tracks::find_by_playlist(&self.id)?;
|
||||
let tracks: Vec<TracksWithArtists> = tracks
|
||||
.into_iter()
|
||||
.map(Track::with_artists)
|
||||
.collect::<Result<Vec<TracksWithArtists>, _>>()?;
|
||||
|
||||
Ok(tracks)
|
||||
}
|
||||
|
||||
|
@ -72,11 +86,28 @@ impl Playlists {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Insertable, Deserialize)]
|
||||
#[diesel(table_name = playlists)]
|
||||
pub struct NewPlaylist {
|
||||
pub name: String,
|
||||
pub public: bool,
|
||||
pub creator_id: Option<String>,
|
||||
}
|
||||
|
||||
impl Playlist {
|
||||
pub fn create(name: &str, public: bool, creator_id: &str) -> NewPlaylist {
|
||||
NewPlaylist {
|
||||
name: name.to_string(),
|
||||
public,
|
||||
creator_id: Some(creator_id.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn from(playlist: Playlist) -> Playlist {
|
||||
Playlist {
|
||||
id: playlist.id,
|
||||
name: playlist.name,
|
||||
public: playlist.public,
|
||||
creator_id: playlist.creator_id,
|
||||
|
||||
created_at: playlist.created_at,
|
|
@ -1,4 +1,5 @@
|
|||
use crate::helpers::db;
|
||||
use crate::models::artists::Artists;
|
||||
use crate::schema::tracks;
|
||||
use chrono::NaiveDateTime;
|
||||
use diesel::result::Error;
|
||||
|
@ -69,11 +70,10 @@ impl Tracks {
|
|||
Ok(tracks)
|
||||
}
|
||||
|
||||
// pub fn get_artist(&self) -> Result<Artist, Error> {
|
||||
// let conn = &mut db::connection();
|
||||
// let artist = ;
|
||||
// Ok(artist)
|
||||
// }
|
||||
pub fn get_artists(&self) -> Result<Vec<Artists>, Error> {
|
||||
let artists = Artists::find_by_track(&self.id)?;
|
||||
Ok(artists)
|
||||
}
|
||||
}
|
||||
|
||||
impl Track {
|
||||
|
@ -90,4 +90,31 @@ impl Track {
|
|||
tidal_id: track.tidal_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_artists(track: Tracks) -> Result<TracksWithArtists, Error> {
|
||||
let artists = track.get_artists()?;
|
||||
|
||||
Ok(TracksWithArtists {
|
||||
id: track.id,
|
||||
title: track.title,
|
||||
duration_ms: track.duration_ms,
|
||||
|
||||
artists,
|
||||
|
||||
spotify_id: track.spotify_id,
|
||||
tidal_id: track.tidal_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct TracksWithArtists {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
pub duration_ms: i32,
|
||||
|
||||
pub artists: Vec<Artists>,
|
||||
|
||||
pub spotify_id: Option<String>,
|
||||
pub tidal_id: Option<String>,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::helpers::db;
|
||||
use crate::schema::users;
|
||||
use bcrypt::BcryptError;
|
||||
use chrono::NaiveDateTime;
|
||||
use diesel::result::Error;
|
||||
use diesel::{
|
||||
|
@ -54,8 +55,8 @@ impl Users {
|
|||
Ok(user)
|
||||
}
|
||||
|
||||
pub fn verify_password(password: &str, user: &Users) -> bool {
|
||||
bcrypt::verify(password, &user.password).unwrap()
|
||||
pub fn verify_password(password: &str, hash: &str) -> Result<bool, BcryptError> {
|
||||
bcrypt::verify(password, hash)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +1,53 @@
|
|||
use crate::helpers::jwt::get_encoding_key;
|
||||
use crate::middlewares::error::ErrorResponse;
|
||||
use crate::models::user::Users;
|
||||
use crate::utils::get_jwt_secret;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::{post, web, HttpResponse};
|
||||
use jwt::SignWithKey;
|
||||
use chrono::{Days, Utc};
|
||||
use jsonwebtoken::{encode, Header};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct JWTClaims {
|
||||
pub user_id: String,
|
||||
pub exp: usize,
|
||||
}
|
||||
|
||||
#[post("/auth/login")]
|
||||
async fn login(body: web::Json<LoginBody>) -> Result<HttpResponse, ErrorResponse> {
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct Response {
|
||||
access_token: String,
|
||||
exp: usize,
|
||||
}
|
||||
|
||||
let user = Users::find_by_email(&body.email);
|
||||
match user {
|
||||
Ok(user) => {
|
||||
let password = Users::verify_password(&body.password, &user);
|
||||
Ok(user) => match Users::verify_password(&body.password, &user.password) {
|
||||
Ok(_res) => {
|
||||
let exp = Utc::now()
|
||||
.checked_add_days(Days::new(30))
|
||||
.expect("valid timestamp")
|
||||
.timestamp();
|
||||
|
||||
if password == false {
|
||||
let claims = JWTClaims {
|
||||
user_id: user.id.to_string(),
|
||||
exp: exp as usize,
|
||||
};
|
||||
let token = encode(&Header::default(), &claims, &get_encoding_key()).unwrap();
|
||||
|
||||
Ok(HttpResponse::Ok().json(Response {
|
||||
access_token: token,
|
||||
exp: exp as usize,
|
||||
}))
|
||||
}
|
||||
Err(_e) => {
|
||||
return Err(ErrorResponse {
|
||||
message: "Invalid credentials.".to_string(),
|
||||
status: StatusCode::BAD_REQUEST,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
let key = get_jwt_secret().unwrap();
|
||||
let mut claims = BTreeMap::new();
|
||||
claims.insert("user_id", &user.id);
|
||||
let token_str = claims.sign_with_key(&key).unwrap();
|
||||
|
||||
Ok(HttpResponse::Ok().json(Response {
|
||||
access_token: token_str,
|
||||
}))
|
||||
}
|
||||
},
|
||||
Err(_err) => {
|
||||
return Err(ErrorResponse {
|
||||
message: "Invalid credentials.".to_string(),
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
use crate::middlewares::error::ErrorResponse;
|
||||
use crate::middlewares::user::get_user;
|
||||
use crate::models::playlist::Playlists;
|
||||
use actix_web::{get, web, HttpRequest, HttpResponse, Scope};
|
||||
use crate::models::playlists::{NewPlaylist, Playlists};
|
||||
use actix_web::{get, post, web, HttpRequest, HttpResponse, Scope};
|
||||
use serde::Serialize;
|
||||
|
||||
pub fn routes() -> Scope {
|
||||
web::scope("/me").service(me).service(me_playlists)
|
||||
web::scope("/me")
|
||||
.service(me)
|
||||
.service(me_playlists)
|
||||
.service(create_playlist)
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -36,6 +39,20 @@ async fn me_playlists(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
|
|||
}
|
||||
|
||||
Ok(HttpResponse::Ok().json(Response {
|
||||
playlists: Playlists::find_for_user(&user.id)?,
|
||||
playlists: Playlists::find_for_user(&user.id, false)?,
|
||||
}))
|
||||
}
|
||||
|
||||
#[post("/playlists")]
|
||||
async fn create_playlist(
|
||||
req: HttpRequest,
|
||||
mut playlist: web::Json<NewPlaylist>,
|
||||
) -> Result<HttpResponse, ErrorResponse> {
|
||||
let user = get_user(req)?;
|
||||
|
||||
playlist.creator_id = Option::from(user.id);
|
||||
|
||||
Playlists::create(playlist.into_inner())?;
|
||||
|
||||
Ok(HttpResponse::Accepted().finish())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::middlewares::error::ErrorResponse;
|
||||
use crate::models::playlist::{PlaylistCreator, Playlists};
|
||||
use crate::models::tracks::Tracks;
|
||||
use crate::models::playlists::{PlaylistCreator, Playlists};
|
||||
use crate::models::tracks::TracksWithArtists;
|
||||
use actix_web::{get, web, HttpResponse};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -9,7 +9,9 @@ struct GetPlaylistResponse {
|
|||
pub id: String,
|
||||
pub name: String,
|
||||
pub creator: PlaylistCreator,
|
||||
pub tracks: Vec<Tracks>,
|
||||
pub tracks: Vec<TracksWithArtists>,
|
||||
pub tracks_count: usize,
|
||||
pub duration: usize,
|
||||
}
|
||||
|
||||
#[get("/{playlist_id}")]
|
||||
|
@ -19,6 +21,14 @@ pub async fn get_playlist(path: web::Path<String>) -> Result<HttpResponse, Error
|
|||
|
||||
let creator = playlist.get_creator()?;
|
||||
|
||||
let tracks = playlist.get_tracks()?;
|
||||
let tracks_count = tracks.len();
|
||||
let duration = tracks
|
||||
.iter()
|
||||
.map(|track| track.duration_ms)
|
||||
.reduce(|a, b| a + b)
|
||||
.unwrap() as usize;
|
||||
|
||||
Ok(HttpResponse::Ok().json(GetPlaylistResponse {
|
||||
id: playlist.id.to_string(),
|
||||
name: playlist.name.to_string(),
|
||||
|
@ -26,6 +36,8 @@ pub async fn get_playlist(path: web::Path<String>) -> Result<HttpResponse, Error
|
|||
id: creator.id,
|
||||
name: creator.name,
|
||||
},
|
||||
tracks: playlist.get_tracks()?,
|
||||
tracks,
|
||||
tracks_count,
|
||||
duration,
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
use crate::middlewares::error::ErrorResponse;
|
||||
use crate::models::playlists::Playlists;
|
||||
use crate::models::user::Users;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::{get, web, HttpResponse, Result};
|
||||
use actix_web::{get, web, HttpResponse, Result, Scope};
|
||||
use diesel::result::Error as DBError;
|
||||
use serde::Serialize;
|
||||
|
||||
pub fn routes() -> Scope {
|
||||
web::scope("/users")
|
||||
.service(get_user)
|
||||
.service(get_user_playlists)
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct GetUserResponse {
|
||||
id: String,
|
||||
name: String,
|
||||
cover: String,
|
||||
}
|
||||
|
||||
#[get("/{user_id}")]
|
||||
async fn get_user(path: web::Path<String>) -> Result<HttpResponse, ErrorResponse> {
|
||||
let user_id = path.into_inner();
|
||||
|
||||
let user = Users::find(user_id.as_str());
|
||||
fn get_a_user(user_id: &str) -> Result<Users, ErrorResponse> {
|
||||
let user = Users::find(user_id);
|
||||
|
||||
match user {
|
||||
Ok(user) => Ok(HttpResponse::Ok().json(GetUserResponse {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
})),
|
||||
Ok(user) => Ok(user),
|
||||
Err(DBError::NotFound) => {
|
||||
return Err(ErrorResponse {
|
||||
message: "User not found".to_string(),
|
||||
|
@ -36,3 +38,24 @@ async fn get_user(path: web::Path<String>) -> Result<HttpResponse, ErrorResponse
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/{user_id}")]
|
||||
async fn get_user(path: web::Path<String>) -> Result<HttpResponse, ErrorResponse> {
|
||||
let user = get_a_user(&path.into_inner())?;
|
||||
let user_id = &user.id;
|
||||
|
||||
Ok(HttpResponse::Ok().json(GetUserResponse {
|
||||
id: user_id.to_string(),
|
||||
name: user.name,
|
||||
cover: format!("https://assets.vybr.net/users/{}.png", user_id),
|
||||
}))
|
||||
}
|
||||
|
||||
#[get("/{user_id}/playlists")]
|
||||
async fn get_user_playlists(path: web::Path<String>) -> Result<HttpResponse, ErrorResponse> {
|
||||
let user = get_a_user(&path.into_inner())?;
|
||||
|
||||
let playlists = Playlists::find_for_user(&user.id, true)?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(playlists))
|
||||
}
|
||||
|
|
|
@ -1,11 +1,36 @@
|
|||
// @generated automatically by Diesel CLI.
|
||||
|
||||
diesel::table! {
|
||||
artists (id) {
|
||||
#[max_length = 24]
|
||||
id -> Varchar,
|
||||
#[max_length = 255]
|
||||
name -> Varchar,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Nullable<Timestamp>,
|
||||
#[max_length = 21]
|
||||
spotify_id -> Nullable<Varchar>,
|
||||
#[max_length = 10]
|
||||
tidal_id -> Nullable<Varchar>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
artists_tracks (artist_id, track_id) {
|
||||
#[max_length = 24]
|
||||
artist_id -> Varchar,
|
||||
#[max_length = 24]
|
||||
track_id -> Varchar,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
playlists (id) {
|
||||
#[max_length = 24]
|
||||
id -> Varchar,
|
||||
#[max_length = 255]
|
||||
name -> Varchar,
|
||||
public -> Bool,
|
||||
#[max_length = 24]
|
||||
creator_id -> Varchar,
|
||||
created_at -> Timestamp,
|
||||
|
@ -52,11 +77,15 @@ diesel::table! {
|
|||
}
|
||||
}
|
||||
|
||||
diesel::joinable!(artists_tracks -> artists (artist_id));
|
||||
diesel::joinable!(artists_tracks -> tracks (track_id));
|
||||
diesel::joinable!(playlists -> users (creator_id));
|
||||
diesel::joinable!(playlists_tracks -> playlists (playlist_id));
|
||||
diesel::joinable!(playlists_tracks -> tracks (track_id));
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
artists,
|
||||
artists_tracks,
|
||||
playlists,
|
||||
playlists_tracks,
|
||||
tracks,
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
use hmac::{Hmac, Mac};
|
||||
use sha2::Sha256;
|
||||
use std::error::Error;
|
||||
|
||||
pub fn get_jwt_secret() -> Result<Hmac<Sha256>, Box<dyn Error>> {
|
||||
let key: Hmac<Sha256> = Hmac::new_from_slice(b"secret")?;
|
||||
Ok(key)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue