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
src
|
@ -1,5 +1,4 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
|
@ -24,45 +23,33 @@ pub struct Config {
|
|||
pub reindex_every_n_seconds: Option<u64>,
|
||||
pub album_art_pattern: Option<Regex>,
|
||||
pub ddns_url: Option<http::Uri>,
|
||||
pub mount_dirs: HashMap<String, MountDir>,
|
||||
pub users: HashMap<String, User>,
|
||||
pub mount_dirs: Vec<MountDir>,
|
||||
pub users: Vec<User>,
|
||||
}
|
||||
|
||||
impl TryFrom<storage::Config> for Config {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(c: storage::Config) -> Result<Self, Self::Error> {
|
||||
let mut users: HashMap<String, User> = HashMap::new();
|
||||
for user in c.users {
|
||||
let user = <storage::User as TryInto<User>>::try_into(user)?;
|
||||
users.insert(user.name.clone(), user);
|
||||
}
|
||||
let mut config = Config::default();
|
||||
config.set_mounts(c.mount_dirs)?;
|
||||
config.set_users(c.users)?;
|
||||
|
||||
let mut mount_dirs: HashMap<String, MountDir> = HashMap::new();
|
||||
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);
|
||||
}
|
||||
config.reindex_every_n_seconds = c.reindex_every_n_seconds;
|
||||
|
||||
let ddns_url = match c.ddns_url.map(http::Uri::try_from) {
|
||||
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) {
|
||||
config.album_art_pattern = match c.album_art_pattern.as_deref().map(Regex::new) {
|
||||
Some(Ok(u)) => Some(u),
|
||||
Some(Err(_)) => return Err(Error::IndexAlbumArtPatternInvalid),
|
||||
None => None,
|
||||
};
|
||||
|
||||
Ok(Config {
|
||||
reindex_every_n_seconds: c.reindex_every_n_seconds,
|
||||
album_art_pattern,
|
||||
ddns_url,
|
||||
mount_dirs,
|
||||
users,
|
||||
})
|
||||
config.ddns_url = match c.ddns_url.map(http::Uri::try_from) {
|
||||
Some(Ok(u)) => Some(u),
|
||||
Some(Err(_)) => return Err(Error::DDNSUpdateURLInvalid),
|
||||
None => None,
|
||||
};
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,9 +58,9 @@ impl From<Config> for storage::Config {
|
|||
Self {
|
||||
reindex_every_n_seconds: c.reindex_every_n_seconds,
|
||||
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()),
|
||||
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> {
|
||||
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> {
|
||||
let config = self.config.read().await;
|
||||
let user = config.users.get(username);
|
||||
user.cloned().ok_or(Error::UserNotFound)
|
||||
config
|
||||
.get_user(username)
|
||||
.cloned()
|
||||
.ok_or(Error::UserNotFound)
|
||||
}
|
||||
|
||||
pub async fn create_user(
|
||||
|
@ -230,7 +219,7 @@ impl Manager {
|
|||
|
||||
pub async fn get_mounts(&self) -> Vec<MountDir> {
|
||||
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>>(
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
@ -40,18 +39,19 @@ impl From<MountDir> for storage::MountDir {
|
|||
|
||||
impl Config {
|
||||
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 {
|
||||
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;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn resolve_virtual_path<P: AsRef<Path>>(&self, virtual_path: P) -> Result<PathBuf, Error> {
|
||||
for (name, mount) in &self.mount_dirs {
|
||||
if let Ok(p) = virtual_path.as_ref().strip_prefix(name) {
|
||||
for mount in &self.mount_dirs {
|
||||
if let Ok(p) = virtual_path.as_ref().strip_prefix(&mount.name) {
|
||||
return if p.components().count() == 0 {
|
||||
Ok(mount.source.clone())
|
||||
} else {
|
||||
|
|
|
@ -48,6 +48,17 @@ impl From<User> for storage::User {
|
|||
}
|
||||
|
||||
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(
|
||||
&mut self,
|
||||
username: &str,
|
||||
|
@ -58,25 +69,34 @@ impl Config {
|
|||
return Err(Error::EmptyUsername);
|
||||
}
|
||||
|
||||
if self.users.contains_key(username) {
|
||||
if self.exists(username) {
|
||||
return Err(Error::DuplicateUsername);
|
||||
}
|
||||
|
||||
let password_hash = auth::hash_password(&password)?;
|
||||
|
||||
self.users.insert(
|
||||
username.to_owned(),
|
||||
User {
|
||||
name: username.to_owned(),
|
||||
admin: Some(admin),
|
||||
initial_password: None,
|
||||
hashed_password: password_hash,
|
||||
},
|
||||
);
|
||||
self.users.push(User {
|
||||
name: username.to_owned(),
|
||||
admin: Some(admin),
|
||||
initial_password: None,
|
||||
hashed_password: password_hash,
|
||||
});
|
||||
|
||||
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(
|
||||
&self,
|
||||
auth_token: &auth::Token,
|
||||
|
@ -84,7 +104,7 @@ impl Config {
|
|||
auth_secret: &auth::Secret,
|
||||
) -> Result<auth::Authorization, Error> {
|
||||
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)
|
||||
} else {
|
||||
Err(Error::IncorrectUsername)
|
||||
|
@ -97,7 +117,7 @@ impl Config {
|
|||
password: &str,
|
||||
auth_secret: &auth::Secret,
|
||||
) -> 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) {
|
||||
let authorization = auth::Authorization {
|
||||
username: username.to_owned(),
|
||||
|
@ -110,19 +130,19 @@ impl Config {
|
|||
}
|
||||
|
||||
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);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 {
|
||||
album_art_pattern: Some("test_pattern".to_owned()),
|
||||
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;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
|
@ -77,7 +77,7 @@ async fn put_settings_golden_path() {
|
|||
&Settings {
|
||||
album_art_pattern: "test_pattern".to_owned(),
|
||||
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