refactor: introduce user changeset
This commit is contained in:
parent
128fca8138
commit
cd20457f67
15
.sqlx/query-348365fd1e76ebfcfa065d1ea7e22cd7cbcd2e981f75fce75f29f1c4fbfc3df5.json
generated
Normal file
15
.sqlx/query-348365fd1e76ebfcfa065d1ea7e22cd7cbcd2e981f75fce75f29f1c4fbfc3df5.json
generated
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE user_ SET locked = $1 WHERE id = $2;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Bool",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "348365fd1e76ebfcfa065d1ea7e22cd7cbcd2e981f75fce75f29f1c4fbfc3df5"
|
||||
}
|
15
.sqlx/query-3e246c54d31804140272a6fc2e3c241c17b086ff219d6084684a0f2b7c31eeed.json
generated
Normal file
15
.sqlx/query-3e246c54d31804140272a6fc2e3c241c17b086ff219d6084684a0f2b7c31eeed.json
generated
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE user_ SET receiveNotifications = $1 WHERE id = $2;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Bool",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3e246c54d31804140272a6fc2e3c241c17b086ff219d6084684a0f2b7c31eeed"
|
||||
}
|
16
.sqlx/query-868bbdcb65f0ee862f221b7e3d1a4f4dbc4d818315d1713a110c4ad7acd09e3e.json
generated
Normal file
16
.sqlx/query-868bbdcb65f0ee862f221b7e3d1a4f4dbc4d818315d1713a110c4ad7acd09e3e.json
generated
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE user_ SET password = $1, salt = $2 WHERE id = $3;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "868bbdcb65f0ee862f221b7e3d1a4f4dbc4d818315d1713a110c4ad7acd09e3e"
|
||||
}
|
41
.sqlx/query-fd2f782d28612d969aa20eb35ea8da4bfdba6f059dbd45b510122210807ac5b6.json
generated
Normal file
41
.sqlx/query-fd2f782d28612d969aa20eb35ea8da4bfdba6f059dbd45b510122210807ac5b6.json
generated
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE user_ SET name = $1, email = $2, role = $3, function = $4, areaId = $5 WHERE id = $6;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "role",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"staff",
|
||||
"areamanager",
|
||||
"admin"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Custom": {
|
||||
"name": "function",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"posten",
|
||||
"fuehrungsassistent",
|
||||
"wachhabender"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Int4",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "fd2f782d28612d969aa20eb35ea8da4bfdba6f059dbd45b510122210807ac5b6"
|
||||
}
|
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -1245,6 +1245,18 @@ version = "0.15.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||
|
||||
[[package]]
|
||||
name = "dummy"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3ee4e39146145f7dd28e6c85ffdce489d93c0d9c88121063b8aacabbd9858d2"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
@ -1347,6 +1359,7 @@ checksum = "aef603df4ba9adbca6a332db7da6f614f21eafefbaf8e087844e452fdec152d0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"deunicode",
|
||||
"dummy",
|
||||
"rand",
|
||||
]
|
||||
|
||||
@ -1549,6 +1562,8 @@ checksum = "f4bd1d7843e437a4caf1d6a9112ba1ee9635b09d909af22aa4e6ec01fe971e22"
|
||||
dependencies = [
|
||||
"compact_str",
|
||||
"garde_derive",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
@ -1560,6 +1575,7 @@ checksum = "a0636cbdc03994db48fc89a0ce7765bd68d08bd8a7a68cb9a36bcde96790f413"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
|
@ -30,7 +30,7 @@ brass-macros = { path = "../macros" }
|
||||
brass-config = { path = "../config" }
|
||||
actix-http = "3.9.0"
|
||||
rinja = "0.3.5"
|
||||
garde = { version = "0.21.0", features = ["derive"] }
|
||||
garde = { version = "0.21.0", features = ["derive", "email"] }
|
||||
maud = "0.26.0"
|
||||
|
||||
[build-dependencies]
|
||||
@ -40,5 +40,5 @@ change-detection = "1.2.0"
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { version = "1.41.1", features = ["yaml", "filters"] }
|
||||
fake = { version = "3.0.1", features = ["chrono"]}
|
||||
fake = { version = "3.0.1", features = ["chrono", "derive"]}
|
||||
regex = "1.11.1"
|
||||
|
@ -123,20 +123,7 @@ async fn handle_password_change_request(
|
||||
|
||||
let (hash, salt) = generate_salt_and_hash_plain_password(password).unwrap();
|
||||
|
||||
User::update(
|
||||
pool,
|
||||
user_id,
|
||||
None,
|
||||
None,
|
||||
Some(&hash),
|
||||
Some(&salt),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
User::update_password(pool, user_id, &hash, &salt).await?;
|
||||
|
||||
if let Some(token) = token {
|
||||
token.delete(pool).await?;
|
||||
|
@ -1,24 +1,16 @@
|
||||
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
|
||||
use brass_macros::db_test;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use garde::Validate;
|
||||
use serde::Deserialize;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{
|
||||
endpoints::IdPath,
|
||||
models::{Function, Role, User},
|
||||
models::{Area, Role, User, UserChangeset},
|
||||
utils::ApplicationError,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::utils::test_helper::{test_post, DbTestContext, RequestConfig, StatusCode};
|
||||
#[cfg(test)]
|
||||
use fake::{
|
||||
faker::{internet::raw::SafeEmail, name::raw::Name},
|
||||
locales::EN,
|
||||
Fake,
|
||||
};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[derive(Deserialize)]
|
||||
#[cfg_attr(test, derive(serde::Serialize))]
|
||||
pub struct EditUserForm {
|
||||
email: String,
|
||||
name: String,
|
||||
@ -50,70 +42,24 @@ pub async fn post_edit(
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
let mut changed = false;
|
||||
|
||||
let email = if user_in_db.email != form.email {
|
||||
changed = true;
|
||||
Some(form.email.as_str())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let name = if user_in_db.name != form.name {
|
||||
changed = true;
|
||||
Some(form.name.as_str())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let role = if user_in_db.role as u8 != form.role {
|
||||
if let Ok(r) = Role::try_from(form.role) {
|
||||
changed = true;
|
||||
Some(r)
|
||||
} else {
|
||||
None
|
||||
let area_id = form.area.unwrap_or(user_in_db.area_id);
|
||||
if Area::read_by_id(pool.get_ref(), area_id).await?.is_none() {
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
||||
let changeset = UserChangeset {
|
||||
name: form.name.clone(),
|
||||
email: form.email.clone(),
|
||||
role: form.role.try_into()?,
|
||||
function: form.function.try_into()?,
|
||||
area_id,
|
||||
};
|
||||
|
||||
let function = if user_in_db.function as u8 != form.function {
|
||||
if let Ok(f) = Function::try_from(form.function) {
|
||||
changed = true;
|
||||
Some(f)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
if let Err(e) = changeset.validate() {
|
||||
return Ok(HttpResponse::BadRequest().body(e.to_string()));
|
||||
};
|
||||
|
||||
let area = if user.role == Role::Admin
|
||||
&& form.area.is_some()
|
||||
&& user_in_db.area_id != form.area.unwrap()
|
||||
{
|
||||
changed = true;
|
||||
Some(form.area.unwrap())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if changed {
|
||||
User::update(
|
||||
pool.get_ref(),
|
||||
path.id,
|
||||
email,
|
||||
name,
|
||||
None,
|
||||
None,
|
||||
role,
|
||||
function,
|
||||
area,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
User::update(pool.get_ref(), user_in_db.id, changeset).await?;
|
||||
|
||||
Ok(HttpResponse::Found()
|
||||
.insert_header((LOCATION, "/users"))
|
||||
@ -121,33 +67,32 @@ pub async fn post_edit(
|
||||
.finish())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{models::*, utils::test_helper::*};
|
||||
use brass_macros::db_test;
|
||||
use fake::{
|
||||
faker::{internet::en::SafeEmail, name::en::Name},
|
||||
Fake, Faker,
|
||||
};
|
||||
|
||||
#[db_test]
|
||||
async fn works_when_user_is_admin(context: &DbTestContext) {
|
||||
User::create(
|
||||
&context.db_pool,
|
||||
&Name(EN).fake::<String>(),
|
||||
&SafeEmail(EN).fake::<String>(),
|
||||
Role::Staff,
|
||||
Function::Posten,
|
||||
1,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
User::create(&context.db_pool, Faker.fake()).await.unwrap();
|
||||
|
||||
crate::models::Area::create(&context.db_pool, "Süd")
|
||||
.await
|
||||
.unwrap();
|
||||
Area::create(&context.db_pool, "Süd").await.unwrap();
|
||||
|
||||
let app = context.app().await;
|
||||
let config = RequestConfig {
|
||||
uri: "/users/edit/1".to_string(),
|
||||
role: Role::Admin,
|
||||
function: crate::models::Function::Posten,
|
||||
function: Function::Posten,
|
||||
user_area: 1,
|
||||
};
|
||||
|
||||
let new_name: String = Name(EN).fake();
|
||||
let new_mail: String = SafeEmail(EN).fake();
|
||||
let new_name: String = Name().fake();
|
||||
let new_mail: String = SafeEmail().fake();
|
||||
|
||||
let form = EditUserForm {
|
||||
name: new_name.clone(),
|
||||
@ -178,7 +123,7 @@ async fn cant_edit_oneself(context: &DbTestContext) {
|
||||
let config = RequestConfig {
|
||||
uri: "/users/edit/1".to_string(),
|
||||
role: Role::Admin,
|
||||
function: crate::models::Function::Posten,
|
||||
function: Function::Posten,
|
||||
user_area: 1,
|
||||
};
|
||||
|
||||
@ -193,3 +138,4 @@ async fn cant_edit_oneself(context: &DbTestContext) {
|
||||
let response = test_post(&context.db_pool, app, &config, form).await;
|
||||
assert_eq!(StatusCode::BAD_REQUEST, response.status());
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
|
||||
use garde::Validate;
|
||||
use serde::Deserialize;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{
|
||||
mail::Mailer,
|
||||
models::{Function, Registration, Role, User},
|
||||
models::{Function, Registration, Role, User, UserChangeset},
|
||||
utils::ApplicationError,
|
||||
};
|
||||
|
||||
@ -37,13 +38,21 @@ pub async fn post_new(
|
||||
let role = Role::try_from(form.role)?;
|
||||
let function = Function::try_from(form.function)?;
|
||||
|
||||
let id = User::create(
|
||||
pool.get_ref(),
|
||||
&form.name,
|
||||
&form.email,
|
||||
let changeset = UserChangeset {
|
||||
name: form.name.clone(),
|
||||
email: form.email.clone(),
|
||||
role,
|
||||
function,
|
||||
area_id,
|
||||
area_id
|
||||
};
|
||||
|
||||
if let Err(e) = changeset.validate() {
|
||||
return Ok(HttpResponse::BadRequest().body(e.to_string()));
|
||||
};
|
||||
|
||||
let id = User::create(
|
||||
pool.get_ref(),
|
||||
changeset
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
@ -25,26 +25,17 @@ pub async fn post(
|
||||
}
|
||||
|
||||
let user = if user.id != path.id {
|
||||
User::read_by_id(pool.get_ref(), path.id).await.unwrap().unwrap()
|
||||
User::read_by_id(pool.get_ref(), path.id)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
} else {
|
||||
user.into_inner()
|
||||
};
|
||||
|
||||
match query.field.as_str() {
|
||||
"locked" => {
|
||||
User::update(
|
||||
pool.get_ref(),
|
||||
user.id,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(!user.locked),
|
||||
)
|
||||
User::update_locked(pool.get_ref(), user.id, !user.locked)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -79,18 +70,10 @@ pub async fn post(
|
||||
}
|
||||
}
|
||||
"receiveNotifications" => {
|
||||
User::update(
|
||||
User::update_receive_notifications(
|
||||
pool.get_ref(),
|
||||
user.id,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(!user.receive_notifications),
|
||||
None,
|
||||
!user.receive_notifications,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
@ -12,6 +12,7 @@ mod password_reset;
|
||||
mod registration;
|
||||
mod role;
|
||||
mod user;
|
||||
mod user_changeset;
|
||||
mod vehicle;
|
||||
mod vehicle_assignement;
|
||||
|
||||
@ -33,6 +34,7 @@ pub use password_reset::{NoneToken, PasswordReset, Token};
|
||||
pub use registration::Registration;
|
||||
pub use role::Role;
|
||||
pub use user::User;
|
||||
pub use user_changeset::UserChangeset;
|
||||
pub use vehicle::Vehicle;
|
||||
pub use vehicle_assignement::VehicleAssignement;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use super::{Area, Function, Result, Role};
|
||||
use super::{Area, Function, Result, Role, UserChangeset};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct User {
|
||||
@ -20,28 +20,22 @@ pub struct User {
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub async fn create(
|
||||
pool: &PgPool,
|
||||
name: &str,
|
||||
email: &str,
|
||||
role: Role,
|
||||
function: Function,
|
||||
area_id: i32,
|
||||
) -> Result<i32> {
|
||||
pub async fn create(pool: &PgPool, changeset: UserChangeset) -> Result<i32> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO user_ (name, email, role, function, areaId)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id;
|
||||
"#,
|
||||
name,
|
||||
email,
|
||||
role as Role,
|
||||
function as Function,
|
||||
area_id
|
||||
changeset.name,
|
||||
changeset.email,
|
||||
changeset.role as Role,
|
||||
changeset.function as Function,
|
||||
changeset.area_id
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await.map(|r| r.id)
|
||||
.await
|
||||
.map(|r| r.id)
|
||||
}
|
||||
|
||||
pub async fn create_with_password(
|
||||
@ -54,8 +48,6 @@ impl User {
|
||||
function: Function,
|
||||
area_id: i32,
|
||||
) -> Result<i32> {
|
||||
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO user_ (name, email, password, salt, role, function, areaId)
|
||||
@ -71,7 +63,8 @@ impl User {
|
||||
area_id
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await.map(|r| r.id)
|
||||
.await
|
||||
.map(|r| r.id)
|
||||
}
|
||||
|
||||
pub async fn read_by_id(pool: &PgPool, id: i32) -> Result<Option<User>> {
|
||||
@ -286,72 +279,55 @@ impl User {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
pub async fn update(pool: &PgPool, id: i32, changeset: UserChangeset) -> Result<()> {
|
||||
sqlx::query!(
|
||||
"UPDATE user_ SET name = $1, email = $2, role = $3, function = $4, areaId = $5 WHERE id = $6;",
|
||||
changeset.name,
|
||||
changeset.email,
|
||||
changeset.role as Role,
|
||||
changeset.function as Function,
|
||||
changeset.area_id,
|
||||
id
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_password(pool: &PgPool, id: i32, password: &str, salt: &str) -> Result<()> {
|
||||
sqlx::query!(
|
||||
"UPDATE user_ SET password = $1, salt = $2 WHERE id = $3;",
|
||||
password,
|
||||
salt,
|
||||
id
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_locked(pool: &PgPool, id: i32, locked: bool) -> Result<()> {
|
||||
sqlx::query!("UPDATE user_ SET locked = $1 WHERE id = $2;", locked, id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_receive_notifications(
|
||||
pool: &PgPool,
|
||||
id: i32,
|
||||
email: Option<&str>,
|
||||
name: Option<&str>,
|
||||
password: Option<&str>,
|
||||
salt: Option<&str>,
|
||||
role: Option<Role>,
|
||||
function: Option<Function>,
|
||||
area_id: Option<i32>,
|
||||
receive_notifications: Option<bool>,
|
||||
locked: Option<bool>,
|
||||
receive_notifications: bool,
|
||||
) -> Result<()> {
|
||||
let mut query_builder = sqlx::QueryBuilder::new("UPDATE user_ SET ");
|
||||
let mut separated = query_builder.separated(", ");
|
||||
|
||||
if let Some(email) = email {
|
||||
separated.push("email = ");
|
||||
separated.push_bind_unseparated(email);
|
||||
}
|
||||
|
||||
if let Some(name) = name {
|
||||
separated.push("name = ");
|
||||
separated.push_bind_unseparated(name);
|
||||
}
|
||||
|
||||
if let Some(password) = password {
|
||||
separated.push("password = ");
|
||||
separated.push_bind_unseparated(password);
|
||||
}
|
||||
|
||||
if let Some(salt) = salt {
|
||||
separated.push("salt = ");
|
||||
separated.push_bind_unseparated(salt);
|
||||
}
|
||||
|
||||
if let Some(role) = role {
|
||||
separated.push("role = ");
|
||||
separated.push_bind_unseparated(role as Role);
|
||||
}
|
||||
|
||||
if let Some(function) = function {
|
||||
separated.push("function = ");
|
||||
separated.push_bind_unseparated(function as Function);
|
||||
}
|
||||
|
||||
if let Some(area_id) = area_id {
|
||||
separated.push("areaId = ");
|
||||
separated.push_bind_unseparated(area_id);
|
||||
}
|
||||
|
||||
if let Some(receive_notifications) = receive_notifications {
|
||||
separated.push("receiveNotifications = ");
|
||||
separated.push_bind_unseparated(receive_notifications);
|
||||
}
|
||||
|
||||
if let Some(locked) = locked {
|
||||
separated.push("locked = ");
|
||||
separated.push_bind_unseparated(locked);
|
||||
}
|
||||
|
||||
query_builder.push(" WHERE id = ");
|
||||
query_builder.push_bind(id);
|
||||
query_builder.push(";");
|
||||
|
||||
query_builder.build().execute(pool).await?;
|
||||
sqlx::query!(
|
||||
"UPDATE user_ SET receiveNotifications = $1 WHERE id = $2;",
|
||||
receive_notifications,
|
||||
id
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
24
web/src/models/user_changeset.rs
Normal file
24
web/src/models/user_changeset.rs
Normal file
@ -0,0 +1,24 @@
|
||||
#[cfg(test)]
|
||||
use fake::{faker::internet::en::SafeEmail, faker::name::en::Name, Dummy};
|
||||
|
||||
use garde::Validate;
|
||||
|
||||
use super::{Function, Role};
|
||||
|
||||
#[derive(Validate)]
|
||||
#[cfg_attr(test, derive(Dummy))]
|
||||
#[garde(allow_unvalidated)]
|
||||
pub struct UserChangeset {
|
||||
#[cfg_attr(test, dummy(faker = "Name()"))]
|
||||
pub name: String,
|
||||
#[garde(email)]
|
||||
#[cfg_attr(test, dummy(faker = "SafeEmail()"))]
|
||||
pub email: String,
|
||||
#[cfg_attr(test, dummy(expr = "Role::Staff"))]
|
||||
pub role: Role,
|
||||
#[cfg_attr(test, dummy(expr = "Function::Posten"))]
|
||||
pub function: Function,
|
||||
/// check before: must exist and user can create other user for this area
|
||||
#[cfg_attr(test, dummy(expr = "1"))]
|
||||
pub area_id: i32,
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user