refactor: finished moving models and validation into own crate

This commit is contained in:
Max Hohlfeld 2025-06-23 23:00:54 +02:00
parent f35b343768
commit 9893c37f80
112 changed files with 485 additions and 518 deletions

5
Cargo.lock generated
View File

@ -792,8 +792,13 @@ name = "brass-db"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"fake",
"garde", "garde",
"rand 0.9.1",
"regex",
"serde",
"sqlx", "sqlx",
"tracing",
] ]
[[package]] [[package]]

View File

@ -9,4 +9,12 @@ publish = false
[dependencies] [dependencies]
sqlx = { version = "^0.8", features = ["runtime-async-std-rustls", "postgres", "chrono"] } sqlx = { version = "^0.8", features = ["runtime-async-std-rustls", "postgres", "chrono"] }
chrono = { version = "0.4.33", features = ["serde", "now"] } chrono = { version = "0.4.33", features = ["serde", "now"] }
garde = { version = "0.22.0", features = ["derive", "email"] } garde = { version = "0.22.0", features = ["derive", "email"] } # refactor out
serde = { version = "1", features = ["derive"] }
rand = { version = "0.9", features = ["os_rng"] }
regex = "1.11.1"
tracing = "0.1.41"
fake = { version = "4", features = ["chrono", "derive"], optional = true}
[features]
test-helpers = ["dep:fake"]

View File

@ -1,24 +1,31 @@
mod models; pub mod models;
mod support;
pub mod validation;
pub use models::area::Area; use std::error::Error;
pub use models::assignment::Assignment; use std::fmt::Display;
pub use models::assignment_changeset::{AssignmentChangeset, AssignmentContext};
pub use models::availability::Availability; use chrono::NaiveTime;
pub use models::availability_assignment_state::AvailabilityAssignmentState;
pub use models::availability_changeset::{ pub use support::{NoneToken, Token};
AvailabilityChangeset, AvailabilityContext, find_free_date_time_slots,
}; const START_OF_DAY: NaiveTime = NaiveTime::from_hms_opt(0, 0, 0).unwrap();
pub use models::clothing::Clothing; const END_OF_DAY: NaiveTime = NaiveTime::from_hms_opt(23, 59, 59).unwrap();
pub use models::event::Event;
pub use models::event_changeset::{EventChangeset, EventContext}; #[derive(Debug)]
pub use models::export_event_row::{ExportEventRow, SimpleAssignment}; pub struct UnsupportedEnumValue {
pub use models::function::Function; pub value: u8,
pub use models::location::Location; pub enum_name: &'static str,
pub use models::password_reset::{NoneToken, PasswordReset, Token}; }
pub use models::registration::Registration;
pub use models::role::Role; impl Display for UnsupportedEnumValue {
pub use models::user::User; fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
pub use models::user_changeset::UserChangeset; write!(
pub use models::user_funtion::UserFunction; f,
pub use models::vehicle::Vehicle; "unsupported enum value '{}' given for enum '{}'",
pub use models::vehicle_assignment::VehicleAssignment; self.value, self.enum_name
)
}
}
impl Error for UnsupportedEnumValue {}

View File

@ -1,8 +1,7 @@
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use sqlx::{PgPool, query}; use sqlx::{PgPool, query};
use super::Result; use super::{AssignmentChangeset, Function, Result};
use crate::{AssignmentChangeset, Function};
pub struct Assignment { pub struct Assignment {
pub event_id: i32, pub event_id: i32,

View File

@ -1,9 +1,10 @@
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use garde::Validate; use garde::Validate;
use crate::{ use crate::models::start_date_time_lies_before_end_date_time;
use super::{
Assignment, Availability, Event, Function, UserFunction, Assignment, Availability, Event, Function, UserFunction,
models::start_date_time_lies_before_end_date_time,
}; };
#[derive(Validate)] #[derive(Validate)]

View File

@ -1,8 +1,7 @@
use chrono::{NaiveDate, NaiveDateTime}; use chrono::{NaiveDate, NaiveDateTime};
use sqlx::{PgPool, query}; use sqlx::{PgPool, query};
use super::Result; use super::{Area, AvailabilityChangeset, Result, Role, User, UserFunction};
use crate::{Area, AvailabilityChangeset, Role, User, UserFunction};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Availability { pub struct Availability {

View File

@ -1,14 +1,10 @@
use chrono::{Days, NaiveDateTime}; use chrono::{Days, NaiveDateTime};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{
utils::validation::{
start_date_time_lies_before_end_date_time, AsyncValidate, AsyncValidateError,
},
END_OF_DAY, START_OF_DAY,
};
use super::Availability; use super::Availability;
use crate::{validation::{
start_date_time_lies_before_end_date_time, AsyncValidate, AsyncValidateError
}, END_OF_DAY, START_OF_DAY};
pub struct AvailabilityChangeset { pub struct AvailabilityChangeset {
pub time: (NaiveDateTime, NaiveDateTime), pub time: (NaiveDateTime, NaiveDateTime),

View File

@ -1,7 +1,7 @@
use chrono::{NaiveDate, NaiveDateTime}; use chrono::{NaiveDate, NaiveDateTime};
use sqlx::{query, PgPool}; use sqlx::{PgPool, query};
use super::{event_changeset::EventChangeset, Clothing, Location, Result}; use super::{Clothing, EventChangeset, Location, Result};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Event { pub struct Event {

View File

@ -1,6 +1,6 @@
use chrono::NaiveDate; use chrono::NaiveDate;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
#[cfg(test)] #[cfg(feature = "test-helpers")]
use fake::{Fake, Faker}; use fake::{Fake, Faker};
use garde::Validate; use garde::Validate;
@ -29,7 +29,7 @@ pub struct EventChangeset {
pub note: Option<String>, pub note: Option<String>,
} }
#[cfg(test)] #[cfg(feature = "test-helpers")]
impl EventChangeset { impl EventChangeset {
pub fn create_for_test(start: NaiveDateTime, end: NaiveDateTime) -> EventChangeset { pub fn create_for_test(start: NaiveDateTime, end: NaiveDateTime) -> EventChangeset {
let changeset = EventChangeset { let changeset = EventChangeset {
@ -55,8 +55,14 @@ pub struct EventContext {
pub amount_of_assigned_posten: i16, pub amount_of_assigned_posten: i16,
} }
fn date_unchanged_if_edit(value: &(NaiveDateTime, NaiveDateTime), context: &Option<EventContext>) -> garde::Result { fn date_unchanged_if_edit(
if context.as_ref().is_some_and(|c| c.date_in_db != value.0.date() ) { value: &(NaiveDateTime, NaiveDateTime),
context: &Option<EventContext>,
) -> garde::Result {
if context
.as_ref()
.is_some_and(|c| c.date_in_db != value.0.date())
{
return Err(garde::Error::new("event date can't be changed")); return Err(garde::Error::new("event date can't be changed"));
} }

View File

@ -1,12 +1,11 @@
use chrono::{NaiveDate, NaiveDateTime}; use chrono::{NaiveDate, NaiveDateTime};
use sqlx::{ use sqlx::{
PgPool,
postgres::{PgHasArrayType, PgTypeInfo}, postgres::{PgHasArrayType, PgTypeInfo},
query, PgPool, query,
}; };
use crate::utils::ApplicationError; use super::{Function, Result};
use super::Function;
pub struct ExportEventRow { pub struct ExportEventRow {
pub start_timestamp: NaiveDateTime, pub start_timestamp: NaiveDateTime,
@ -38,7 +37,7 @@ impl ExportEventRow {
pool: &PgPool, pool: &PgPool,
time: (NaiveDate, NaiveDate), time: (NaiveDate, NaiveDate),
area: i32, area: i32,
) -> Result<Vec<ExportEventRow>, ApplicationError> { ) -> Result<Vec<ExportEventRow>> {
let rows = query!( let rows = query!(
"select "select
event.starttimestamp, event.starttimestamp,

View File

@ -1,8 +1,9 @@
use std::fmt::Display; use std::fmt::Display;
use crate::utils::ApplicationError;
use serde::Serialize; use serde::Serialize;
use crate::UnsupportedEnumValue;
#[derive(sqlx::Type, Debug, Clone, Copy, PartialEq, Eq, Serialize, PartialOrd, Ord)] #[derive(sqlx::Type, Debug, Clone, Copy, PartialEq, Eq, Serialize, PartialOrd, Ord)]
#[sqlx(type_name = "function", rename_all = "lowercase")] #[sqlx(type_name = "function", rename_all = "lowercase")]
pub enum Function { pub enum Function {
@ -22,16 +23,16 @@ impl Display for Function {
} }
impl TryFrom<u8> for Function { impl TryFrom<u8> for Function {
type Error = ApplicationError; type Error = UnsupportedEnumValue;
fn try_from(value: u8) -> Result<Self, Self::Error> { fn try_from(value: u8) -> Result<Self, Self::Error> {
match value { match value {
1 => Ok(Function::Posten), 1 => Ok(Function::Posten),
5 => Ok(Function::Fuehrungsassistent), 5 => Ok(Function::Fuehrungsassistent),
10 => Ok(Function::Wachhabender), 10 => Ok(Function::Wachhabender),
_ => Err(ApplicationError::UnsupportedEnumValue { _ => Err(UnsupportedEnumValue {
value: value.to_string(), value,
enum_name: String::from("Function"), enum_name: "Function",
}), }),
} }
} }

View File

@ -1,8 +1,6 @@
use sqlx::{query, PgPool}; use sqlx::{PgPool, query};
use super::Area; use super::{Area, Result};
use super::Result;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Location { pub struct Location {

View File

@ -1,23 +1,46 @@
pub mod area; mod area;
pub mod assignment; mod assignment;
pub mod assignment_changeset; mod assignment_changeset;
pub mod availability; mod availability;
pub mod availability_assignment_state; mod availability_assignment_state;
pub mod availability_changeset; mod availability_changeset;
pub mod clothing; mod clothing;
pub mod event; mod event;
pub mod event_changeset; mod event_changeset;
pub mod export_event_row; mod export_event_row;
pub mod function; mod function;
pub mod location; mod location;
pub mod password_reset; mod password_reset;
pub mod registration; mod registration;
pub mod role; mod role;
pub mod user; mod user;
pub mod user_changeset; mod user_changeset;
pub mod user_funtion; mod user_funtion;
pub mod vehicle; mod vehicle;
pub mod vehicle_assignment; mod vehicle_assignment;
pub use area::Area;
pub use assignment::Assignment;
pub use assignment_changeset::{AssignmentChangeset, AssignmentContext};
pub use availability::Availability;
pub use availability_assignment_state::AvailabilityAssignmentState;
pub use availability_changeset::{
AvailabilityChangeset, AvailabilityContext, find_free_date_time_slots,
};
pub use clothing::Clothing;
pub use event::Event;
pub use event_changeset::{EventChangeset, EventContext};
pub use export_event_row::{ExportEventRow, SimpleAssignment};
pub use function::Function;
pub use location::Location;
pub use password_reset::PasswordReset;
pub use registration::Registration;
pub use role::Role;
pub use user::User;
pub use user_changeset::UserChangeset;
pub use user_funtion::UserFunction;
pub use vehicle::Vehicle;
pub use vehicle_assignment::VehicleAssignment;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;

View File

@ -1,19 +1,9 @@
use chrono::TimeDelta; use chrono::TimeDelta;
use sqlx::{query_as, PgPool}; use sqlx::{PgPool, query_as};
use crate::support::{Token, generate_token_and_expiration};
use super::Result; use super::Result;
use crate::utils::token_generation::generate_token_and_expiration;
pub trait Token {
async fn delete(&self, pool: &PgPool) -> Result<()>;
}
pub struct NoneToken {}
impl Token for NoneToken {
async fn delete(&self, _pool: &PgPool) -> Result<()> {
unimplemented!()
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct PasswordReset { pub struct PasswordReset {

View File

@ -1,7 +1,5 @@
use chrono::TimeDelta; use chrono::TimeDelta;
use sqlx::{query_as, PgPool}; use sqlx::{PgPool, query_as};
use crate::utils::token_generation::generate_token_and_expiration;
#[derive(Debug)] #[derive(Debug)]
pub struct Registration { pub struct Registration {
@ -9,7 +7,9 @@ pub struct Registration {
pub userid: i32, pub userid: i32,
} }
use super::{password_reset::Token, Result}; use crate::support::{Token, generate_token_and_expiration};
use super::Result;
impl Registration { impl Registration {
pub async fn insert_new_for_user(pool: &PgPool, user_id: i32) -> Result<Registration> { pub async fn insert_new_for_user(pool: &PgPool, user_id: i32) -> Result<Registration> {

View File

@ -1,4 +1,4 @@
use crate::utils::ApplicationError; use crate::UnsupportedEnumValue;
#[derive(sqlx::Type, Debug, Clone, Copy, PartialEq)] #[derive(sqlx::Type, Debug, Clone, Copy, PartialEq)]
#[sqlx(type_name = "role", rename_all = "lowercase")] #[sqlx(type_name = "role", rename_all = "lowercase")]
@ -9,16 +9,16 @@ pub enum Role {
} }
impl TryFrom<u8> for Role { impl TryFrom<u8> for Role {
type Error = ApplicationError; type Error = UnsupportedEnumValue;
fn try_from(value: u8) -> Result<Self, Self::Error> { fn try_from(value: u8) -> Result<Self, Self::Error> {
match value { match value {
1 => Ok(Role::Staff), 1 => Ok(Role::Staff),
10 => Ok(Role::AreaManager), 10 => Ok(Role::AreaManager),
100 => Ok(Role::Admin), 100 => Ok(Role::Admin),
_ => Err(ApplicationError::UnsupportedEnumValue { _ => Err(UnsupportedEnumValue {
value: value.to_string(), value,
enum_name: String::from("Role"), enum_name: "Role",
}), }),
} }
} }

View File

@ -107,7 +107,7 @@ impl User {
Ok(user) Ok(user)
} }
pub async fn read_for_login(pool: &PgPool, email: &str) -> anyhow::Result<User> { pub async fn read_for_login(pool: &PgPool, email: &str) -> Result<User> {
let record = sqlx::query!( let record = sqlx::query!(
r#" r#"
SELECT id, SELECT id,
@ -155,7 +155,7 @@ impl User {
Ok(record.and_then(|r| Some(r.id))) Ok(record.and_then(|r| Some(r.id)))
} }
pub async fn read_all(pool: &PgPool) -> anyhow::Result<Vec<User>> { pub async fn read_all(pool: &PgPool) -> Result<Vec<User>> {
let records = sqlx::query!( let records = sqlx::query!(
r#" r#"
SELECT id, SELECT id,
@ -343,7 +343,7 @@ impl User {
Ok(()) Ok(())
} }
pub async fn update_login_timestamp(pool: &PgPool, id: i32) -> anyhow::Result<()> { pub async fn update_login_timestamp(pool: &PgPool, id: i32) -> Result<()> {
sqlx::query!("UPDATE user_ SET lastLogin = NOW() WHERE id = $1;", id) sqlx::query!("UPDATE user_ SET lastLogin = NOW() WHERE id = $1;", id)
.execute(pool) .execute(pool)
.await?; .await?;

View File

@ -1,31 +1,33 @@
#[cfg(test)] #[cfg(feature = "test-helpers")]
use fake::{faker::internet::en::SafeEmail, faker::name::en::Name, Dummy}; use fake::{Dummy, faker::internet::en::SafeEmail, faker::name::en::Name};
use sqlx::PgPool; use sqlx::PgPool;
use crate::utils::validation::{email_is_valid, AsyncValidate, AsyncValidateError, DbContext};
use super::{Area, Function, Role}; use super::{Area, Function, Role};
use crate::validation::{AsyncValidate, AsyncValidateError, DbContext, email_is_valid};
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(test, derive(Dummy))] #[cfg_attr(feature = "test-helpers", derive(Dummy))]
pub struct UserChangeset { pub struct UserChangeset {
#[cfg_attr(test, dummy(faker = "Name()"))] #[cfg_attr(feature = "test-helpers", dummy(faker = "Name()"))]
pub name: String, pub name: String,
#[cfg_attr(test, dummy(faker = "SafeEmail()"))] #[cfg_attr(feature = "test-helpers", dummy(faker = "SafeEmail()"))]
pub email: String, pub email: String,
#[cfg_attr(test, dummy(expr = "Role::Staff"))] #[cfg_attr(feature = "test-helpers", dummy(expr = "Role::Staff"))]
pub role: Role, pub role: Role,
#[cfg_attr(test, dummy(expr = "vec![Function::Posten]"))] #[cfg_attr(feature = "test-helpers", dummy(expr = "vec![Function::Posten]"))]
pub functions: Vec<Function>, pub functions: Vec<Function>,
#[cfg_attr(test, dummy(expr = "1"))] #[cfg_attr(feature = "test-helpers", dummy(expr = "1"))]
pub area_id: i32, pub area_id: i32,
} }
impl <'a>AsyncValidate<'a> for UserChangeset { impl<'a> AsyncValidate<'a> for UserChangeset {
type Context = DbContext<'a>; type Context = DbContext<'a>;
async fn validate_with_context(&self, context: &'a Self::Context) -> Result<(), AsyncValidateError> { async fn validate_with_context(
&self,
context: &'a Self::Context,
) -> Result<(), AsyncValidateError> {
email_is_valid(&self.email)?; email_is_valid(&self.email)?;
area_exists(context.pool, self.area_id).await?; area_exists(context.pool, self.area_id).await?;

5
db/src/support/mod.rs Normal file
View File

@ -0,0 +1,5 @@
mod token_generation;
mod token_trait;
pub use token_generation::generate_token_and_expiration;
pub use token_trait::{Token, NoneToken};

View File

@ -0,0 +1,18 @@
use chrono::{NaiveDateTime, TimeDelta, Utc};
use rand::{Rng, distr::Alphanumeric, rng};
pub fn generate_token_and_expiration(
token_length_bytes: usize,
validity: TimeDelta,
) -> (String, NaiveDateTime) {
let value = std::iter::repeat(())
.map(|()| rng().sample(Alphanumeric))
.take(token_length_bytes)
.collect::<Vec<_>>();
let token = String::from_utf8(value).unwrap();
let expires = Utc::now().naive_utc() + validity;
(token, expires)
}

View File

@ -0,0 +1,12 @@
use sqlx::PgPool;
pub trait Token {
fn delete(&self, pool: &PgPool) -> impl Future<Output = Result<(), sqlx::Error>>;
}
pub struct NoneToken {}
impl Token for NoneToken {
async fn delete(&self, _pool: &PgPool) -> Result<(), sqlx::Error> {
unimplemented!()
}
}

View File

@ -0,0 +1,10 @@
use super::AsyncValidateError;
pub trait AsyncValidate<'a> {
type Context: 'a;
fn validate_with_context(
&self,
context: &'a Self::Context,
) -> impl Future<Output = Result<(), AsyncValidateError>>;
}

1
rustfmt.toml Normal file
View File

@ -0,0 +1 @@
imports_granularity = "Crate"

View File

@ -38,7 +38,6 @@ tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
tracing-panic = "0.1.2" tracing-panic = "0.1.2"
rust_xlsxwriter = "0.87.0" rust_xlsxwriter = "0.87.0"
regex = "1.11.1"
[build-dependencies] [build-dependencies]
built = "0.7.4" built = "0.7.4"
@ -48,4 +47,5 @@ change-detection = "1.2.0"
[dev-dependencies] [dev-dependencies]
insta = { version = "1.41.1", features = ["yaml", "filters"] } insta = { version = "1.41.1", features = ["yaml", "filters"] }
fake = { version = "4", features = ["chrono", "derive"]} fake = { version = "4", features = ["chrono", "derive"]}
brass-db = { path = "../db", features = ["test-helpers"] }
regex = "1.11.1" regex = "1.11.1"

View File

@ -1,11 +1,8 @@
use actix_web::{web, HttpResponse, Responder}; use actix_web::{web, HttpResponse, Responder};
use brass_db::models::{Area, Role, User};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::IdPath, utils::ApplicationError};
endpoints::IdPath,
models::{Area, Role, User},
utils::ApplicationError,
};
#[actix_web::delete("/area/delete/{id}")] #[actix_web::delete("/area/delete/{id}")]
pub async fn delete( pub async fn delete(
@ -28,10 +25,8 @@ pub async fn delete(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::utils::test_helper::{test_delete, DbTestContext, RequestConfig, StatusCode};
models::{Area, Function, Location, Role}, use brass_db::models::{Area, Function, Location, Role};
utils::test_helper::{test_delete, DbTestContext, RequestConfig, StatusCode},
};
use brass_macros::db_test; use brass_macros::db_test;
#[db_test] #[db_test]

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{area::NewOrEditAreaTemplate, IdPath}, endpoints::{area::NewOrEditAreaTemplate, IdPath},
models::{Area, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Area, Role, User};
#[actix_web::get("/area/edit/{id}")] #[actix_web::get("/area/edit/{id}")]
async fn get( async fn get(
@ -32,23 +32,18 @@ async fn get(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use actix_http::StatusCode; use actix_http::StatusCode;
use brass_db::models::Role;
use brass_macros::db_test; use brass_macros::db_test;
use crate::{ use crate::utils::test_helper::{
models::{Function, Role}, assert_snapshot, read_body, test_get, DbTestContext, RequestConfig,
utils::test_helper::{assert_snapshot, read_body, test_get, DbTestContext, RequestConfig},
}; };
#[db_test] #[db_test]
async fn produces_template_when_area_exists_and_user_is_admin(context: &DbTestContext) { async fn produces_template_when_area_exists_and_user_is_admin(context: &DbTestContext) {
let app = context.app().await; let app = context.app().await;
let config = RequestConfig { let config = RequestConfig::new("/area/edit/1").with_role(Role::Admin);
uri: "/area/edit/1".to_string(),
role: Role::Admin,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_get(&context.db_pool, app, &config).await; let response = test_get(&context.db_pool, app, &config).await;
assert_eq!(StatusCode::OK, response.status()); assert_eq!(StatusCode::OK, response.status());
@ -61,12 +56,7 @@ mod tests {
async fn returns_unauthorized_when_user_is_not_admin(context: &DbTestContext) { async fn returns_unauthorized_when_user_is_not_admin(context: &DbTestContext) {
let app = context.app().await; let app = context.app().await;
let config = RequestConfig { let config = RequestConfig::new("/area/edit/1").with_role(Role::AreaManager);
uri: "/area/edit/1".to_string(),
role: Role::AreaManager,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_get(&context.db_pool, app, &config).await; let response = test_get(&context.db_pool, app, &config).await;
assert_eq!(StatusCode::UNAUTHORIZED, response.status()); assert_eq!(StatusCode::UNAUTHORIZED, response.status());
@ -76,12 +66,7 @@ mod tests {
async fn returns_not_found_when_area_does_not_exist(context: &DbTestContext) { async fn returns_not_found_when_area_does_not_exist(context: &DbTestContext) {
let app = context.app().await; let app = context.app().await;
let config = RequestConfig { let config = RequestConfig::new("/area/edit/2").with_role(Role::Admin);
uri: "/area/edit/2".to_string(),
role: Role::Admin,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_get(&context.db_pool, app, &config).await; let response = test_get(&context.db_pool, app, &config).await;
assert_eq!(StatusCode::NOT_FOUND, response.status()); assert_eq!(StatusCode::NOT_FOUND, response.status());

View File

@ -1,9 +1,9 @@
use crate::{ use crate::{
endpoints::area::NewOrEditAreaTemplate, endpoints::area::NewOrEditAreaTemplate,
models::{Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use actix_web::{web, Responder}; use actix_web::{web, Responder};
use brass_db::models::{Role, User};
#[actix_web::get("/area/new")] #[actix_web::get("/area/new")]
async fn get(user: web::ReqData<User>) -> Result<impl Responder, ApplicationError> { async fn get(user: web::ReqData<User>) -> Result<impl Responder, ApplicationError> {
@ -21,13 +21,13 @@ async fn get(user: web::ReqData<User>) -> Result<impl Responder, ApplicationErro
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use brass_macros::db_test;
use crate::{ use crate::{
models::{Function, Role},
utils::test_helper::{ utils::test_helper::{
assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode, assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
}, },
}; };
use brass_db::models::{Function, Role};
use brass_macros::db_test;
#[db_test] #[db_test]
async fn produces_template_when_user_is_admin(context: &DbTestContext) { async fn produces_template_when_user_is_admin(context: &DbTestContext) {

View File

@ -7,7 +7,7 @@ pub mod delete;
use askama::Template; use askama::Template;
use serde::Deserialize; use serde::Deserialize;
use crate::models::{Area, Role, User}; use brass_db::models::{Area, Role, User};
#[derive(Template)] #[derive(Template)]
#[cfg_attr(not(test), template(path = "area/new_or_edit.html"))] #[cfg_attr(not(test), template(path = "area/new_or_edit.html"))]

View File

@ -1,11 +1,8 @@
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder}; use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::IdPath, utils::ApplicationError};
endpoints::IdPath, use brass_db::models::{Area, Role, User};
models::{Area, Role, User},
utils::ApplicationError,
};
use super::AreaForm; use super::AreaForm;
@ -35,11 +32,11 @@ pub async fn post(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use actix_http::StatusCode; use actix_http::StatusCode;
use brass_db::models::{Area, Function, Role};
use brass_macros::db_test; use brass_macros::db_test;
use crate::{ use crate::{
endpoints::area::AreaForm, endpoints::area::AreaForm,
models::{Area, Function, Role},
utils::test_helper::{test_post, DbTestContext, RequestConfig}, utils::test_helper::{test_post, DbTestContext, RequestConfig},
}; };

View File

@ -1,11 +1,8 @@
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder}; use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::area::AreaForm, utils::ApplicationError};
endpoints::area::AreaForm, use brass_db::models::{Area, Role, User};
models::{Area, Role, User},
utils::ApplicationError,
};
#[actix_web::post("/area/new")] #[actix_web::post("/area/new")]
pub async fn post( pub async fn post(
@ -28,11 +25,11 @@ pub async fn post(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use actix_http::StatusCode; use actix_http::StatusCode;
use brass_db::models::{Area, Function, Role};
use brass_macros::db_test; use brass_macros::db_test;
use crate::{ use crate::{
endpoints::area::AreaForm, endpoints::area::AreaForm,
models::{Area, Function, Role},
utils::test_helper::{test_post, DbTestContext, RequestConfig}, utils::test_helper::{test_post, DbTestContext, RequestConfig},
}; };

View File

@ -4,7 +4,6 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::assignment::PlanEventPersonalTablePartialTemplate, endpoints::assignment::PlanEventPersonalTablePartialTemplate,
models::{Assignment, Event, Role, User},
utils::{ utils::{
event_planning_template::{ event_planning_template::{
generate_availability_assignment_list, generate_status_whether_staff_is_required, generate_availability_assignment_list, generate_status_whether_staff_is_required,
@ -12,6 +11,7 @@ use crate::{
ApplicationError, TemplateResponse, ApplicationError, TemplateResponse,
}, },
}; };
use brass_db::models::{Assignment, Event, Role, User};
#[derive(Deserialize)] #[derive(Deserialize)]
struct AssignmentDeleteQuery { struct AssignmentDeleteQuery {
@ -71,12 +71,10 @@ mod tests {
use fake::{faker::chrono::en::Date, Fake, Faker}; use fake::{faker::chrono::en::Date, Fake, Faker};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::test_helper::{test_delete, DbTestContext, RequestConfig};
models::{ use brass_db::models::{
Assignment, AssignmentChangeset, Availability, AvailabilityChangeset, Event, Assignment, AssignmentChangeset, Availability, AvailabilityChangeset, Event,
EventChangeset, Function, Location, Role, User, EventChangeset, Function, Location, Role, User,
},
utils::test_helper::{test_delete, DbTestContext, RequestConfig},
}; };
async fn arrange(pool: &PgPool) -> anyhow::Result<()> { async fn arrange(pool: &PgPool) -> anyhow::Result<()> {

View File

@ -1,10 +1,8 @@
use askama::Template; use askama::Template;
use crate::{ use crate::filters;
filters,
models::{Availability, AvailabilityAssignmentState, Event},
};
use brass_db::models::{Availability, AvailabilityAssignmentState, Event};
pub mod delete; pub mod delete;
pub mod post_new; pub mod post_new;

View File

@ -5,10 +5,6 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::assignment::PlanEventPersonalTablePartialTemplate, endpoints::assignment::PlanEventPersonalTablePartialTemplate,
models::{
Assignment, AssignmentChangeset, AssignmentContext, Availability, Event, Function, Role,
User,
},
utils::{ utils::{
event_planning_template::{ event_planning_template::{
generate_availability_assignment_list, generate_status_whether_staff_is_required, generate_availability_assignment_list, generate_status_whether_staff_is_required,
@ -17,6 +13,10 @@ use crate::{
}, },
}; };
use brass_db::models::{
Assignment, AssignmentChangeset, AssignmentContext, Availability, Event, Function, Role, User,
};
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct AssignmentQuery { pub struct AssignmentQuery {
availability: i32, availability: i32,

View File

@ -1,10 +1,8 @@
use actix_web::{web, HttpResponse, Responder}; use actix_web::{web, HttpResponse, Responder};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::IdPath, utils::ApplicationError};
endpoints::IdPath, use brass_db::models::{Availability, User};
models::{Availability, User}, utils::ApplicationError,
};
#[actix_web::delete("/availability/delete/{id}")] #[actix_web::delete("/availability/delete/{id}")]
pub async fn delete( pub async fn delete(

View File

@ -3,9 +3,11 @@ use chrono::{Days, NaiveDate, NaiveTime};
use serde::Deserialize; use serde::Deserialize;
use sqlx::PgPool; use sqlx::PgPool;
use crate::endpoints::availability::NewOrEditAvailabilityTemplate; use crate::{
use crate::models::{find_free_date_time_slots, Availability, User}; endpoints::availability::NewOrEditAvailabilityTemplate,
use crate::utils::{ApplicationError, TemplateResponse}; utils::{ApplicationError, TemplateResponse},
};
use brass_db::models::{find_free_date_time_slots, Availability, User};
#[derive(Deserialize)] #[derive(Deserialize)]
struct AvailabilityNewQuery { struct AvailabilityNewQuery {

View File

@ -4,15 +4,17 @@ use chrono::{NaiveDate, Utc};
use serde::Deserialize; use serde::Deserialize;
use sqlx::PgPool; use sqlx::PgPool;
use crate::filters; use crate::{
use crate::models::{ filters,
find_free_date_time_slots, Area, Assignment, Availability, Event, Function, Role, User, Vehicle, utils::{
event_planning_template::generate_vehicles_assigned_and_available,
ApplicationError,
DateTimeFormat::{DayMonthYear, DayMonthYearHourMinute, HourMinute},
TemplateResponse,
},
}; };
use crate::utils::{ use brass_db::models::{
event_planning_template::generate_vehicles_assigned_and_available, find_free_date_time_slots, Area, Assignment, Availability, Event, Function, Role, User, Vehicle,
ApplicationError,
DateTimeFormat::{DayMonthYear, DayMonthYearHourMinute, HourMinute},
TemplateResponse,
}; };
#[derive(Deserialize)] #[derive(Deserialize)]

View File

@ -4,9 +4,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{availability::NewOrEditAvailabilityTemplate, IdPath}, endpoints::{availability::NewOrEditAvailabilityTemplate, IdPath},
models::{find_free_date_time_slots, Availability, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{find_free_date_time_slots, Availability, User};
#[actix_web::get("/availability/edit/{id}")] #[actix_web::get("/availability/edit/{id}")]
pub async fn get( pub async fn get(

View File

@ -2,9 +2,11 @@ use askama::Template;
use chrono::{NaiveDate, NaiveDateTime, NaiveTime}; use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use serde::Deserialize; use serde::Deserialize;
use crate::filters; use crate::{
use crate::models::{Role, User}; filters,
use crate::utils::DateTimeFormat::{DayMonth, DayMonthYear, DayMonthYearHourMinute, HourMinute}; utils::DateTimeFormat::{DayMonth, DayMonthYear, DayMonthYearHourMinute, HourMinute},
};
use brass_db::models::{Role, User};
pub mod delete; pub mod delete;
pub mod get_new; pub mod get_new;

View File

@ -3,8 +3,11 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::availability::AvailabilityForm, endpoints::availability::AvailabilityForm,
utils::{self, ApplicationError},
};
use brass_db::{
models::{Availability, AvailabilityChangeset, AvailabilityContext, User}, models::{Availability, AvailabilityChangeset, AvailabilityContext, User},
utils::{self, validation::AsyncValidate, ApplicationError}, validation::AsyncValidate,
}; };
#[actix_web::post("/availability/new")] #[actix_web::post("/availability/new")]

View File

@ -3,8 +3,11 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{availability::AvailabilityForm, IdPath}, endpoints::{availability::AvailabilityForm, IdPath},
utils::{self, ApplicationError},
};
use brass_db::{
models::{Availability, AvailabilityChangeset, AvailabilityContext, User}, models::{Availability, AvailabilityChangeset, AvailabilityContext, User},
utils::{self, validation::AsyncValidate, ApplicationError}, validation::AsyncValidate,
}; };
#[actix_web::post("/availability/edit/{id}")] #[actix_web::post("/availability/edit/{id}")]

View File

@ -1,11 +1,8 @@
use actix_web::{web, HttpResponse, Responder}; use actix_web::{web, HttpResponse, Responder};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::IdPath, utils::ApplicationError};
endpoints::IdPath, use brass_db::models::{Clothing, Role, User};
models::{Clothing, Role, User},
utils::ApplicationError,
};
#[actix_web::delete("/clothing/{id}")] #[actix_web::delete("/clothing/{id}")]
pub async fn delete( pub async fn delete(
@ -28,13 +25,8 @@ pub async fn delete(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::utils::test_helper::{test_delete, DbTestContext, RequestConfig, StatusCode};
models::{Clothing, Role}, use brass_db::models::{Clothing, Role};
utils::test_helper::{
test_delete, DbTestContext, RequestConfig,
StatusCode,
},
};
use brass_macros::db_test; use brass_macros::db_test;
#[db_test] #[db_test]

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{clothing::EditClothingPartialTemplate, IdPath}, endpoints::{clothing::EditClothingPartialTemplate, IdPath},
models::{Clothing, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Clothing, Role, User};
#[actix_web::get("/clothing/edit/{id}")] #[actix_web::get("/clothing/edit/{id}")]
pub async fn get( pub async fn get(
@ -31,12 +31,10 @@ pub async fn get(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::utils::test_helper::{
models::{Clothing, Role}, assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
utils::test_helper::{
assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
},
}; };
use brass_db::models::{Clothing, Role};
use brass_macros::db_test; use brass_macros::db_test;
#[db_test] #[db_test]

View File

@ -2,9 +2,9 @@ use actix_web::{web, Responder};
use crate::{ use crate::{
endpoints::clothing::EditClothingPartialTemplate, endpoints::clothing::EditClothingPartialTemplate,
models::{Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Role, User};
#[actix_web::get("/clothing/new")] #[actix_web::get("/clothing/new")]
pub async fn get(user: web::ReqData<User>) -> Result<impl Responder, ApplicationError> { pub async fn get(user: web::ReqData<User>) -> Result<impl Responder, ApplicationError> {

View File

@ -2,10 +2,8 @@ use actix_web::{web, Responder};
use askama::Template; use askama::Template;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::{ApplicationError, TemplateResponse};
models::{Clothing, Role, User}, use brass_db::models::{Clothing, Role, User};
utils::{ApplicationError, TemplateResponse},
};
#[derive(Template)] #[derive(Template)]
#[cfg_attr(not(test), template(path = "clothing/overview.html"))] #[cfg_attr(not(test), template(path = "clothing/overview.html"))]
@ -40,12 +38,10 @@ pub async fn get(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::utils::test_helper::{
models::{Clothing, Role}, assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
utils::test_helper::{
assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
},
}; };
use brass_db::models::{Clothing, Role};
use brass_macros::db_test; use brass_macros::db_test;
#[db_test] #[db_test]

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{clothing::ReadClothingPartialTemplate, IdPath}, endpoints::{clothing::ReadClothingPartialTemplate, IdPath},
models::{Clothing, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Clothing, Role, User};
#[actix_web::get("/clothing/{id}")] #[actix_web::get("/clothing/{id}")]
pub async fn get( pub async fn get(
@ -28,12 +28,10 @@ pub async fn get(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::utils::test_helper::{
models::{Clothing, Role}, assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
utils::test_helper::{
assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
},
}; };
use brass_db::models::{Clothing, Role};
use brass_macros::db_test; use brass_macros::db_test;
#[db_test] #[db_test]

View File

@ -2,8 +2,8 @@ use askama::Template;
use garde::Validate; use garde::Validate;
use serde::Deserialize; use serde::Deserialize;
use crate::models::Clothing;
use crate::filters; use crate::filters;
use brass_db::models::Clothing;
pub mod delete; pub mod delete;
pub mod get_edit; pub mod get_edit;
@ -28,6 +28,6 @@ struct ReadClothingPartialTemplate {
#[derive(Deserialize, Validate)] #[derive(Deserialize, Validate)]
struct NewOrEditClothingForm { struct NewOrEditClothingForm {
#[garde(length(min=3))] #[garde(length(min = 3))]
name: String, name: String,
} }

View File

@ -7,9 +7,9 @@ use crate::{
clothing::{NewOrEditClothingForm, ReadClothingPartialTemplate}, clothing::{NewOrEditClothingForm, ReadClothingPartialTemplate},
IdPath, IdPath,
}, },
models::{Clothing, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Clothing, Role, User};
#[actix_web::post("/clothing/{id}")] #[actix_web::post("/clothing/{id}")]
pub async fn post( pub async fn post(

View File

@ -4,9 +4,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::clothing::{NewOrEditClothingForm, ReadClothingPartialTemplate}, endpoints::clothing::{NewOrEditClothingForm, ReadClothingPartialTemplate},
models::{Clothing, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Clothing, Role, User};
#[actix_web::post("/clothing")] #[actix_web::post("/clothing")]
pub async fn post( pub async fn post(

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::IdPath, endpoints::IdPath,
models::{Assignment, Event, Role, User},
utils::{self, ApplicationError}, utils::{self, ApplicationError},
}; };
use brass_db::models::{Assignment, Event, Role, User};
#[actix_web::delete("/events/{id}")] #[actix_web::delete("/events/{id}")]
pub async fn delete( pub async fn delete(

View File

@ -11,9 +11,9 @@ use chrono::{NaiveDate, NaiveTime};
use crate::{ use crate::{
endpoints::{events::NewOrEditEventTemplate, IdPath}, endpoints::{events::NewOrEditEventTemplate, IdPath},
models::{Assignment, Clothing, Event, Function, Location, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Assignment, Clothing, Event, Function, Location, Role, User};
#[actix_web::get("/events/{id}/edit")] #[actix_web::get("/events/{id}/edit")]
pub async fn get( pub async fn get(
@ -94,13 +94,14 @@ async fn produces_template(context: &DbTestContext) {
//) //)
//.await //.await
//.unwrap(); //.unwrap();
//// TODO: refactor
Location::create(&context.db_pool, "Hauptbahnhof", 1) Location::create(&context.db_pool, "Hauptbahnhof", 1)
.await .await
.unwrap(); .unwrap();
let date = NaiveDate::parse_from_str("2025-01-01", "%F").unwrap(); let date = NaiveDate::parse_from_str("2025-01-01", "%F").unwrap();
let changeset = crate::models::EventChangeset { let changeset = brass_db::models::EventChangeset {
time: ( time: (
date.and_time(NaiveTime::parse_from_str("08:00", "%R").unwrap()), date.and_time(NaiveTime::parse_from_str("08:00", "%R").unwrap()),
date.and_time(NaiveTime::parse_from_str("10:00", "%R").unwrap()), date.and_time(NaiveTime::parse_from_str("10:00", "%R").unwrap()),
@ -120,7 +121,7 @@ async fn produces_template(context: &DbTestContext) {
let config = RequestConfig { let config = RequestConfig {
uri: "/events/1/edit".to_string(), uri: "/events/1/edit".to_string(),
role: Role::Admin, role: Role::Admin,
function: vec![crate::models::Function::Posten], function: vec![brass_db::models::Function::Posten],
user_area: 1, user_area: 1,
}; };
let response = test_get(&context.db_pool, app, &config).await; let response = test_get(&context.db_pool, app, &config).await;

View File

@ -4,9 +4,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{events::NewOrEditEventTemplate, NaiveDateQuery}, endpoints::{events::NewOrEditEventTemplate, NaiveDateQuery},
models::{Clothing, Location, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Clothing, Location, Role, User};
#[actix_web::get("/events/new")] #[actix_web::get("/events/new")]
pub async fn get( pub async fn get(

View File

@ -5,7 +5,6 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::IdPath, endpoints::IdPath,
filters, filters,
models::{Availability, AvailabilityAssignmentState, Event, Role, User, Vehicle},
utils::{ utils::{
event_planning_template::{ event_planning_template::{
generate_availability_assignment_list, generate_status_whether_staff_is_required, generate_availability_assignment_list, generate_status_whether_staff_is_required,
@ -14,6 +13,7 @@ use crate::{
ApplicationError, TemplateResponse, ApplicationError, TemplateResponse,
}, },
}; };
use brass_db::models::{Availability, AvailabilityAssignmentState, Event, Role, User, Vehicle};
#[derive(Template)] #[derive(Template)]
#[template(path = "events/plan.html")] #[template(path = "events/plan.html")]

View File

@ -3,9 +3,8 @@ use chrono::{Days, NaiveDateTime};
use chrono::{NaiveDate, NaiveTime}; use chrono::{NaiveDate, NaiveTime};
use serde::Deserialize; use serde::Deserialize;
use crate::filters; use crate::{filters, utils::DateTimeFormat::{DayMonthYear, HourMinute, YearMonthDayTHourMinute}};
use crate::models::{Clothing, Location, Role, User}; use brass_db::models::{Clothing, Location, Role, User};
use crate::utils::DateTimeFormat::{DayMonthYear, HourMinute, YearMonthDayTHourMinute};
pub mod delete; pub mod delete;
pub mod get_edit; pub mod get_edit;

View File

@ -5,13 +5,13 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{events::NewOrEditEventForm, IdPath}, endpoints::{events::NewOrEditEventForm, IdPath},
models::{
Assignment, AssignmentChangeset, Availability, Event, EventChangeset, EventContext,
Function, Location, Role, User,
},
utils::{self, ApplicationError}, utils::{self, ApplicationError},
END_OF_DAY, START_OF_DAY, END_OF_DAY, START_OF_DAY,
}; };
use brass_db::models::{
Assignment, AssignmentChangeset, Availability, Event, EventChangeset, EventContext, Function,
Location, Role, User,
};
#[actix_web::post("/events/{id}/edit")] #[actix_web::post("/events/{id}/edit")]
pub async fn post( pub async fn post(

View File

@ -4,9 +4,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::events::NewOrEditEventForm, endpoints::events::NewOrEditEventForm,
models::{Event, EventChangeset, Location, Role, User},
utils::{self, ApplicationError}, utils::{self, ApplicationError},
}; };
use brass_db::models::{Event, EventChangeset, Location, Role, User};
#[actix_web::post("/events/new")] #[actix_web::post("/events/new")]
pub async fn post( pub async fn post(

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::IdPath, endpoints::IdPath,
models::{Event, Role, User},
utils::{self, ApplicationError}, utils::{self, ApplicationError},
}; };
use brass_db::models::{Event, Role, User};
#[actix_web::put("/events/{id}/cancel")] #[actix_web::put("/events/{id}/cancel")]
pub async fn put_cancel( pub async fn put_cancel(

View File

@ -1,12 +1,10 @@
use actix_web::{web, Responder}; use actix_web::{web, Responder};
use chrono::{NaiveDate, Utc};
use askama::Template; use askama::Template;
use chrono::{NaiveDate, Utc};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::{ApplicationError, TemplateResponse};
models::{Area, Role, User}, use brass_db::models::{Area, Role, User};
utils::{ApplicationError, TemplateResponse},
};
#[derive(Template)] #[derive(Template)]
#[template(path = "export/availability.html")] #[template(path = "export/availability.html")]

View File

@ -7,10 +7,8 @@ use quick_xml::se::Serializer;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::ApplicationError;
models::{Area, Availability, Role, User, UserFunction}, use brass_db::models::{Area, Availability, Role, User, UserFunction};
utils::ApplicationError,
};
#[derive(Deserialize)] #[derive(Deserialize)]
struct ExportQuery { struct ExportQuery {

View File

@ -3,10 +3,8 @@ use askama::Template;
use chrono::{Datelike, Months, NaiveDate, Utc}; use chrono::{Datelike, Months, NaiveDate, Utc};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::{ApplicationError, TemplateResponse};
models::{Area, Role, User}, use brass_db::models::{Area, Role, User};
utils::{ApplicationError, TemplateResponse},
};
#[derive(Template)] #[derive(Template)]
#[template(path = "export/events.html")] #[template(path = "export/events.html")]

View File

@ -1,15 +1,12 @@
use crate::models::{ExportEventRow, Function, SimpleAssignment};
use actix_http::header::CONTENT_DISPOSITION; use actix_http::header::CONTENT_DISPOSITION;
use actix_web::{http::header::ContentDisposition, web, HttpResponse, Responder}; use actix_web::{http::header::ContentDisposition, web, HttpResponse, Responder};
use brass_db::models::{ExportEventRow, Function, Role, SimpleAssignment, User};
use chrono::{Datelike, NaiveDate}; use chrono::{Datelike, NaiveDate};
use rust_xlsxwriter::workbook::Workbook; use rust_xlsxwriter::workbook::Workbook;
use serde::Deserialize; use serde::Deserialize;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::{ApplicationError, DateTimeFormat};
models::{Role, User},
utils::{ApplicationError, DateTimeFormat},
};
#[derive(Deserialize)] #[derive(Deserialize)]
struct ExportQuery { struct ExportQuery {

View File

@ -1,11 +1,8 @@
use actix_web::{web, HttpResponse, Responder}; use actix_web::{web, HttpResponse, Responder};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::IdPath, utils::ApplicationError};
endpoints::IdPath, use brass_db::models::{Location, Role, User};
models::{Location, Role, User},
utils::ApplicationError,
};
#[actix_web::delete("/locations/delete/{id}")] #[actix_web::delete("/locations/delete/{id}")]
pub async fn delete( pub async fn delete(

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{location::LocationTemplate, IdPath}, endpoints::{location::LocationTemplate, IdPath},
models::{Area, Location, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Area, Location, Role, User};
#[actix_web::get("/locations/edit/{id}")] #[actix_web::get("/locations/edit/{id}")]
pub async fn get( pub async fn get(

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::location::LocationTemplate, endpoints::location::LocationTemplate,
models::{Area, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Area, Role, User};
#[actix_web::get("/locations/new")] #[actix_web::get("/locations/new")]
pub async fn get( pub async fn get(

View File

@ -2,10 +2,8 @@ use actix_web::{web, Responder};
use askama::Template; use askama::Template;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::{ApplicationError, TemplateResponse};
models::{Area, Location, Role, User}, use brass_db::models::{Area, Location, Role, User};
utils::{ApplicationError, TemplateResponse},
};
#[derive(Template)] #[derive(Template)]
#[template(path = "location/overview.html")] #[template(path = "location/overview.html")]

View File

@ -1,15 +1,15 @@
use askama::Template; use askama::Template;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::models::{Area, Location, Role, User};
use crate::filters; use crate::filters;
use brass_db::models::{Area, Location, Role, User};
pub mod delete;
pub mod get_edit;
pub mod get_new; pub mod get_new;
pub mod get_overview; pub mod get_overview;
pub mod post_new;
pub mod get_edit;
pub mod post_edit; pub mod post_edit;
pub mod delete; pub mod post_new;
#[derive(Template)] #[derive(Template)]
#[template(path = "location/new_or_edit.html")] #[template(path = "location/new_or_edit.html")]

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{location::LocationForm, IdPath}, endpoints::{location::LocationForm, IdPath},
models::{Location, Role, User},
utils::ApplicationError, utils::ApplicationError,
}; };
use brass_db::models::{Location, Role, User};
#[actix_web::post("/locations/edit/{id}")] #[actix_web::post("/locations/edit/{id}")]
pub async fn post( pub async fn post(

View File

@ -1,15 +1,8 @@
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder}; use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
use brass_macros::db_test;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::location::LocationForm, utils::ApplicationError};
endpoints::location::LocationForm, use brass_db::models::{Location, Role, User};
models::{Location, Role, User},
utils::ApplicationError,
};
#[cfg(test)]
use crate::utils::test_helper::{test_post, DbTestContext, RequestConfig, StatusCode};
#[actix_web::post("/locations/new")] #[actix_web::post("/locations/new")]
pub async fn post( pub async fn post(
@ -35,58 +28,68 @@ pub async fn post(
.finish()) .finish())
} }
#[db_test] #[cfg(test)]
async fn works_when_user_is_admin(context: &DbTestContext) { mod tests {
let app = context.app().await; use crate::{
let config = RequestConfig { endpoints::location::LocationForm,
uri: "/locations/new".to_string(), utils::test_helper::{test_post, DbTestContext, RequestConfig, StatusCode},
role: Role::Admin,
function: vec![crate::models::Function::Posten],
user_area: 1,
}; };
use brass_db::models::{Function, Location, Role};
use brass_macros::db_test;
let form = LocationForm { #[db_test]
name: "Hauptbahnhof".to_string(), async fn works_when_user_is_admin(context: &DbTestContext) {
area: Some(1), let app = context.app().await;
}; let config = RequestConfig {
uri: "/locations/new".to_string(),
role: Role::Admin,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_post(&context.db_pool, app, &config, form).await; let form = LocationForm {
assert_eq!(StatusCode::FOUND, response.status()); name: "Hauptbahnhof".to_string(),
area: Some(1),
};
assert_eq!( let response = test_post(&context.db_pool, app, &config, form).await;
"Hauptbahnhof".to_string(), assert_eq!(StatusCode::FOUND, response.status());
Location::read_by_id(&context.db_pool, 1)
.await assert_eq!(
.unwrap() "Hauptbahnhof".to_string(),
.unwrap() Location::read_by_id(&context.db_pool, 1)
.name .await
); .unwrap()
} .unwrap()
.name
#[db_test] );
async fn uses_area_id_of_area_manager(context: &DbTestContext) { }
let app = context.app().await;
let config = RequestConfig { #[db_test]
uri: "/locations/new".to_string(), async fn uses_area_id_of_area_manager(context: &DbTestContext) {
role: Role::AreaManager, let app = context.app().await;
function: vec![crate::models::Function::Posten], let config = RequestConfig {
user_area: 1, uri: "/locations/new".to_string(),
}; role: Role::AreaManager,
function: vec![Function::Posten],
let form = LocationForm { user_area: 1,
name: "Hauptbahnhof".to_string(), };
area: None,
}; let form = LocationForm {
name: "Hauptbahnhof".to_string(),
let response = test_post(&context.db_pool, app, &config, form).await; area: None,
assert_eq!(StatusCode::FOUND, response.status()); };
assert_eq!( let response = test_post(&context.db_pool, app, &config, form).await;
"Hauptbahnhof".to_string(), assert_eq!(StatusCode::FOUND, response.status());
Location::read_by_id(&context.db_pool, 1)
.await assert_eq!(
.unwrap() "Hauptbahnhof".to_string(),
.unwrap() Location::read_by_id(&context.db_pool, 1)
.name .await
); .unwrap()
.unwrap()
.name
);
}
} }

View File

@ -1,11 +1,8 @@
use actix_web::{web, HttpResponse, Responder}; use actix_web::{web, HttpResponse, Responder};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::IdPath, utils::ApplicationError};
endpoints::IdPath, use brass_db::models::{Role, User};
models::{Role, User},
utils::ApplicationError,
};
#[actix_web::delete("/users/{id}")] #[actix_web::delete("/users/{id}")]
pub async fn delete( pub async fn delete(

View File

@ -1,10 +1,9 @@
use actix_web::{web, Responder}; use actix_web::{web, Responder};
use askama::Template; use askama::Template;
use crate::{ use crate::utils::{ApplicationError, TemplateResponse};
models::User,
utils::{ApplicationError, TemplateResponse}, use brass_db::models::User;
};
#[derive(Template)] #[derive(Template)]
#[template(path = "user/profile_change_password.html")] #[template(path = "user/profile_change_password.html")]

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{user::NewOrEditUserTemplate, IdPath}, endpoints::{user::NewOrEditUserTemplate, IdPath},
models::{Area, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Area, Role, User};
#[actix_web::get("/users/edit/{id}")] #[actix_web::get("/users/edit/{id}")]
pub async fn get_edit( pub async fn get_edit(

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::user::NewOrEditUserTemplate, endpoints::user::NewOrEditUserTemplate,
models::{Area, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Area, Role, User};
#[actix_web::get("/users/new")] #[actix_web::get("/users/new")]
pub async fn get_new( pub async fn get_new(

View File

@ -1,8 +1,8 @@
use crate::{ use crate::{
filters, filters,
models::{Area, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Area, Role, User};
use actix_web::{web, Responder}; use actix_web::{web, Responder};
use askama::Template; use askama::Template;
@ -14,7 +14,7 @@ pub struct UsersTemplate {
user: User, user: User,
area: Option<Area>, area: Option<Area>,
users: Vec<User>, users: Vec<User>,
is_oob: bool is_oob: bool,
} }
#[actix_web::get("/users")] #[actix_web::get("/users")]
@ -44,7 +44,7 @@ pub async fn get_overview(
user: user.into_inner(), user: user.into_inner(),
area, area,
users, users,
is_oob: false is_oob: false,
}; };
Ok(template.to_response()?) Ok(template.to_response()?)

View File

@ -4,9 +4,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
filters, filters,
models::{Area, Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Area, Role, User};
#[derive(Template)] #[derive(Template)]
#[template(path = "user/profile.html")] #[template(path = "user/profile.html")]

View File

@ -3,10 +3,8 @@ use actix_web::{get, http::header::LOCATION, web, HttpResponse, Responder};
use serde::Deserialize; use serde::Deserialize;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::{ApplicationError, TemplateResponse};
models::Registration, use brass_db::models::Registration;
utils::{ApplicationError, TemplateResponse},
};
use super::ResetPasswordTemplate; use super::ResetPasswordTemplate;

View File

@ -4,10 +4,8 @@ use askama::Template;
use serde::Deserialize; use serde::Deserialize;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::{ApplicationError, Customization, TemplateResponse};
models::PasswordReset, use brass_db::models::PasswordReset;
utils::{ApplicationError, Customization, TemplateResponse},
};
use super::ResetPasswordTemplate; use super::ResetPasswordTemplate;

View File

@ -1,8 +1,6 @@
use crate::{ use crate::filters;
filters,
models::{Area, Role, User},
};
use askama::Template; use askama::Template;
use brass_db::models::{Area, Role, User};
use serde::Deserialize; use serde::Deserialize;
pub mod delete; pub mod delete;
@ -22,8 +20,8 @@ pub mod post_new;
pub mod post_register; pub mod post_register;
pub mod post_resend_registration; pub mod post_resend_registration;
pub mod post_reset; pub mod post_reset;
pub mod put_receive_notifications;
pub mod put_lock; pub mod put_lock;
pub mod put_receive_notifications;
#[derive(Template)] #[derive(Template)]
#[template(path = "user/new_or_edit.html")] #[template(path = "user/new_or_edit.html")]

View File

@ -3,10 +3,8 @@ use maud::html;
use serde::Deserialize; use serde::Deserialize;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::{password_change::PasswordChangeBuilder, ApplicationError};
models::{NoneToken, User}, use brass_db::{models::User, NoneToken};
utils::{password_change::PasswordChangeBuilder, ApplicationError},
};
#[derive(Deserialize)] #[derive(Deserialize)]
struct ChangePasswordForm { struct ChangePasswordForm {

View File

@ -1,10 +1,10 @@
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder}; use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
use brass_db::{models::{Function, Role, User, UserChangeset}, validation::{AsyncValidate, DbContext}};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{user::NewOrEditUserForm, IdPath}, endpoints::{user::NewOrEditUserForm, IdPath},
models::{Function, Role, User, UserChangeset}, utils::ApplicationError,
utils::{validation::{AsyncValidate, DbContext}, ApplicationError},
}; };
#[actix_web::post("/users/edit/{id}")] #[actix_web::post("/users/edit/{id}")]
@ -78,7 +78,8 @@ pub async fn post_edit(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{endpoints::user::NewOrEditUserForm, models::*, utils::test_helper::*}; use crate::{endpoints::user::NewOrEditUserForm, utils::test_helper::*};
use brass_db::models::*;
use brass_macros::db_test; use brass_macros::db_test;
use fake::{ use fake::{
faker::{internet::en::SafeEmail, name::en::Name}, faker::{internet::en::SafeEmail, name::en::Name},

View File

@ -1,9 +1,10 @@
use actix_identity::Identity; use actix_identity::Identity;
use actix_web::{web, HttpMessage, HttpRequest, HttpResponse, Responder}; use actix_web::{web, HttpMessage, HttpRequest, HttpResponse, Responder};
use brass_db::models::User;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{models::User, utils::auth::hash_plain_password_with_salt}; use crate::utils::auth::hash_plain_password_with_salt;
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct LoginForm { pub struct LoginForm {

View File

@ -1,11 +1,10 @@
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder}; use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::user::NewOrEditUserForm, mail::Mailer, utils::ApplicationError};
endpoints::user::NewOrEditUserForm, use brass_db::{
mail::Mailer,
models::{Function, Registration, Role, User, UserChangeset}, models::{Function, Registration, Role, User, UserChangeset},
utils::{validation::{AsyncValidate, DbContext}, ApplicationError}, validation::{AsyncValidate, DbContext},
}; };
#[actix_web::post("/users/new")] #[actix_web::post("/users/new")]

View File

@ -3,10 +3,8 @@ use maud::html;
use serde::Deserialize; use serde::Deserialize;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::{password_change::PasswordChangeBuilder, ApplicationError};
models::Registration, use brass_db::models::Registration;
utils::{password_change::PasswordChangeBuilder, ApplicationError},
};
#[derive(Deserialize)] #[derive(Deserialize)]
struct RegisterForm { struct RegisterForm {

View File

@ -2,12 +2,8 @@ use actix_web::{web, HttpResponse, Responder};
use serde_json::json; use serde_json::json;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::IdPath, mail::Mailer, utils::ApplicationError};
endpoints::IdPath, use brass_db::models::{Registration, Role, User};
mail::Mailer,
models::{Registration, Role, User},
utils::ApplicationError,
};
#[actix_web::post("/users/{id}/resend-registration")] #[actix_web::post("/users/{id}/resend-registration")]
pub async fn post( pub async fn post(

View File

@ -5,9 +5,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
mail::Mailer, mail::Mailer,
models::{PasswordReset, User},
utils::{password_change::PasswordChangeBuilder, ApplicationError}, utils::{password_change::PasswordChangeBuilder, ApplicationError},
}; };
use brass_db::models::{PasswordReset, User};
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
struct ResetPasswordForm { struct ResetPasswordForm {

View File

@ -2,12 +2,8 @@ use actix_web::{web, HttpResponse, Responder};
use askama::Template; use askama::Template;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::IdPath, filters, utils::ApplicationError};
endpoints::IdPath, use brass_db::models::{Role, User};
filters,
models::{Role, User},
utils::ApplicationError,
};
#[derive(Template, Debug)] #[derive(Template, Debug)]
#[template(path = "user/overview_locked_td.html")] #[template(path = "user/overview_locked_td.html")]
@ -86,12 +82,10 @@ async fn handle_lock_state_for_user(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::utils::test_helper::{
models::{Area, Function, Role, User}, assert_snapshot, read_body, test_put, DbTestContext, RequestConfig, StatusCode,
utils::test_helper::{
assert_snapshot, read_body, test_put, DbTestContext, RequestConfig, StatusCode,
},
}; };
use brass_db::models::{Area, Function, Role, User};
use brass_macros::db_test; use brass_macros::db_test;
use fake::{Fake, Faker}; use fake::{Fake, Faker};

View File

@ -7,9 +7,9 @@ use tracing::error;
use crate::{ use crate::{
endpoints::IdPath, endpoints::IdPath,
filters, filters,
models::User,
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::User;
#[derive(Template)] #[derive(Template)]
#[template(path = "user/profile.html", block = "notificationinput")] #[template(path = "user/profile.html", block = "notificationinput")]

View File

@ -1,11 +1,8 @@
use actix_web::{web, HttpResponse, Responder}; use actix_web::{web, HttpResponse, Responder};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::IdPath, utils::ApplicationError};
endpoints::IdPath, use brass_db::models::{Role, User, Vehicle};
models::{Role, User, Vehicle},
utils::ApplicationError,
};
#[actix_web::delete("/vehicles/{id}")] #[actix_web::delete("/vehicles/{id}")]
pub async fn delete( pub async fn delete(
@ -28,10 +25,8 @@ pub async fn delete(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::utils::test_helper::{test_delete, DbTestContext, RequestConfig, StatusCode};
models::{Function, Role, Vehicle}, use brass_db::models::{Function, Role, Vehicle};
utils::test_helper::{test_delete, DbTestContext, RequestConfig, StatusCode},
};
use brass_macros::db_test; use brass_macros::db_test;
#[db_test] #[db_test]

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{vehicle::VehicleNewOrEditTemplate, IdPath}, endpoints::{vehicle::VehicleNewOrEditTemplate, IdPath},
models::{Role, User, Vehicle},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Role, User, Vehicle};
#[actix_web::get("/vehicles/{id}")] #[actix_web::get("/vehicles/{id}")]
pub async fn get( pub async fn get(
@ -31,12 +31,10 @@ pub async fn get(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::utils::test_helper::{
models::{Function, Role, Vehicle}, assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
utils::test_helper::{
assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
},
}; };
use brass_db::models::{Role, Function, Vehicle};
use brass_macros::db_test; use brass_macros::db_test;
#[db_test] #[db_test]

View File

@ -2,9 +2,9 @@ use actix_web::{web, Responder};
use crate::{ use crate::{
endpoints::vehicle::VehicleNewOrEditTemplate, endpoints::vehicle::VehicleNewOrEditTemplate,
models::{Role, User},
utils::{ApplicationError, TemplateResponse}, utils::{ApplicationError, TemplateResponse},
}; };
use brass_db::models::{Role, User};
#[actix_web::get("/vehicles/new")] #[actix_web::get("/vehicles/new")]
pub async fn get(user: web::ReqData<User>) -> Result<impl Responder, ApplicationError> { pub async fn get(user: web::ReqData<User>) -> Result<impl Responder, ApplicationError> {
@ -22,12 +22,10 @@ pub async fn get(user: web::ReqData<User>) -> Result<impl Responder, Application
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::utils::test_helper::{
models::{Function, Role}, assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
utils::test_helper::{
assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
},
}; };
use brass_db::models::{Function, Role};
use brass_macros::db_test; use brass_macros::db_test;
#[db_test] #[db_test]

View File

@ -2,10 +2,8 @@ use actix_web::{web, Responder};
use askama::Template; use askama::Template;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::utils::{ApplicationError, TemplateResponse};
models::{Role, User, Vehicle}, use brass_db::models::{Role, User, Vehicle};
utils::{ApplicationError, TemplateResponse},
};
#[derive(Template)] #[derive(Template)]
#[cfg_attr(not(test), template(path = "vehicles/overview.html"))] #[cfg_attr(not(test), template(path = "vehicles/overview.html"))]
@ -40,12 +38,10 @@ pub async fn get(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::utils::test_helper::{
models::{Function, Role, Vehicle}, assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
utils::test_helper::{
assert_snapshot, read_body, test_get, DbTestContext, RequestConfig, StatusCode,
},
}; };
use brass_db::models::{Role, User, Vehicle};
use brass_macros::db_test; use brass_macros::db_test;
#[db_test] #[db_test]
@ -62,12 +58,7 @@ mod tests {
async fn area_manager_can_view_overview(context: &DbTestContext) { async fn area_manager_can_view_overview(context: &DbTestContext) {
let app = context.app().await; let app = context.app().await;
let config = RequestConfig { let config = RequestConfig::new("/vehicles").with_role(Role::AreaManager);
uri: "/vehicles".to_string(),
role: Role::AreaManager,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_get(&context.db_pool, &app, &config).await; let response = test_get(&context.db_pool, &app, &config).await;
assert_eq!(StatusCode::OK, response.status()); assert_eq!(StatusCode::OK, response.status());
@ -80,12 +71,7 @@ mod tests {
.await .await
.unwrap(); .unwrap();
let config = RequestConfig { let config = RequestConfig::new("/vehicles").with_role(Role::Admin);
uri: "/vehicles".to_string(),
role: Role::Admin,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_get(&context.db_pool, &app, &config).await; let response = test_get(&context.db_pool, &app, &config).await;
assert_eq!(StatusCode::OK, response.status()); assert_eq!(StatusCode::OK, response.status());

View File

@ -1,7 +1,7 @@
use askama::Template; use askama::Template;
use serde::Deserialize; use serde::Deserialize;
use crate::models::{Role, User, Vehicle}; use brass_db::models::{Role, User, Vehicle};
pub mod delete; pub mod delete;
pub mod get_edit; pub mod get_edit;

View File

@ -3,9 +3,9 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::{vehicle::VehicleForm, IdPath}, endpoints::{vehicle::VehicleForm, IdPath},
models::{Role, User, Vehicle},
utils::ApplicationError, utils::ApplicationError,
}; };
use brass_db::models::{Role, User, Vehicle};
#[actix_web::post("/vehicles/{id}")] #[actix_web::post("/vehicles/{id}")]
pub async fn post( pub async fn post(
@ -41,11 +41,11 @@ pub async fn post(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use actix_http::StatusCode; use actix_http::StatusCode;
use brass_db::models::{Role, Vehicle};
use brass_macros::db_test; use brass_macros::db_test;
use crate::{ use crate::{
endpoints::vehicle::VehicleForm, endpoints::vehicle::VehicleForm,
models::{Role, Vehicle},
utils::test_helper::{test_post, DbTestContext, RequestConfig}, utils::test_helper::{test_post, DbTestContext, RequestConfig},
}; };

View File

@ -1,11 +1,8 @@
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder}; use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{ use crate::{endpoints::vehicle::VehicleForm, utils::ApplicationError};
endpoints::vehicle::VehicleForm, use brass_db::models::{Role, User, Vehicle};
models::{Role, User, Vehicle},
utils::ApplicationError,
};
#[actix_web::post("/vehicles/new")] #[actix_web::post("/vehicles/new")]
pub async fn post( pub async fn post(
@ -28,11 +25,11 @@ pub async fn post(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use actix_http::StatusCode; use actix_http::StatusCode;
use brass_db::models::{Role, Vehicle};
use brass_macros::db_test; use brass_macros::db_test;
use crate::{ use crate::{
endpoints::vehicle::VehicleForm, endpoints::vehicle::VehicleForm,
models::{Role, Vehicle},
utils::test_helper::{test_post, DbTestContext, RequestConfig}, utils::test_helper::{test_post, DbTestContext, RequestConfig},
}; };

View File

@ -4,12 +4,12 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::vehicle_assignment::PlanVehiclesPartialTemplate, endpoints::vehicle_assignment::PlanVehiclesPartialTemplate,
models::{Event, Role, User, VehicleAssignment},
utils::{ utils::{
event_planning_template::generate_vehicles_assigned_and_available, ApplicationError, event_planning_template::generate_vehicles_assigned_and_available, ApplicationError,
TemplateResponse, TemplateResponse,
}, },
}; };
use brass_db::models::{Event, Role, User, VehicleAssignment};
#[derive(Deserialize)] #[derive(Deserialize)]
struct VehicleAssignmentDeleteQuery { struct VehicleAssignmentDeleteQuery {

View File

@ -1,9 +1,9 @@
use askama::Template; use askama::Template;
use crate::models::{Event, Vehicle}; use brass_db::models::{Event, Vehicle};
pub mod post_new;
pub mod delete; pub mod delete;
pub mod post_new;
#[derive(Template)] #[derive(Template)]
#[template(path = "events/plan_vehicles.html")] #[template(path = "events/plan_vehicles.html")]

View File

@ -4,12 +4,12 @@ use sqlx::PgPool;
use crate::{ use crate::{
endpoints::vehicle_assignment::PlanVehiclesPartialTemplate, endpoints::vehicle_assignment::PlanVehiclesPartialTemplate,
models::{Event, Role, User, Vehicle, VehicleAssignment},
utils::{ utils::{
event_planning_template::generate_vehicles_assigned_and_available, ApplicationError, event_planning_template::generate_vehicles_assigned_and_available, ApplicationError,
TemplateResponse, TemplateResponse,
}, },
}; };
use brass_db::models::{Event, Role, User, Vehicle, VehicleAssignment};
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct VehicleAssignmentQuery { pub struct VehicleAssignmentQuery {
@ -65,8 +65,7 @@ pub async fn post(
.body("Vehicle already assigned to a timely conflicting event.")); .body("Vehicle already assigned to a timely conflicting event."));
} }
VehicleAssignment::create(pool.get_ref(), event.id, vehicle.id, event.start, event.end) VehicleAssignment::create(pool.get_ref(), event.id, vehicle.id, event.start, event.end).await?;
.await?;
let (vehicles_assigned, vehicles_available) = let (vehicles_assigned, vehicles_available) =
generate_vehicles_assigned_and_available(pool.get_ref(), &event).await?; generate_vehicles_assigned_and_available(pool.get_ref(), &event).await?;

View File

@ -4,7 +4,8 @@ use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use maud::html; use maud::html;
use tracing::trace; use tracing::trace;
use crate::{models::UserFunction, utils::DateTimeFormat}; use crate::utils::DateTimeFormat;
use brass_db::models::UserFunction;
pub fn show_area_query(a: &Option<i32>, first: bool) -> askama::Result<String> { pub fn show_area_query(a: &Option<i32>, first: bool) -> askama::Result<String> {
let char = if first { '?' } else { '&' }; let char = if first { '?' } else { '&' };
@ -77,21 +78,30 @@ pub fn show_tree(f: &UserFunction) -> askama::Result<String> {
pub fn fmt_date(v: &NaiveDate, format: DateTimeFormat) -> askama::Result<String> { pub fn fmt_date(v: &NaiveDate, format: DateTimeFormat) -> askama::Result<String> {
let format_string = format.into(); let format_string = format.into();
trace!(format=format_string, "formatting naivedate into string with format"); trace!(
format = format_string,
"formatting naivedate into string with format"
);
Ok(v.format(format_string).to_string()) Ok(v.format(format_string).to_string())
} }
pub fn fmt_datetime(v: &NaiveDateTime, format: DateTimeFormat) -> askama::Result<String> { pub fn fmt_datetime(v: &NaiveDateTime, format: DateTimeFormat) -> askama::Result<String> {
let format_string = format.into(); let format_string = format.into();
trace!(format=format_string, "formatting naivedatetime into string with format"); trace!(
format = format_string,
"formatting naivedatetime into string with format"
);
Ok(v.format(format_string).to_string()) Ok(v.format(format_string).to_string())
} }
pub fn fmt_time(v: &NaiveTime, format: DateTimeFormat) -> askama::Result<String> { pub fn fmt_time(v: &NaiveTime, format: DateTimeFormat) -> askama::Result<String> {
let format_string = format.into(); let format_string = format.into();
trace!(format=format_string, "formatting naivetime into string with format"); trace!(
format = format_string,
"formatting naivetime into string with format"
);
Ok(v.format(format_string).to_string()) Ok(v.format(format_string).to_string())
} }

View File

@ -4,7 +4,8 @@ use lettre::{
Address, AsyncTransport, Message, Address, AsyncTransport, Message,
}; };
use crate::{models::User, utils::ApplicationError}; use crate::utils::ApplicationError;
use brass_db::models::User;
use super::Mailer; use super::Mailer;

Some files were not shown because too many files have changed in this diff Show More