Error cleanup
This commit is contained in:
parent
f609afc5ed
commit
4ec8f2161b
5 changed files with 105 additions and 71 deletions
|
@ -1,16 +1,19 @@
|
||||||
use anyhow::bail;
|
|
||||||
use diesel::dsl::sql;
|
use diesel::dsl::sql;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use diesel::sql_types;
|
use diesel::sql_types;
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::db::{self, directories, songs};
|
use crate::db::{self, directories, songs};
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum QueryError {
|
pub enum QueryError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Database(#[from] diesel::result::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
DatabaseConnection(#[from] db::Error),
|
DatabaseConnection(#[from] db::Error),
|
||||||
|
#[error("Song was not found: `{0}`")]
|
||||||
|
SongNotFound(PathBuf),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Vfs(#[from] vfs::Error),
|
Vfs(#[from] vfs::Error),
|
||||||
#[error("Unspecified")]
|
#[error("Unspecified")]
|
||||||
|
@ -178,7 +181,7 @@ impl Index {
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_song(&self, virtual_path: &Path) -> anyhow::Result<Song> {
|
pub fn get_song(&self, virtual_path: &Path) -> Result<Song, QueryError> {
|
||||||
let vfs = self.vfs_manager.get_vfs()?;
|
let vfs = self.vfs_manager.get_vfs()?;
|
||||||
let mut connection = self.db.connect()?;
|
let mut connection = self.db.connect()?;
|
||||||
|
|
||||||
|
@ -192,7 +195,7 @@ impl Index {
|
||||||
|
|
||||||
match real_song.virtualize(&vfs) {
|
match real_song.virtualize(&vfs) {
|
||||||
Some(s) => Ok(s),
|
Some(s) => Ok(s),
|
||||||
_ => bail!("Missing VFS mapping"),
|
None => Err(QueryError::SongNotFound(real_path)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,29 @@
|
||||||
use anyhow::*;
|
|
||||||
use rustfm_scrobble::{Scrobble, Scrobbler};
|
use rustfm_scrobble::{Scrobble, Scrobbler};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use user::AuthToken;
|
use user::AuthToken;
|
||||||
|
|
||||||
use crate::app::{index::Index, user};
|
use crate::app::{
|
||||||
|
index::{Index, QueryError},
|
||||||
|
user,
|
||||||
|
};
|
||||||
|
|
||||||
const LASTFM_API_KEY: &str = "02b96c939a2b451c31dfd67add1f696e";
|
const LASTFM_API_KEY: &str = "02b96c939a2b451c31dfd67add1f696e";
|
||||||
const LASTFM_API_SECRET: &str = "0f25a80ceef4b470b5cb97d99d4b3420";
|
const LASTFM_API_SECRET: &str = "0f25a80ceef4b470b5cb97d99d4b3420";
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Failed to authenticate with last.fm")]
|
||||||
|
ScrobblerAuthentication(rustfm_scrobble::ScrobblerError),
|
||||||
|
#[error("Failed to emit last.fm scrobble")]
|
||||||
|
Scrobble(rustfm_scrobble::ScrobblerError),
|
||||||
|
#[error("Failed to emit last.fm now playing update")]
|
||||||
|
NowPlaying(rustfm_scrobble::ScrobblerError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Query(#[from] QueryError),
|
||||||
|
#[error(transparent)]
|
||||||
|
User(#[from] user::Error),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Manager {
|
pub struct Manager {
|
||||||
index: Index,
|
index: Index,
|
||||||
|
@ -22,44 +38,50 @@ impl Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_link_token(&self, username: &str) -> Result<AuthToken> {
|
pub fn generate_link_token(&self, username: &str) -> Result<AuthToken, Error> {
|
||||||
self.user_manager
|
self.user_manager
|
||||||
.generate_lastfm_link_token(username)
|
.generate_lastfm_link_token(username)
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn link(&self, username: &str, lastfm_token: &str) -> Result<()> {
|
pub fn link(&self, username: &str, lastfm_token: &str) -> Result<(), Error> {
|
||||||
let mut scrobbler = Scrobbler::new(LASTFM_API_KEY, LASTFM_API_SECRET);
|
let mut scrobbler = Scrobbler::new(LASTFM_API_KEY, LASTFM_API_SECRET);
|
||||||
let auth_response = scrobbler.authenticate_with_token(lastfm_token)?;
|
let auth_response = scrobbler
|
||||||
|
.authenticate_with_token(lastfm_token)
|
||||||
|
.map_err(Error::ScrobblerAuthentication)?;
|
||||||
|
|
||||||
self.user_manager
|
self.user_manager
|
||||||
.lastfm_link(username, &auth_response.name, &auth_response.key)
|
.lastfm_link(username, &auth_response.name, &auth_response.key)
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unlink(&self, username: &str) -> Result<()> {
|
pub fn unlink(&self, username: &str) -> Result<(), Error> {
|
||||||
self.user_manager.lastfm_unlink(username)
|
self.user_manager
|
||||||
|
.lastfm_unlink(username)
|
||||||
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scrobble(&self, username: &str, track: &Path) -> Result<()> {
|
pub fn scrobble(&self, username: &str, track: &Path) -> Result<(), Error> {
|
||||||
let mut scrobbler = Scrobbler::new(LASTFM_API_KEY, LASTFM_API_SECRET);
|
let mut scrobbler = Scrobbler::new(LASTFM_API_KEY, LASTFM_API_SECRET);
|
||||||
let scrobble = self.scrobble_from_path(track)?;
|
let scrobble = self.scrobble_from_path(track)?;
|
||||||
let auth_token = self.user_manager.get_lastfm_session_key(username)?;
|
let auth_token = self.user_manager.get_lastfm_session_key(username)?;
|
||||||
scrobbler.authenticate_with_session_key(&auth_token);
|
scrobbler.authenticate_with_session_key(&auth_token);
|
||||||
scrobbler.scrobble(&scrobble)?;
|
scrobbler.scrobble(&scrobble).map_err(Error::Scrobble)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn now_playing(&self, username: &str, track: &Path) -> Result<()> {
|
pub fn now_playing(&self, username: &str, track: &Path) -> Result<(), Error> {
|
||||||
let mut scrobbler = Scrobbler::new(LASTFM_API_KEY, LASTFM_API_SECRET);
|
let mut scrobbler = Scrobbler::new(LASTFM_API_KEY, LASTFM_API_SECRET);
|
||||||
let scrobble = self.scrobble_from_path(track)?;
|
let scrobble = self.scrobble_from_path(track)?;
|
||||||
let auth_token = self.user_manager.get_lastfm_session_key(username)?;
|
let auth_token = self.user_manager.get_lastfm_session_key(username)?;
|
||||||
scrobbler.authenticate_with_session_key(&auth_token);
|
scrobbler.authenticate_with_session_key(&auth_token);
|
||||||
scrobbler.now_playing(&scrobble)?;
|
scrobbler
|
||||||
|
.now_playing(&scrobble)
|
||||||
|
.map_err(Error::NowPlaying)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scrobble_from_path(&self, track: &Path) -> Result<Scrobble> {
|
fn scrobble_from_path(&self, track: &Path) -> Result<Scrobble, Error> {
|
||||||
let song = self.index.get_song(track)?;
|
let song = self.index.get_song(track)?;
|
||||||
Ok(Scrobble::new(
|
Ok(Scrobble::new(
|
||||||
song.artist.as_deref().unwrap_or(""),
|
song.artist.as_deref().unwrap_or(""),
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use anyhow::anyhow;
|
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use pbkdf2::password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString};
|
use pbkdf2::password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString};
|
||||||
use pbkdf2::Pbkdf2;
|
use pbkdf2::Pbkdf2;
|
||||||
|
@ -11,6 +10,8 @@ use crate::db::{self, users, DB};
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
Database(#[from] diesel::result::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
DatabaseConnection(#[from] db::Error),
|
DatabaseConnection(#[from] db::Error),
|
||||||
#[error("Cannot use empty username")]
|
#[error("Cannot use empty username")]
|
||||||
|
@ -25,14 +26,14 @@ pub enum Error {
|
||||||
InvalidAuthToken,
|
InvalidAuthToken,
|
||||||
#[error("Incorrect authorization scope")]
|
#[error("Incorrect authorization scope")]
|
||||||
IncorrectAuthorizationScope,
|
IncorrectAuthorizationScope,
|
||||||
#[error("Unspecified")]
|
#[error("Last.fm session key is missing")]
|
||||||
Unspecified,
|
MissingLastFMSessionKey,
|
||||||
}
|
#[error("Failed to hash password")]
|
||||||
|
PasswordHashing,
|
||||||
impl From<anyhow::Error> for Error {
|
#[error("Failed to encode authorization token")]
|
||||||
fn from(_: anyhow::Error) -> Self {
|
AuthorizationTokenEncoding,
|
||||||
Error::Unspecified
|
#[error("Failed to encode Branca token")]
|
||||||
}
|
BrancaTokenEncoding,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Insertable, Queryable)]
|
#[derive(Debug, Insertable, Queryable)]
|
||||||
|
@ -104,17 +105,14 @@ impl Manager {
|
||||||
|
|
||||||
diesel::insert_into(users::table)
|
diesel::insert_into(users::table)
|
||||||
.values(&new_user)
|
.values(&new_user)
|
||||||
.execute(&mut connection)
|
.execute(&mut connection)?;
|
||||||
.map_err(|_| Error::Unspecified)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(&self, username: &str) -> Result<(), Error> {
|
pub fn delete(&self, username: &str) -> Result<(), Error> {
|
||||||
use crate::db::users::dsl::*;
|
use crate::db::users::dsl::*;
|
||||||
let mut connection = self.db.connect()?;
|
let mut connection = self.db.connect()?;
|
||||||
diesel::delete(users.filter(name.eq(username)))
|
diesel::delete(users.filter(name.eq(username))).execute(&mut connection)?;
|
||||||
.execute(&mut connection)
|
|
||||||
.map_err(|_| Error::Unspecified)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,8 +122,7 @@ impl Manager {
|
||||||
use crate::db::users::dsl::*;
|
use crate::db::users::dsl::*;
|
||||||
diesel::update(users.filter(name.eq(username)))
|
diesel::update(users.filter(name.eq(username)))
|
||||||
.set(password_hash.eq(hash))
|
.set(password_hash.eq(hash))
|
||||||
.execute(&mut connection)
|
.execute(&mut connection)?;
|
||||||
.map_err(|_| Error::Unspecified)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,8 +131,7 @@ impl Manager {
|
||||||
let mut connection = self.db.connect()?;
|
let mut connection = self.db.connect()?;
|
||||||
diesel::update(users.filter(name.eq(username)))
|
diesel::update(users.filter(name.eq(username)))
|
||||||
.set(admin.eq(is_admin as i32))
|
.set(admin.eq(is_admin as i32))
|
||||||
.execute(&mut connection)
|
.execute(&mut connection)?;
|
||||||
.map_err(|_| Error::Unspecified)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +156,7 @@ impl Manager {
|
||||||
Err(Error::IncorrectPassword)
|
Err(Error::IncorrectPassword)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => Err(Error::Unspecified),
|
Err(e) => Err(e.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,16 +195,16 @@ impl Manager {
|
||||||
|
|
||||||
fn generate_auth_token(&self, authorization: &Authorization) -> Result<AuthToken, Error> {
|
fn generate_auth_token(&self, authorization: &Authorization) -> Result<AuthToken, Error> {
|
||||||
let serialized_authorization =
|
let serialized_authorization =
|
||||||
serde_json::to_string(&authorization).map_err(|_| Error::Unspecified)?;
|
serde_json::to_string(&authorization).or(Err(Error::AuthorizationTokenEncoding))?;
|
||||||
branca::encode(
|
branca::encode(
|
||||||
serialized_authorization.as_bytes(),
|
serialized_authorization.as_bytes(),
|
||||||
&self.auth_secret.key,
|
&self.auth_secret.key,
|
||||||
SystemTime::now()
|
SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
.map_err(|_| Error::Unspecified)?
|
.unwrap_or_default()
|
||||||
.as_secs() as u32,
|
.as_secs() as u32,
|
||||||
)
|
)
|
||||||
.map_err(|_| Error::Unspecified)
|
.or(Err(Error::BrancaTokenEncoding))
|
||||||
.map(AuthToken)
|
.map(AuthToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,10 +218,10 @@ impl Manager {
|
||||||
pub fn list(&self) -> Result<Vec<User>, Error> {
|
pub fn list(&self) -> Result<Vec<User>, Error> {
|
||||||
use crate::db::users::dsl::*;
|
use crate::db::users::dsl::*;
|
||||||
let mut connection = self.db.connect()?;
|
let mut connection = self.db.connect()?;
|
||||||
users
|
let listed_users = users
|
||||||
.select((name, password_hash, admin))
|
.select((name, password_hash, admin))
|
||||||
.get_results(&mut connection)
|
.get_results(&mut connection)?;
|
||||||
.map_err(|_| Error::Unspecified)
|
Ok(listed_users)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exists(&self, username: &str) -> Result<bool, Error> {
|
pub fn exists(&self, username: &str) -> Result<bool, Error> {
|
||||||
|
@ -234,8 +230,7 @@ impl Manager {
|
||||||
let results: Vec<String> = users
|
let results: Vec<String> = users
|
||||||
.select(name)
|
.select(name)
|
||||||
.filter(name.eq(username))
|
.filter(name.eq(username))
|
||||||
.get_results(&mut connection)
|
.get_results(&mut connection)?;
|
||||||
.map_err(|_| Error::Unspecified)?;
|
|
||||||
Ok(!results.is_empty())
|
Ok(!results.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,8 +240,7 @@ impl Manager {
|
||||||
let is_admin: i32 = users
|
let is_admin: i32 = users
|
||||||
.filter(name.eq(username))
|
.filter(name.eq(username))
|
||||||
.select(admin)
|
.select(admin)
|
||||||
.get_result(&mut connection)
|
.get_result(&mut connection)?;
|
||||||
.map_err(|_| Error::Unspecified)?;
|
|
||||||
Ok(is_admin != 0)
|
Ok(is_admin != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,8 +250,7 @@ impl Manager {
|
||||||
let (theme_base, theme_accent, read_lastfm_username) = users
|
let (theme_base, theme_accent, read_lastfm_username) = users
|
||||||
.select((web_theme_base, web_theme_accent, lastfm_username))
|
.select((web_theme_base, web_theme_accent, lastfm_username))
|
||||||
.filter(name.eq(username))
|
.filter(name.eq(username))
|
||||||
.get_result(&mut connection)
|
.get_result(&mut connection)?;
|
||||||
.map_err(|_| Error::Unspecified)?;
|
|
||||||
Ok(Preferences {
|
Ok(Preferences {
|
||||||
web_theme_base: theme_base,
|
web_theme_base: theme_base,
|
||||||
web_theme_accent: theme_accent,
|
web_theme_accent: theme_accent,
|
||||||
|
@ -277,8 +270,7 @@ impl Manager {
|
||||||
web_theme_base.eq(&preferences.web_theme_base),
|
web_theme_base.eq(&preferences.web_theme_base),
|
||||||
web_theme_accent.eq(&preferences.web_theme_accent),
|
web_theme_accent.eq(&preferences.web_theme_accent),
|
||||||
))
|
))
|
||||||
.execute(&mut connection)
|
.execute(&mut connection)?;
|
||||||
.map_err(|_| Error::Unspecified)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,8 +287,7 @@ impl Manager {
|
||||||
lastfm_username.eq(lastfm_login),
|
lastfm_username.eq(lastfm_login),
|
||||||
lastfm_session_key.eq(session_key),
|
lastfm_session_key.eq(session_key),
|
||||||
))
|
))
|
||||||
.execute(&mut connection)
|
.execute(&mut connection)?;
|
||||||
.map_err(|_| Error::Unspecified)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,24 +298,21 @@ impl Manager {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_lastfm_session_key(&self, username: &str) -> anyhow::Result<String> {
|
pub fn get_lastfm_session_key(&self, username: &str) -> Result<String, Error> {
|
||||||
use crate::db::users::dsl::*;
|
use crate::db::users::dsl::*;
|
||||||
let mut connection = self.db.connect()?;
|
let mut connection = self.db.connect()?;
|
||||||
let token = users
|
let token: Option<String> = users
|
||||||
.filter(name.eq(username))
|
.filter(name.eq(username))
|
||||||
.select(lastfm_session_key)
|
.select(lastfm_session_key)
|
||||||
.get_result(&mut connection)?;
|
.get_result(&mut connection)?;
|
||||||
match token {
|
token.ok_or(Error::MissingLastFMSessionKey)
|
||||||
Some(t) => Ok(t),
|
|
||||||
_ => Err(anyhow!("Missing LastFM credentials")),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_lastfm_linked(&self, username: &str) -> bool {
|
pub fn is_lastfm_linked(&self, username: &str) -> bool {
|
||||||
self.get_lastfm_session_key(username).is_ok()
|
self.get_lastfm_session_key(username).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lastfm_unlink(&self, username: &str) -> anyhow::Result<()> {
|
pub fn lastfm_unlink(&self, username: &str) -> Result<(), Error> {
|
||||||
use crate::db::users::dsl::*;
|
use crate::db::users::dsl::*;
|
||||||
let mut connection = self.db.connect()?;
|
let mut connection = self.db.connect()?;
|
||||||
let null: Option<String> = None;
|
let null: Option<String> = None;
|
||||||
|
@ -342,7 +330,7 @@ fn hash_password(password: &str) -> Result<String, Error> {
|
||||||
let salt = SaltString::generate(&mut OsRng);
|
let salt = SaltString::generate(&mut OsRng);
|
||||||
match Pbkdf2.hash_password(password.as_bytes(), &salt) {
|
match Pbkdf2.hash_password(password.as_bytes(), &salt) {
|
||||||
Ok(h) => Ok(h.to_string()),
|
Ok(h) => Ok(h.to_string()),
|
||||||
Err(_) => Err(Error::Unspecified),
|
Err(_) => Err(Error::PasswordHashing),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,22 +73,23 @@ pub fn make_config() -> impl FnOnce(&mut ServiceConfig) + Clone {
|
||||||
impl ResponseError for APIError {
|
impl ResponseError for APIError {
|
||||||
fn status_code(&self) -> StatusCode {
|
fn status_code(&self) -> StatusCode {
|
||||||
match self {
|
match self {
|
||||||
APIError::AuthenticationRequired => StatusCode::UNAUTHORIZED,
|
|
||||||
APIError::IncorrectCredentials => StatusCode::UNAUTHORIZED,
|
|
||||||
APIError::EmptyUsername => StatusCode::BAD_REQUEST,
|
|
||||||
APIError::EmptyPassword => StatusCode::BAD_REQUEST,
|
|
||||||
APIError::DeletingOwnAccount => StatusCode::CONFLICT,
|
|
||||||
APIError::OwnAdminPrivilegeRemoval => StatusCode::CONFLICT,
|
|
||||||
APIError::AudioFileIOError => StatusCode::NOT_FOUND,
|
APIError::AudioFileIOError => StatusCode::NOT_FOUND,
|
||||||
APIError::ThumbnailFileIOError => StatusCode::NOT_FOUND,
|
APIError::AuthenticationRequired => StatusCode::UNAUTHORIZED,
|
||||||
|
APIError::DeletingOwnAccount => StatusCode::CONFLICT,
|
||||||
|
APIError::EmptyPassword => StatusCode::BAD_REQUEST,
|
||||||
|
APIError::EmptyUsername => StatusCode::BAD_REQUEST,
|
||||||
|
APIError::IncorrectCredentials => StatusCode::UNAUTHORIZED,
|
||||||
|
APIError::Internal => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
APIError::LastFMAccountNotLinked => StatusCode::NO_CONTENT,
|
APIError::LastFMAccountNotLinked => StatusCode::NO_CONTENT,
|
||||||
APIError::LastFMLinkContentBase64DecodeError => StatusCode::BAD_REQUEST,
|
APIError::LastFMLinkContentBase64DecodeError => StatusCode::BAD_REQUEST,
|
||||||
APIError::LastFMLinkContentEncodingError => StatusCode::BAD_REQUEST,
|
APIError::LastFMLinkContentEncodingError => StatusCode::BAD_REQUEST,
|
||||||
APIError::UserNotFound => StatusCode::NOT_FOUND,
|
APIError::OwnAdminPrivilegeRemoval => StatusCode::CONFLICT,
|
||||||
APIError::PlaylistNotFound => StatusCode::NOT_FOUND,
|
APIError::PlaylistNotFound => StatusCode::NOT_FOUND,
|
||||||
APIError::VFSPathNotFound => StatusCode::NOT_FOUND,
|
APIError::SongMetadataNotFound => StatusCode::NOT_FOUND,
|
||||||
APIError::Internal => StatusCode::INTERNAL_SERVER_ERROR,
|
APIError::ThumbnailFileIOError => StatusCode::NOT_FOUND,
|
||||||
APIError::Unspecified => StatusCode::INTERNAL_SERVER_ERROR,
|
APIError::Unspecified => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
APIError::UserNotFound => StatusCode::NOT_FOUND,
|
||||||
|
APIError::VFSPathNotFound => StatusCode::NOT_FOUND,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::app::index::QueryError;
|
use crate::app::index::QueryError;
|
||||||
use crate::app::{config, ddns, playlist, settings, user, vfs};
|
use crate::app::{config, ddns, lastfm, playlist, settings, user, vfs};
|
||||||
use crate::db;
|
use crate::db;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
@ -34,6 +34,8 @@ pub enum APIError {
|
||||||
UserNotFound,
|
UserNotFound,
|
||||||
#[error("Playlist not found")]
|
#[error("Playlist not found")]
|
||||||
PlaylistNotFound,
|
PlaylistNotFound,
|
||||||
|
#[error("Song not found")]
|
||||||
|
SongMetadataNotFound,
|
||||||
#[error("Internal server error")]
|
#[error("Internal server error")]
|
||||||
Internal,
|
Internal,
|
||||||
#[error("Unspecified")]
|
#[error("Unspecified")]
|
||||||
|
@ -72,7 +74,9 @@ impl From<playlist::Error> for APIError {
|
||||||
impl From<QueryError> for APIError {
|
impl From<QueryError> for APIError {
|
||||||
fn from(error: QueryError) -> APIError {
|
fn from(error: QueryError) -> APIError {
|
||||||
match error {
|
match error {
|
||||||
|
QueryError::Database(_) => APIError::Internal,
|
||||||
QueryError::DatabaseConnection(e) => e.into(),
|
QueryError::DatabaseConnection(e) => e.into(),
|
||||||
|
QueryError::SongNotFound(_) => APIError::SongMetadataNotFound,
|
||||||
QueryError::Vfs(e) => e.into(),
|
QueryError::Vfs(e) => e.into(),
|
||||||
QueryError::Unspecified => APIError::Unspecified,
|
QueryError::Unspecified => APIError::Unspecified,
|
||||||
}
|
}
|
||||||
|
@ -96,6 +100,9 @@ impl From<settings::Error> for APIError {
|
||||||
impl From<user::Error> for APIError {
|
impl From<user::Error> for APIError {
|
||||||
fn from(error: user::Error) -> APIError {
|
fn from(error: user::Error) -> APIError {
|
||||||
match error {
|
match error {
|
||||||
|
user::Error::AuthorizationTokenEncoding => APIError::Internal,
|
||||||
|
user::Error::BrancaTokenEncoding => APIError::Internal,
|
||||||
|
user::Error::Database(_) => APIError::Internal,
|
||||||
user::Error::DatabaseConnection(e) => e.into(),
|
user::Error::DatabaseConnection(e) => e.into(),
|
||||||
user::Error::EmptyUsername => APIError::EmptyUsername,
|
user::Error::EmptyUsername => APIError::EmptyUsername,
|
||||||
user::Error::EmptyPassword => APIError::EmptyPassword,
|
user::Error::EmptyPassword => APIError::EmptyPassword,
|
||||||
|
@ -103,7 +110,8 @@ impl From<user::Error> for APIError {
|
||||||
user::Error::IncorrectPassword => APIError::IncorrectCredentials,
|
user::Error::IncorrectPassword => APIError::IncorrectCredentials,
|
||||||
user::Error::InvalidAuthToken => APIError::IncorrectCredentials,
|
user::Error::InvalidAuthToken => APIError::IncorrectCredentials,
|
||||||
user::Error::IncorrectAuthorizationScope => APIError::IncorrectCredentials,
|
user::Error::IncorrectAuthorizationScope => APIError::IncorrectCredentials,
|
||||||
user::Error::Unspecified => APIError::Unspecified,
|
user::Error::PasswordHashing => APIError::Internal,
|
||||||
|
user::Error::MissingLastFMSessionKey => APIError::IncorrectCredentials,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,3 +149,15 @@ impl From<db::Error> for APIError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<lastfm::Error> for APIError {
|
||||||
|
fn from(error: lastfm::Error) -> APIError {
|
||||||
|
match error {
|
||||||
|
lastfm::Error::ScrobblerAuthentication(_) => APIError::Internal,
|
||||||
|
lastfm::Error::Scrobble(_) => APIError::Internal,
|
||||||
|
lastfm::Error::NowPlaying(_) => APIError::Internal,
|
||||||
|
lastfm::Error::Query(e) => e.into(),
|
||||||
|
lastfm::Error::User(e) => e.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue