Split up models
Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
@@ -2,10 +2,7 @@ use non_empty_string::NonEmptyString;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use std::{
|
use std::collections::HashMap;
|
||||||
collections::HashMap,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct UsersFile {
|
pub struct UsersFile {
|
||||||
@@ -27,68 +24,8 @@ pub struct UserFile {
|
|||||||
pub extra: Option<HashMap<NonEmptyString, Value>>,
|
pub extra: Option<HashMap<NonEmptyString, Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
impl From<super::users::User> for UserFile {
|
||||||
pub struct User {
|
fn from(user: super::users::User) -> Self {
|
||||||
pub displayname: NonEmptyString,
|
|
||||||
pub email: Option<String>,
|
|
||||||
pub password: NonEmptyString,
|
|
||||||
pub disabled: bool,
|
|
||||||
pub groups: Vec<NonEmptyString>,
|
|
||||||
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub extra: Option<HashMap<NonEmptyString, Value>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Users {
|
|
||||||
pub users: HashMap<NonEmptyString, User>,
|
|
||||||
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub extra: Option<HashMap<NonEmptyString, Value>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Users {
|
|
||||||
type Target = HashMap<NonEmptyString, User>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.users
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Users {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.users
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<UserFile> for User {
|
|
||||||
fn from(user_file: UserFile) -> Self {
|
|
||||||
Self {
|
|
||||||
displayname: user_file.displayname,
|
|
||||||
email: user_file.email,
|
|
||||||
password: user_file.password,
|
|
||||||
disabled: user_file.disabled.unwrap_or(false),
|
|
||||||
groups: user_file.groups.unwrap_or_default(),
|
|
||||||
extra: user_file.extra,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<UsersFile> for Users {
|
|
||||||
fn from(users_file: UsersFile) -> Self {
|
|
||||||
Self {
|
|
||||||
users: users_file
|
|
||||||
.users
|
|
||||||
.into_iter()
|
|
||||||
.map(|(key, user)| (key, User::from(user)))
|
|
||||||
.collect(),
|
|
||||||
extra: users_file.extra,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<User> for UserFile {
|
|
||||||
fn from(user: User) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
displayname: user.displayname,
|
displayname: user.displayname,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
@@ -104,8 +41,8 @@ impl From<User> for UserFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Users> for UsersFile {
|
impl From<super::users::Users> for UsersFile {
|
||||||
fn from(users: Users) -> Self {
|
fn from(users: super::users::Users) -> Self {
|
||||||
Self {
|
Self {
|
||||||
users: users
|
users: users
|
||||||
.users
|
.users
|
||||||
@@ -116,45 +53,3 @@ impl From<Users> for UsersFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Group {
|
|
||||||
pub users: Vec<NonEmptyString>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Groups {
|
|
||||||
pub groups: HashMap<NonEmptyString, Group>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Groups {
|
|
||||||
type Target = HashMap<NonEmptyString, Group>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.groups
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Groups {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.groups
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<UsersFile> for Groups {
|
|
||||||
fn from(users_file: UsersFile) -> Self {
|
|
||||||
users_file.users.into_iter().fold(
|
|
||||||
Self {
|
|
||||||
groups: HashMap::new(),
|
|
||||||
},
|
|
||||||
|mut acc, (key, user)| {
|
|
||||||
for group in user.groups.unwrap_or_default() {
|
|
||||||
acc.entry(group)
|
|
||||||
.or_insert_with(|| Group { users: Vec::new() })
|
|
||||||
.users
|
|
||||||
.push(key.clone());
|
|
||||||
}
|
|
||||||
acc
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
49
src/models/groups.rs
Normal file
49
src/models/groups.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
use non_empty_string::NonEmptyString;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Group {
|
||||||
|
pub users: Vec<NonEmptyString>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Groups {
|
||||||
|
pub groups: HashMap<NonEmptyString, Group>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Groups {
|
||||||
|
type Target = HashMap<NonEmptyString, Group>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.groups
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Groups {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.groups
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<super::authelia::UsersFile> for Groups {
|
||||||
|
fn from(users_file: super::authelia::UsersFile) -> Self {
|
||||||
|
users_file.users.into_iter().fold(
|
||||||
|
Self {
|
||||||
|
groups: HashMap::new(),
|
||||||
|
},
|
||||||
|
|mut acc, (key, user)| {
|
||||||
|
for group in user.groups.unwrap_or_default() {
|
||||||
|
acc.entry(group)
|
||||||
|
.or_insert_with(|| Group { users: Vec::new() })
|
||||||
|
.users
|
||||||
|
.push(key.clone());
|
||||||
|
}
|
||||||
|
acc
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@@ -1 +1,3 @@
|
|||||||
pub mod authelia;
|
pub mod authelia;
|
||||||
|
pub mod groups;
|
||||||
|
pub mod users;
|
||||||
|
68
src/models/users.rs
Normal file
68
src/models/users.rs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
use non_empty_string::NonEmptyString;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct User {
|
||||||
|
pub displayname: NonEmptyString,
|
||||||
|
pub email: Option<String>,
|
||||||
|
pub password: NonEmptyString,
|
||||||
|
pub disabled: bool,
|
||||||
|
pub groups: Vec<NonEmptyString>,
|
||||||
|
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub extra: Option<HashMap<NonEmptyString, Value>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Users {
|
||||||
|
pub users: HashMap<NonEmptyString, User>,
|
||||||
|
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub extra: Option<HashMap<NonEmptyString, Value>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Users {
|
||||||
|
type Target = HashMap<NonEmptyString, User>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.users
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Users {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.users
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<super::authelia::UserFile> for User {
|
||||||
|
fn from(user_file: super::authelia::UserFile) -> Self {
|
||||||
|
Self {
|
||||||
|
displayname: user_file.displayname,
|
||||||
|
email: user_file.email,
|
||||||
|
password: user_file.password,
|
||||||
|
disabled: user_file.disabled.unwrap_or(false),
|
||||||
|
groups: user_file.groups.unwrap_or_default(),
|
||||||
|
extra: user_file.extra,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<super::authelia::UsersFile> for Users {
|
||||||
|
fn from(users_file: super::authelia::UsersFile) -> Self {
|
||||||
|
Self {
|
||||||
|
users: users_file
|
||||||
|
.users
|
||||||
|
.into_iter()
|
||||||
|
.map(|(key, user)| (key, User::from(user)))
|
||||||
|
.collect(),
|
||||||
|
extra: users_file.extra,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -11,7 +11,7 @@ use log::error;
|
|||||||
use non_empty_string::NonEmptyString;
|
use non_empty_string::NonEmptyString;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{models::authelia, routes::auth, state::State};
|
use crate::{models::groups, routes::auth, state::State};
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
struct GroupResponse {
|
struct GroupResponse {
|
||||||
@@ -19,8 +19,8 @@ struct GroupResponse {
|
|||||||
users: Vec<NonEmptyString>,
|
users: Vec<NonEmptyString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(NonEmptyString, authelia::Group)> for GroupResponse {
|
impl From<(NonEmptyString, groups::Group)> for GroupResponse {
|
||||||
fn from((groupname, group): (NonEmptyString, authelia::Group)) -> Self {
|
fn from((groupname, group): (NonEmptyString, groups::Group)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
groupname,
|
groupname,
|
||||||
users: group.users,
|
users: group.users,
|
||||||
@@ -30,8 +30,8 @@ impl From<(NonEmptyString, authelia::Group)> for GroupResponse {
|
|||||||
|
|
||||||
type GroupsResponse = HashMap<NonEmptyString, GroupResponse>;
|
type GroupsResponse = HashMap<NonEmptyString, GroupResponse>;
|
||||||
|
|
||||||
impl From<authelia::Groups> for GroupsResponse {
|
impl From<groups::Groups> for GroupsResponse {
|
||||||
fn from(groups: authelia::Groups) -> Self {
|
fn from(groups: groups::Groups) -> Self {
|
||||||
groups
|
groups
|
||||||
.groups
|
.groups
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -74,7 +74,7 @@ pub struct GroupCreate {
|
|||||||
users: Vec<NonEmptyString>,
|
users: Vec<NonEmptyString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<GroupCreate> for authelia::Group {
|
impl From<GroupCreate> for groups::Group {
|
||||||
fn from(update: GroupCreate) -> Self {
|
fn from(update: GroupCreate) -> Self {
|
||||||
Self {
|
Self {
|
||||||
users: update.users,
|
users: update.users,
|
||||||
@@ -97,7 +97,7 @@ pub async fn create(
|
|||||||
return Err(StatusCode::CONFLICT);
|
return Err(StatusCode::CONFLICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
let group_created = authelia::Group::from(group_create);
|
let group_created = groups::Group::from(group_create);
|
||||||
|
|
||||||
for username in &group_created.users {
|
for username in &group_created.users {
|
||||||
if !users.contains_key(username) {
|
if !users.contains_key(username) {
|
||||||
@@ -125,7 +125,7 @@ pub struct GroupUpdate {
|
|||||||
users: Vec<NonEmptyString>,
|
users: Vec<NonEmptyString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<GroupUpdate> for authelia::Group {
|
impl From<GroupUpdate> for groups::Group {
|
||||||
fn from(update: GroupUpdate) -> Self {
|
fn from(update: GroupUpdate) -> Self {
|
||||||
Self {
|
Self {
|
||||||
users: update.users,
|
users: update.users,
|
||||||
@@ -150,7 +150,7 @@ pub async fn update(
|
|||||||
.unwrap_or_else(|| groupname.clone());
|
.unwrap_or_else(|| groupname.clone());
|
||||||
|
|
||||||
let group_existing = groups.get(&groupname).ok_or(StatusCode::NOT_FOUND)?;
|
let group_existing = groups.get(&groupname).ok_or(StatusCode::NOT_FOUND)?;
|
||||||
let group_updated = authelia::Group::from(group_update);
|
let group_updated = groups::Group::from(group_update);
|
||||||
|
|
||||||
if groupname != new_groupname
|
if groupname != new_groupname
|
||||||
&& (groupname == state.config.oauth.admin_group
|
&& (groupname == state.config.oauth.admin_group
|
||||||
|
@@ -12,7 +12,7 @@ use non_empty_string::NonEmptyString;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
models::authelia, routes::auth, state::State, utils::crypto::generate_random_password_hash,
|
models::users, routes::auth, state::State, utils::crypto::generate_random_password_hash,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
@@ -23,8 +23,8 @@ struct UserResponse {
|
|||||||
groups: Option<Vec<NonEmptyString>>,
|
groups: Option<Vec<NonEmptyString>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(NonEmptyString, authelia::User)> for UserResponse {
|
impl From<(NonEmptyString, users::User)> for UserResponse {
|
||||||
fn from((username, user): (NonEmptyString, authelia::User)) -> Self {
|
fn from((username, user): (NonEmptyString, users::User)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
username,
|
username,
|
||||||
displayname: user.displayname,
|
displayname: user.displayname,
|
||||||
@@ -36,8 +36,8 @@ impl From<(NonEmptyString, authelia::User)> for UserResponse {
|
|||||||
|
|
||||||
type UsersResponse = HashMap<NonEmptyString, UserResponse>;
|
type UsersResponse = HashMap<NonEmptyString, UserResponse>;
|
||||||
|
|
||||||
impl From<authelia::Users> for UsersResponse {
|
impl From<users::Users> for UsersResponse {
|
||||||
fn from(users: authelia::Users) -> Self {
|
fn from(users: users::Users) -> Self {
|
||||||
users
|
users
|
||||||
.users
|
.users
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -84,7 +84,7 @@ pub struct UserCreate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::fallible_impl_from)]
|
#[allow(clippy::fallible_impl_from)]
|
||||||
impl From<UserCreate> for authelia::User {
|
impl From<UserCreate> for users::User {
|
||||||
fn from(user_create: UserCreate) -> Self {
|
fn from(user_create: UserCreate) -> Self {
|
||||||
Self {
|
Self {
|
||||||
displayname: user_create.displayname,
|
displayname: user_create.displayname,
|
||||||
@@ -112,7 +112,7 @@ pub async fn create(
|
|||||||
return Err(StatusCode::CONFLICT);
|
return Err(StatusCode::CONFLICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
let user_created = authelia::User::from(user_create);
|
let user_created = users::User::from(user_create);
|
||||||
users.users.insert(username.clone(), user_created.clone());
|
users.users.insert(username.clone(), user_created.clone());
|
||||||
|
|
||||||
state.save_users(users).map_err(|e| {
|
state.save_users(users).map_err(|e| {
|
||||||
@@ -132,7 +132,7 @@ pub struct UserUpdate {
|
|||||||
groups: Option<Vec<NonEmptyString>>,
|
groups: Option<Vec<NonEmptyString>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(Self, UserUpdate)> for authelia::User {
|
impl From<(Self, UserUpdate)> for users::User {
|
||||||
fn from((user_existing, user_update): (Self, UserUpdate)) -> Self {
|
fn from((user_existing, user_update): (Self, UserUpdate)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
displayname: user_update.displayname,
|
displayname: user_update.displayname,
|
||||||
@@ -162,7 +162,7 @@ pub async fn update(
|
|||||||
.unwrap_or_else(|| username.clone());
|
.unwrap_or_else(|| username.clone());
|
||||||
|
|
||||||
let user_existing = users.remove(&username).ok_or(StatusCode::NOT_FOUND)?;
|
let user_existing = users.remove(&username).ok_or(StatusCode::NOT_FOUND)?;
|
||||||
let user_updated = authelia::User::from((user_existing, user_update));
|
let user_updated = users::User::from((user_existing, user_update));
|
||||||
|
|
||||||
users
|
users
|
||||||
.users
|
.users
|
||||||
|
@@ -3,34 +3,33 @@ use std::error::Error;
|
|||||||
use crate::{models, state::State};
|
use crate::{models, state::State};
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn load_users(&self) -> Result<models::authelia::Users, Box<dyn Error + Send + Sync>> {
|
pub fn load_users(&self) -> Result<models::users::Users, Box<dyn Error + Send + Sync>> {
|
||||||
let file_contents = std::fs::read_to_string(&self.config.authelia.user_database)?;
|
let file_contents = std::fs::read_to_string(&self.config.authelia.user_database)?;
|
||||||
let users_file: models::authelia::UsersFile = serde_yaml::from_str(&file_contents)?;
|
let users_file: models::authelia::UsersFile = serde_yaml::from_str(&file_contents)?;
|
||||||
let users = models::authelia::Users::from(users_file);
|
let users = models::users::Users::from(users_file);
|
||||||
Ok(users)
|
Ok(users)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_groups(&self) -> Result<models::authelia::Groups, Box<dyn Error + Send + Sync>> {
|
pub fn load_groups(&self) -> Result<models::groups::Groups, Box<dyn Error + Send + Sync>> {
|
||||||
let file_contents = std::fs::read_to_string(&self.config.authelia.user_database)?;
|
let file_contents = std::fs::read_to_string(&self.config.authelia.user_database)?;
|
||||||
let users_file = serde_yaml::from_str::<models::authelia::UsersFile>(&file_contents)?;
|
let users_file = serde_yaml::from_str::<models::authelia::UsersFile>(&file_contents)?;
|
||||||
let groups = models::authelia::Groups::from(users_file);
|
let groups = models::groups::Groups::from(users_file);
|
||||||
Ok(groups)
|
Ok(groups)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_users_and_groups(
|
pub fn load_users_and_groups(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<(models::authelia::Users, models::authelia::Groups), Box<dyn Error + Send + Sync>>
|
) -> Result<(models::users::Users, models::groups::Groups), Box<dyn Error + Send + Sync>> {
|
||||||
{
|
|
||||||
let file_contents = std::fs::read_to_string(&self.config.authelia.user_database)?;
|
let file_contents = std::fs::read_to_string(&self.config.authelia.user_database)?;
|
||||||
let users_file = serde_yaml::from_str::<models::authelia::UsersFile>(&file_contents)?;
|
let users_file = serde_yaml::from_str::<models::authelia::UsersFile>(&file_contents)?;
|
||||||
let users = models::authelia::Users::from(users_file.clone());
|
let users = models::users::Users::from(users_file.clone());
|
||||||
let groups = models::authelia::Groups::from(users_file);
|
let groups = models::groups::Groups::from(users_file);
|
||||||
Ok((users, groups))
|
Ok((users, groups))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_users(
|
pub fn save_users(
|
||||||
&self,
|
&self,
|
||||||
users: models::authelia::Users,
|
users: models::users::Users,
|
||||||
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
let users_file = models::authelia::UsersFile::from(users);
|
let users_file = models::authelia::UsersFile::from(users);
|
||||||
let file_contents = serde_yaml::to_string(&users_file)?;
|
let file_contents = serde_yaml::to_string(&users_file)?;
|
||||||
|
Reference in New Issue
Block a user