Preserve order of mounts points and users
This commit is contained in:
parent
497b3bb545
commit
08052c25a3
4 changed files with 64 additions and 55 deletions
|
@ -1,5 +1,4 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
|
@ -24,45 +23,33 @@ pub struct Config {
|
||||||
pub reindex_every_n_seconds: Option<u64>,
|
pub reindex_every_n_seconds: Option<u64>,
|
||||||
pub album_art_pattern: Option<Regex>,
|
pub album_art_pattern: Option<Regex>,
|
||||||
pub ddns_url: Option<http::Uri>,
|
pub ddns_url: Option<http::Uri>,
|
||||||
pub mount_dirs: HashMap<String, MountDir>,
|
pub mount_dirs: Vec<MountDir>,
|
||||||
pub users: HashMap<String, User>,
|
pub users: Vec<User>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<storage::Config> for Config {
|
impl TryFrom<storage::Config> for Config {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(c: storage::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 config = Config::default();
|
||||||
for user in c.users {
|
config.set_mounts(c.mount_dirs)?;
|
||||||
let user = <storage::User as TryInto<User>>::try_into(user)?;
|
config.set_users(c.users)?;
|
||||||
users.insert(user.name.clone(), user);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut mount_dirs: HashMap<String, MountDir> = HashMap::new();
|
config.reindex_every_n_seconds = c.reindex_every_n_seconds;
|
||||||
for mount_dir in c.mount_dirs {
|
|
||||||
let mount_dir = <storage::MountDir as TryInto<MountDir>>::try_into(mount_dir)?;
|
|
||||||
mount_dirs.insert(mount_dir.name.clone(), mount_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ddns_url = match c.ddns_url.map(http::Uri::try_from) {
|
config.album_art_pattern = match c.album_art_pattern.as_deref().map(Regex::new) {
|
||||||
Some(Ok(u)) => Some(u),
|
|
||||||
Some(Err(_)) => return Err(Error::DDNSUpdateURLInvalid),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let album_art_pattern = match c.album_art_pattern.as_deref().map(Regex::new) {
|
|
||||||
Some(Ok(u)) => Some(u),
|
Some(Ok(u)) => Some(u),
|
||||||
Some(Err(_)) => return Err(Error::IndexAlbumArtPatternInvalid),
|
Some(Err(_)) => return Err(Error::IndexAlbumArtPatternInvalid),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Config {
|
config.ddns_url = match c.ddns_url.map(http::Uri::try_from) {
|
||||||
reindex_every_n_seconds: c.reindex_every_n_seconds,
|
Some(Ok(u)) => Some(u),
|
||||||
album_art_pattern,
|
Some(Err(_)) => return Err(Error::DDNSUpdateURLInvalid),
|
||||||
ddns_url,
|
None => None,
|
||||||
mount_dirs,
|
};
|
||||||
users,
|
|
||||||
})
|
Ok(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,9 +58,9 @@ impl From<Config> for storage::Config {
|
||||||
Self {
|
Self {
|
||||||
reindex_every_n_seconds: c.reindex_every_n_seconds,
|
reindex_every_n_seconds: c.reindex_every_n_seconds,
|
||||||
album_art_pattern: c.album_art_pattern.map(|p| p.as_str().to_owned()),
|
album_art_pattern: c.album_art_pattern.map(|p| p.as_str().to_owned()),
|
||||||
mount_dirs: c.mount_dirs.into_iter().map(|(_, d)| d.into()).collect(),
|
mount_dirs: c.mount_dirs.into_iter().map(|d| d.into()).collect(),
|
||||||
ddns_url: c.ddns_url.map(|u| u.to_string()),
|
ddns_url: c.ddns_url.map(|u| u.to_string()),
|
||||||
users: c.users.into_iter().map(|(_, u)| u.into()).collect(),
|
users: c.users.into_iter().map(|u| u.into()).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,13 +168,15 @@ impl Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
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.iter().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_user(&self, username: &str) -> Result<User, Error> {
|
pub async fn get_user(&self, username: &str) -> Result<User, Error> {
|
||||||
let config = self.config.read().await;
|
let config = self.config.read().await;
|
||||||
let user = config.users.get(username);
|
config
|
||||||
user.cloned().ok_or(Error::UserNotFound)
|
.get_user(username)
|
||||||
|
.cloned()
|
||||||
|
.ok_or(Error::UserNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_user(
|
pub async fn create_user(
|
||||||
|
@ -230,7 +219,7 @@ impl Manager {
|
||||||
|
|
||||||
pub async fn get_mounts(&self) -> Vec<MountDir> {
|
pub async fn get_mounts(&self) -> Vec<MountDir> {
|
||||||
let config = self.config.read().await;
|
let config = self.config.read().await;
|
||||||
config.mount_dirs.values().cloned().collect()
|
config.mount_dirs.iter().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn resolve_virtual_path<P: AsRef<Path>>(
|
pub async fn resolve_virtual_path<P: AsRef<Path>>(
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
@ -40,18 +39,19 @@ impl From<MountDir> for storage::MountDir {
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn set_mounts(&mut self, mount_dirs: Vec<storage::MountDir>) -> Result<(), Error> {
|
pub fn set_mounts(&mut self, mount_dirs: Vec<storage::MountDir>) -> Result<(), Error> {
|
||||||
let mut new_mount_dirs = HashMap::new();
|
let mut new_mount_dirs = Vec::new();
|
||||||
for mount_dir in mount_dirs {
|
for mount_dir in mount_dirs {
|
||||||
let mount_dir = <storage::MountDir as TryInto<MountDir>>::try_into(mount_dir)?;
|
let mount_dir = <storage::MountDir as TryInto<MountDir>>::try_into(mount_dir)?;
|
||||||
new_mount_dirs.insert(mount_dir.name.clone(), mount_dir);
|
new_mount_dirs.push(mount_dir);
|
||||||
}
|
}
|
||||||
|
new_mount_dirs.dedup_by(|a, b| a.name == b.name);
|
||||||
self.mount_dirs = new_mount_dirs;
|
self.mount_dirs = new_mount_dirs;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_virtual_path<P: AsRef<Path>>(&self, virtual_path: P) -> Result<PathBuf, Error> {
|
pub fn resolve_virtual_path<P: AsRef<Path>>(&self, virtual_path: P) -> Result<PathBuf, Error> {
|
||||||
for (name, mount) in &self.mount_dirs {
|
for mount in &self.mount_dirs {
|
||||||
if let Ok(p) = virtual_path.as_ref().strip_prefix(name) {
|
if let Ok(p) = virtual_path.as_ref().strip_prefix(&mount.name) {
|
||||||
return if p.components().count() == 0 {
|
return if p.components().count() == 0 {
|
||||||
Ok(mount.source.clone())
|
Ok(mount.source.clone())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -48,6 +48,17 @@ impl From<User> for storage::User {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
pub fn set_users(&mut self, users: Vec<storage::User>) -> Result<(), Error> {
|
||||||
|
let mut new_users = Vec::new();
|
||||||
|
for user in users {
|
||||||
|
let user = <storage::User as TryInto<User>>::try_into(user)?;
|
||||||
|
new_users.push(user);
|
||||||
|
}
|
||||||
|
new_users.dedup_by(|a, b| a.name == b.name);
|
||||||
|
self.users = new_users;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_user(
|
pub fn create_user(
|
||||||
&mut self,
|
&mut self,
|
||||||
username: &str,
|
username: &str,
|
||||||
|
@ -58,25 +69,34 @@ impl Config {
|
||||||
return Err(Error::EmptyUsername);
|
return Err(Error::EmptyUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.users.contains_key(username) {
|
if self.exists(username) {
|
||||||
return Err(Error::DuplicateUsername);
|
return Err(Error::DuplicateUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
let password_hash = auth::hash_password(&password)?;
|
let password_hash = auth::hash_password(&password)?;
|
||||||
|
|
||||||
self.users.insert(
|
self.users.push(User {
|
||||||
username.to_owned(),
|
name: username.to_owned(),
|
||||||
User {
|
admin: Some(admin),
|
||||||
name: username.to_owned(),
|
initial_password: None,
|
||||||
admin: Some(admin),
|
hashed_password: password_hash,
|
||||||
initial_password: None,
|
});
|
||||||
hashed_password: password_hash,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn exists(&self, username: &str) -> bool {
|
||||||
|
self.users.iter().any(|u| u.name == username)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_user(&self, username: &str) -> Option<&User> {
|
||||||
|
self.users.iter().find(|u| u.name == username)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_user_mut(&mut self, username: &str) -> Option<&mut User> {
|
||||||
|
self.users.iter_mut().find(|u| u.name == username)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn authenticate(
|
pub fn authenticate(
|
||||||
&self,
|
&self,
|
||||||
auth_token: &auth::Token,
|
auth_token: &auth::Token,
|
||||||
|
@ -84,7 +104,7 @@ impl Config {
|
||||||
auth_secret: &auth::Secret,
|
auth_secret: &auth::Secret,
|
||||||
) -> Result<auth::Authorization, Error> {
|
) -> Result<auth::Authorization, Error> {
|
||||||
let authorization = auth::decode_auth_token(auth_token, scope, auth_secret)?;
|
let authorization = auth::decode_auth_token(auth_token, scope, auth_secret)?;
|
||||||
if self.users.contains_key(&authorization.username) {
|
if self.exists(&authorization.username) {
|
||||||
Ok(authorization)
|
Ok(authorization)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::IncorrectUsername)
|
Err(Error::IncorrectUsername)
|
||||||
|
@ -97,7 +117,7 @@ impl Config {
|
||||||
password: &str,
|
password: &str,
|
||||||
auth_secret: &auth::Secret,
|
auth_secret: &auth::Secret,
|
||||||
) -> Result<auth::Token, Error> {
|
) -> Result<auth::Token, Error> {
|
||||||
let user = self.users.get(username).ok_or(Error::IncorrectUsername)?;
|
let user = self.get_user(username).ok_or(Error::IncorrectUsername)?;
|
||||||
if auth::verify_password(&user.hashed_password, password) {
|
if auth::verify_password(&user.hashed_password, password) {
|
||||||
let authorization = auth::Authorization {
|
let authorization = auth::Authorization {
|
||||||
username: username.to_owned(),
|
username: username.to_owned(),
|
||||||
|
@ -110,19 +130,19 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_is_admin(&mut self, username: &str, is_admin: bool) -> Result<(), Error> {
|
pub fn set_is_admin(&mut self, username: &str, is_admin: bool) -> Result<(), Error> {
|
||||||
let user = self.users.get_mut(username).ok_or(Error::UserNotFound)?;
|
let user = self.get_user_mut(username).ok_or(Error::UserNotFound)?;
|
||||||
user.admin = Some(is_admin);
|
user.admin = Some(is_admin);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_password(&mut self, username: &str, password: &str) -> Result<(), Error> {
|
pub fn set_password(&mut self, username: &str, password: &str) -> Result<(), Error> {
|
||||||
let user = self.users.get_mut(username).ok_or(Error::UserNotFound)?;
|
let user = self.get_user_mut(username).ok_or(Error::UserNotFound)?;
|
||||||
user.hashed_password = auth::hash_password(password)?;
|
user.hashed_password = auth::hash_password(password)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_user(&mut self, username: &str) {
|
pub fn delete_user(&mut self, username: &str) {
|
||||||
self.users.remove(username);
|
self.users.retain(|u| u.name != username);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ async fn put_settings_golden_path() {
|
||||||
let request = protocol::put_settings(dto::NewSettings {
|
let request = protocol::put_settings(dto::NewSettings {
|
||||||
album_art_pattern: Some("test_pattern".to_owned()),
|
album_art_pattern: Some("test_pattern".to_owned()),
|
||||||
reindex_every_n_seconds: Some(31),
|
reindex_every_n_seconds: Some(31),
|
||||||
ddns_update_url: Some("ddns_url".to_owned()),
|
ddns_update_url: Some("http://example.com/".to_owned()),
|
||||||
});
|
});
|
||||||
let response = service.fetch(&request).await;
|
let response = service.fetch(&request).await;
|
||||||
assert_eq!(response.status(), StatusCode::OK);
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
|
@ -77,7 +77,7 @@ async fn put_settings_golden_path() {
|
||||||
&Settings {
|
&Settings {
|
||||||
album_art_pattern: "test_pattern".to_owned(),
|
album_art_pattern: "test_pattern".to_owned(),
|
||||||
reindex_every_n_seconds: 31,
|
reindex_every_n_seconds: 31,
|
||||||
ddns_update_url: "ddns_url".to_owned(),
|
ddns_update_url: "http://example.com/".to_owned(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue