Config refactor continued
This commit is contained in:
parent
c7a760e2c2
commit
ae5da0f4f3
9 changed files with 103 additions and 63 deletions
|
@ -5,12 +5,13 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::app::Error;
|
use crate::app::Error;
|
||||||
|
|
||||||
mod mounts;
|
mod mounts;
|
||||||
mod raw;
|
pub mod storage;
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
pub use mounts::*;
|
pub use mounts::*;
|
||||||
|
@ -27,27 +28,27 @@ pub struct Config {
|
||||||
pub users: HashMap<String, User>,
|
pub users: HashMap<String, User>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<raw::Config> for Config {
|
impl TryFrom<storage::Config> for Config {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(raw: raw::Config) -> Result<Self, Self::Error> {
|
fn try_from(c: storage::Config) -> Result<Self, Self::Error> {
|
||||||
let mut users: HashMap<String, User> = HashMap::new();
|
let mut users: HashMap<String, User> = HashMap::new();
|
||||||
for user in raw.users {
|
for user in c.users {
|
||||||
if let Ok(user) = <raw::User as TryInto<User>>::try_into(user) {
|
if let Ok(user) = <storage::User as TryInto<User>>::try_into(user) {
|
||||||
users.insert(user.name.clone(), user);
|
users.insert(user.name.clone(), user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mount_dirs = raw
|
let mount_dirs = c
|
||||||
.mount_dirs
|
.mount_dirs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|m| m.try_into().ok())
|
.filter_map(|m| m.try_into().ok())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(Config {
|
Ok(Config {
|
||||||
reindex_every_n_seconds: raw.reindex_every_n_seconds, // TODO validate and warn
|
reindex_every_n_seconds: c.reindex_every_n_seconds, // TODO validate and warn
|
||||||
album_art_pattern: raw.album_art_pattern, // TODO validate and warn
|
album_art_pattern: c.album_art_pattern, // TODO validate and warn
|
||||||
ddns_url: raw.ddns_url, // TODO validate and warn
|
ddns_url: c.ddns_url, // TODO validate and warn
|
||||||
mount_dirs,
|
mount_dirs,
|
||||||
users,
|
users,
|
||||||
})
|
})
|
||||||
|
@ -63,8 +64,8 @@ pub struct Manager {
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
pub async fn new(config_file_path: &Path, auth_secret: auth::Secret) -> Result<Self, Error> {
|
pub async fn new(config_file_path: &Path, auth_secret: auth::Secret) -> Result<Self, Error> {
|
||||||
let raw_config = raw::Config::default(); // TODO read from disk!!
|
let config = storage::Config::default(); // TODO read from disk!!
|
||||||
let config = raw_config.try_into()?;
|
let config: Config = config.try_into()?;
|
||||||
let manager = Self {
|
let manager = Self {
|
||||||
config_file_path: config_file_path.to_owned(),
|
config_file_path: config_file_path.to_owned(),
|
||||||
config: Arc::new(RwLock::new(config)),
|
config: Arc::new(RwLock::new(config)),
|
||||||
|
@ -73,8 +74,8 @@ impl Manager {
|
||||||
Ok(manager)
|
Ok(manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn apply(&self, raw_config: raw::Config) -> Result<(), Error> {
|
pub async fn apply(&self, config: storage::Config) -> Result<(), Error> {
|
||||||
*self.config.write().await = raw_config.try_into()?;
|
*self.config.write().await = config.try_into()?;
|
||||||
// TODO persistence
|
// TODO persistence
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -85,16 +86,34 @@ impl Manager {
|
||||||
Duration::from_secs(seconds)
|
Duration::from_secs(seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn set_index_sleep_duration(&self, duration: Duration) {
|
||||||
|
let mut config = self.config.write().await;
|
||||||
|
config.reindex_every_n_seconds = Some(duration.as_secs());
|
||||||
|
// TODO persistence
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_index_album_art_pattern(&self) -> String {
|
pub async fn get_index_album_art_pattern(&self) -> String {
|
||||||
let config = self.config.read().await;
|
let config = self.config.read().await;
|
||||||
let pattern = config.album_art_pattern.clone();
|
let pattern = config.album_art_pattern.clone();
|
||||||
pattern.unwrap_or("Folder.(jpeg|jpg|png)".to_owned())
|
pattern.unwrap_or("Folder.(jpeg|jpg|png)".to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn set_index_album_art_pattern(&self, regex: Regex) {
|
||||||
|
let mut config = self.config.write().await;
|
||||||
|
config.album_art_pattern = Some(regex.as_str().to_owned());
|
||||||
|
// TODO persistence
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_ddns_update_url(&self) -> Option<String> {
|
pub async fn get_ddns_update_url(&self) -> Option<String> {
|
||||||
self.config.read().await.ddns_url.clone()
|
self.config.read().await.ddns_url.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn set_ddns_update_url(&self, url: http::Uri) {
|
||||||
|
let mut config = self.config.write().await;
|
||||||
|
config.ddns_url = Some(url.to_string());
|
||||||
|
// TODO persistence
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_users(&self) -> Vec<User> {
|
pub async fn get_users(&self) -> Vec<User> {
|
||||||
self.config.read().await.users.values().cloned().collect()
|
self.config.read().await.users.values().cloned().collect()
|
||||||
}
|
}
|
||||||
|
@ -160,7 +179,7 @@ impl Manager {
|
||||||
config.resolve_virtual_path(virtual_path)
|
config.resolve_virtual_path(virtual_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_mounts(&self, mount_dirs: Vec<raw::MountDir>) {
|
pub async fn set_mounts(&self, mount_dirs: Vec<storage::MountDir>) {
|
||||||
self.config.write().await.set_mounts(mount_dirs);
|
self.config.write().await.set_mounts(mount_dirs);
|
||||||
// TODO persistence
|
// TODO persistence
|
||||||
}
|
}
|
||||||
|
@ -169,18 +188,20 @@ impl Manager {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use super::*;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::app::config::storage::*;
|
||||||
use crate::app::test;
|
use crate::app::test;
|
||||||
use crate::test_name;
|
use crate::test_name;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn can_apply_config() {
|
async fn can_apply_config() {
|
||||||
let ctx = test::ContextBuilder::new(test_name!()).build().await;
|
let ctx = test::ContextBuilder::new(test_name!()).build().await;
|
||||||
let new_config = raw::Config {
|
let new_config = Config {
|
||||||
reindex_every_n_seconds: Some(100),
|
reindex_every_n_seconds: Some(100),
|
||||||
album_art_pattern: Some("cool_pattern".to_owned()),
|
album_art_pattern: Some("cool_pattern".to_owned()),
|
||||||
mount_dirs: vec![raw::MountDir {
|
mount_dirs: vec![MountDir {
|
||||||
source: "/home/music".to_owned(),
|
source: PathBuf::from("/home/music"),
|
||||||
name: "Library".to_owned(),
|
name: "Library".to_owned(),
|
||||||
}],
|
}],
|
||||||
ddns_url: Some("https://cooldns.com".to_owned()),
|
ddns_url: Some("https://cooldns.com".to_owned()),
|
||||||
|
|
|
@ -7,7 +7,7 @@ use regex::Regex;
|
||||||
|
|
||||||
use crate::app::Error;
|
use crate::app::Error;
|
||||||
|
|
||||||
use super::raw;
|
use super::storage;
|
||||||
use super::Config;
|
use super::Config;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
|
@ -16,10 +16,10 @@ pub struct MountDir {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<raw::MountDir> for MountDir {
|
impl TryFrom<storage::MountDir> for MountDir {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(mount_dir: raw::MountDir) -> Result<Self, Self::Error> {
|
fn try_from(mount_dir: storage::MountDir) -> Result<Self, Self::Error> {
|
||||||
// TODO validation
|
// TODO validation
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
source: sanitize_path(&mount_dir.source),
|
source: sanitize_path(&mount_dir.source),
|
||||||
|
@ -29,7 +29,7 @@ impl TryFrom<raw::MountDir> for MountDir {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn set_mounts(&mut self, mount_dirs: Vec<raw::MountDir>) {
|
pub fn set_mounts(&mut self, mount_dirs: Vec<storage::MountDir>) {
|
||||||
self.mount_dirs = mount_dirs
|
self.mount_dirs = mount_dirs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|m| m.try_into().ok())
|
.filter_map(|m| m.try_into().ok())
|
||||||
|
@ -51,11 +51,12 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sanitize_path(source: &str) -> PathBuf {
|
fn sanitize_path(source: &PathBuf) -> PathBuf {
|
||||||
|
let path_string = source.to_string_lossy();
|
||||||
let separator_regex = Regex::new(r"\\|/").unwrap();
|
let separator_regex = Regex::new(r"\\|/").unwrap();
|
||||||
let mut correct_separator = String::new();
|
let mut correct_separator = String::new();
|
||||||
correct_separator.push(std::path::MAIN_SEPARATOR);
|
correct_separator.push(std::path::MAIN_SEPARATOR);
|
||||||
let path_string = separator_regex.replace_all(source, correct_separator.as_str());
|
let path_string = separator_regex.replace_all(&path_string, correct_separator.as_str());
|
||||||
PathBuf::from(path_string.deref())
|
PathBuf::from(path_string.deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,10 +66,10 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_resolve_virtual_paths() {
|
fn can_resolve_virtual_paths() {
|
||||||
let raw_config = raw::Config {
|
let raw_config = storage::Config {
|
||||||
mount_dirs: vec![raw::MountDir {
|
mount_dirs: vec![storage::MountDir {
|
||||||
name: "root".to_owned(),
|
name: "root".to_owned(),
|
||||||
source: "test_dir".to_owned(),
|
source: PathBuf::from("test_dir"),
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
@ -121,10 +122,10 @@ mod test {
|
||||||
};
|
};
|
||||||
|
|
||||||
for test in tests {
|
for test in tests {
|
||||||
let raw_config = raw::Config {
|
let raw_config = storage::Config {
|
||||||
mount_dirs: vec![raw::MountDir {
|
mount_dirs: vec![storage::MountDir {
|
||||||
name: "root".to_owned(),
|
name: "root".to_owned(),
|
||||||
source: test.to_owned(),
|
source: PathBuf::from(test),
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use std::{io::Read, path::Path};
|
use std::{
|
||||||
|
io::Read,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -17,7 +20,7 @@ pub struct User {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct MountDir {
|
pub struct MountDir {
|
||||||
pub source: String,
|
pub source: PathBuf,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::app::{auth, Error};
|
use crate::app::{auth, Error};
|
||||||
|
|
||||||
use super::raw;
|
use super::storage;
|
||||||
use super::Config;
|
use super::Config;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
|
@ -11,10 +11,10 @@ pub struct User {
|
||||||
pub hashed_password: String,
|
pub hashed_password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<raw::User> for User {
|
impl TryFrom<storage::User> for User {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(user: raw::User) -> Result<Self, Self::Error> {
|
fn try_from(user: storage::User) -> Result<Self, Self::Error> {
|
||||||
let hashed_password = match (&user.initial_password, &user.hashed_password) {
|
let hashed_password = match (&user.initial_password, &user.hashed_password) {
|
||||||
(_, Some(p)) => p.clone(),
|
(_, Some(p)) => p.clone(),
|
||||||
(Some(p), None) => auth::hash_password(p)?,
|
(Some(p), None) => auth::hash_password(p)?,
|
||||||
|
@ -36,7 +36,7 @@ impl User {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<User> for raw::User {
|
impl From<User> for storage::User {
|
||||||
fn from(user: User) -> Self {
|
fn from(user: User) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: user.name,
|
name: user.name,
|
||||||
|
@ -137,7 +137,7 @@ mod test {
|
||||||
const TEST_PASSWORD: &str = "super_secret!";
|
const TEST_PASSWORD: &str = "super_secret!";
|
||||||
|
|
||||||
fn adds_password_hashes() {
|
fn adds_password_hashes() {
|
||||||
let user_in = raw::User {
|
let user_in = storage::User {
|
||||||
name: TEST_USERNAME.to_owned(),
|
name: TEST_USERNAME.to_owned(),
|
||||||
initial_password: Some(TEST_PASSWORD.to_owned()),
|
initial_password: Some(TEST_PASSWORD.to_owned()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -145,7 +145,7 @@ mod test {
|
||||||
|
|
||||||
let user: User = user_in.try_into().unwrap();
|
let user: User = user_in.try_into().unwrap();
|
||||||
|
|
||||||
let user_out: raw::User = user.into();
|
let user_out: storage::User = user.into();
|
||||||
|
|
||||||
assert_eq!(user_out.name, TEST_USERNAME);
|
assert_eq!(user_out.name, TEST_USERNAME);
|
||||||
assert_eq!(user_out.initial_password, Some(TEST_PASSWORD.to_owned()));
|
assert_eq!(user_out.initial_password, Some(TEST_PASSWORD.to_owned()));
|
||||||
|
@ -153,13 +153,13 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn preserves_password_hashes() {
|
fn preserves_password_hashes() {
|
||||||
let user_in = raw::User {
|
let user_in = storage::User {
|
||||||
name: TEST_USERNAME.to_owned(),
|
name: TEST_USERNAME.to_owned(),
|
||||||
hashed_password: Some("hash".to_owned()),
|
hashed_password: Some("hash".to_owned()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let user: User = user_in.clone().try_into().unwrap();
|
let user: User = user_in.clone().try_into().unwrap();
|
||||||
let user_out: raw::User = user.into();
|
let user_out: storage::User = user.into();
|
||||||
assert_eq!(user_out, user_in);
|
assert_eq!(user_out, user_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::app::config::storage::*;
|
||||||
use crate::app::{auth, config, index, ndb, playlist, scanner};
|
use crate::app::{auth, config, index, ndb, playlist, scanner};
|
||||||
use crate::test::*;
|
use crate::test::*;
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ pub struct Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ContextBuilder {
|
pub struct ContextBuilder {
|
||||||
config: config::Config,
|
config: Config,
|
||||||
pub test_directory: PathBuf,
|
pub test_directory: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,12 +20,12 @@ impl ContextBuilder {
|
||||||
pub fn new(test_name: String) -> Self {
|
pub fn new(test_name: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
test_directory: prepare_test_directory(test_name),
|
test_directory: prepare_test_directory(test_name),
|
||||||
config: config::Config::default(),
|
config: Config::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn user(mut self, name: &str, password: &str, is_admin: bool) -> Self {
|
pub fn user(mut self, name: &str, password: &str, is_admin: bool) -> Self {
|
||||||
self.config.users.push(config::User {
|
self.config.users.push(User {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
initial_password: Some(password.to_owned()),
|
initial_password: Some(password.to_owned()),
|
||||||
admin: Some(is_admin),
|
admin: Some(is_admin),
|
||||||
|
@ -34,9 +35,9 @@ impl ContextBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mount(mut self, name: &str, source: &str) -> Self {
|
pub fn mount(mut self, name: &str, source: &str) -> Self {
|
||||||
self.config.mount_dirs.push(config::MountDir {
|
self.config.mount_dirs.push(MountDir {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
source: source.to_owned(),
|
source: PathBuf::from(source),
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::path::PathBuf;
|
use std::{path::PathBuf, time::Duration};
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{DefaultBodyLimit, Path, Query, State},
|
extract::{DefaultBodyLimit, Path, Query, State},
|
||||||
|
@ -9,6 +9,7 @@ use axum::{
|
||||||
use axum_extra::headers::Range;
|
use axum_extra::headers::Range;
|
||||||
use axum_extra::TypedHeader;
|
use axum_extra::TypedHeader;
|
||||||
use axum_range::{KnownSize, Ranged};
|
use axum_range::{KnownSize, Ranged};
|
||||||
|
use regex::Regex;
|
||||||
use tower_http::{compression::CompressionLayer, CompressionLevel};
|
use tower_http::{compression::CompressionLayer, CompressionLevel};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -116,9 +117,26 @@ async fn put_settings(
|
||||||
State(config_manager): State<config::Manager>,
|
State(config_manager): State<config::Manager>,
|
||||||
Json(new_settings): Json<dto::NewSettings>,
|
Json(new_settings): Json<dto::NewSettings>,
|
||||||
) -> Result<(), APIError> {
|
) -> Result<(), APIError> {
|
||||||
settings_manager
|
if let Some(pattern) = new_settings.album_art_pattern {
|
||||||
.amend(&new_settings.to_owned().into())
|
let Ok(regex) = Regex::new(&pattern) else {
|
||||||
.await?;
|
return Err(APIError::InvalidAlbumArtPattern);
|
||||||
|
};
|
||||||
|
config_manager.set_index_album_art_pattern(regex).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(seconds) = new_settings.reindex_every_n_seconds {
|
||||||
|
config_manager
|
||||||
|
.set_index_sleep_duration(Duration::from_secs(seconds as u64))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(url_string) = new_settings.ddns_update_url {
|
||||||
|
let Ok(uri) = http::Uri::try_from(url_string) else {
|
||||||
|
return Err(APIError::InvalidDDNSURL);
|
||||||
|
};
|
||||||
|
config_manager.set_ddns_update_url(uri).await;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +154,7 @@ async fn put_mount_dirs(
|
||||||
State(config_manager): State<config::Manager>,
|
State(config_manager): State<config::Manager>,
|
||||||
new_mount_dirs: Json<Vec<dto::MountDir>>,
|
new_mount_dirs: Json<Vec<dto::MountDir>>,
|
||||||
) -> Result<(), APIError> {
|
) -> Result<(), APIError> {
|
||||||
let new_mount_dirs: Vec<config::MountDir> =
|
let new_mount_dirs: Vec<config::storage::MountDir> =
|
||||||
new_mount_dirs.iter().cloned().map(|m| m.into()).collect();
|
new_mount_dirs.iter().cloned().map(|m| m.into()).collect();
|
||||||
config_manager.set_mounts(new_mount_dirs).await;
|
config_manager.set_mounts(new_mount_dirs).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -31,6 +31,8 @@ impl IntoResponse for APIError {
|
||||||
APIError::EmptyUsername => StatusCode::BAD_REQUEST,
|
APIError::EmptyUsername => StatusCode::BAD_REQUEST,
|
||||||
APIError::IncorrectCredentials => StatusCode::UNAUTHORIZED,
|
APIError::IncorrectCredentials => StatusCode::UNAUTHORIZED,
|
||||||
APIError::Internal => StatusCode::INTERNAL_SERVER_ERROR,
|
APIError::Internal => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
APIError::InvalidAlbumArtPattern => StatusCode::BAD_REQUEST,
|
||||||
|
APIError::InvalidDDNSURL => StatusCode::BAD_REQUEST,
|
||||||
APIError::Io(_, _) => StatusCode::INTERNAL_SERVER_ERROR,
|
APIError::Io(_, _) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
APIError::OwnAdminPrivilegeRemoval => StatusCode::CONFLICT,
|
APIError::OwnAdminPrivilegeRemoval => StatusCode::CONFLICT,
|
||||||
APIError::PasswordHashing => StatusCode::INTERNAL_SERVER_ERROR,
|
APIError::PasswordHashing => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::app::{config, index, peaks, playlist, thumbnail, user};
|
use crate::app::{config, index, peaks, playlist, thumbnail};
|
||||||
use std::{collections::HashMap, convert::From, path::PathBuf};
|
use std::{collections::HashMap, convert::From, path::PathBuf};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
|
@ -127,16 +127,6 @@ pub struct NewUser {
|
||||||
pub admin: bool,
|
pub admin: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NewUser> for user::NewUser {
|
|
||||||
fn from(u: NewUser) -> Self {
|
|
||||||
Self {
|
|
||||||
name: u.name,
|
|
||||||
password: u.password,
|
|
||||||
admin: u.admin,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct UserUpdate {
|
pub struct UserUpdate {
|
||||||
pub new_password: Option<String>,
|
pub new_password: Option<String>,
|
||||||
|
@ -145,11 +135,11 @@ pub struct UserUpdate {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
pub struct MountDir {
|
pub struct MountDir {
|
||||||
pub source: String,
|
pub source: PathBuf,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<MountDir> for config::MountDir {
|
impl From<MountDir> for config::storage::MountDir {
|
||||||
fn from(m: MountDir) -> Self {
|
fn from(m: MountDir) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: m.name,
|
name: m.name,
|
||||||
|
|
|
@ -49,6 +49,10 @@ pub enum APIError {
|
||||||
IncorrectCredentials,
|
IncorrectCredentials,
|
||||||
#[error("Internal server error")]
|
#[error("Internal server error")]
|
||||||
Internal,
|
Internal,
|
||||||
|
#[error("Could not parse album art pattern")]
|
||||||
|
InvalidAlbumArtPattern,
|
||||||
|
#[error("Could not parse DDNS update URL")]
|
||||||
|
InvalidDDNSURL,
|
||||||
#[error("File I/O error for `{0}`:\n\n{1}")]
|
#[error("File I/O error for `{0}`:\n\n{1}")]
|
||||||
Io(PathBuf, std::io::Error),
|
Io(PathBuf, std::io::Error),
|
||||||
#[error("Cannot remove your own admin privilege")]
|
#[error("Cannot remove your own admin privilege")]
|
||||||
|
|
Loading…
Add table
Reference in a new issue