refactor: WIP rework of function system

This commit is contained in:
Max Hohlfeld 2025-03-10 22:37:15 +01:00
parent a5344adb73
commit 4508150e30
40 changed files with 319 additions and 190 deletions

View File

@ -28,6 +28,10 @@
}
},
{
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -38,6 +42,9 @@
]
}
}
}
}
}
},
"Int4"
]

View File

@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id,\n name,\n email,\n password,\n salt,\n role AS \"role: Role\",\n function AS \"function: Function\",\n areaId,\n locked,\n lastLogin,\n receiveNotifications\n FROM user_\n WHERE id = $1;\n ",
"query": "\n SELECT id,\n name,\n email,\n password,\n salt,\n role AS \"role: Role\",\n function AS \"function: Functions\",\n areaId,\n locked,\n lastLogin,\n receiveNotifications\n FROM user_\n WHERE areaId = $1;\n ",
"describe": {
"columns": [
{
@ -46,8 +46,12 @@
},
{
"ordinal": 6,
"name": "function: Function",
"name": "function: Functions",
"type_info": {
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -59,6 +63,9 @@
}
}
}
}
}
}
},
{
"ordinal": 7,
@ -100,5 +107,5 @@
false
]
},
"hash": "3338639844455180fdc70262cb982042ee2ff5cc8ab0fd6101bf5d4182f58530"
"hash": "4da130f5ff77ea010db74c51e5dfc966aeae7ff1c4fa44395a0136bbd4a760c5"
}

View File

@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n availabillity.id,\n availabillity.userId,\n availabillity.date,\n availabillity.startTime,\n availabillity.endTime,\n availabillity.comment,\n user_.name,\n user_.email,\n user_.password,\n user_.salt,\n user_.role AS \"role: Role\",\n user_.function AS \"function: Function\",\n user_.areaId,\n user_.locked,\n user_.lastLogin,\n user_.receiveNotifications,\n area.name AS areaName\n FROM availabillity\n JOIN user_ ON availabillity.userId = user_.id\n JOIN area ON user_.areaId = area.id\n WHERE user_.areaId = $1 AND\n availabillity.date >= $2 AND\n availabillity.date <= $3;\n ",
"query": "\n SELECT\n availabillity.id,\n availabillity.userId,\n availabillity.date,\n availabillity.startTime,\n availabillity.endTime,\n availabillity.comment,\n user_.name,\n user_.email,\n user_.password,\n user_.salt,\n user_.role AS \"role: Role\",\n user_.function AS \"function: Functions\",\n user_.areaId,\n user_.locked,\n user_.lastLogin,\n user_.receiveNotifications,\n area.name AS areaName\n FROM availabillity\n JOIN user_ ON availabillity.userId = user_.id\n JOIN area ON user_.areaId = area.id\n WHERE user_.areaId = $1 AND\n availabillity.date >= $2 AND\n availabillity.date <= $3;\n ",
"describe": {
"columns": [
{
@ -71,8 +71,12 @@
},
{
"ordinal": 11,
"name": "function: Function",
"name": "function: Functions",
"type_info": {
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -84,6 +88,9 @@
}
}
}
}
}
}
},
{
"ordinal": 12,
@ -138,5 +145,5 @@
false
]
},
"hash": "d3705fa03f98a5b83c65e29fe98d8c6015dfbff58460b420b9634bf2a0e38e4e"
"hash": "6adecc71eae15d0ef809e16cfedf42ab8ec9c1e0c7eb423c0eee5be56f6ddf26"
}

View File

@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n availabillity.id,\n availabillity.userId,\n availabillity.date,\n availabillity.startTime,\n availabillity.endTime,\n availabillity.comment,\n user_.name,\n user_.email,\n user_.password,\n user_.salt,\n user_.role AS \"role: Role\",\n user_.function AS \"function: Function\",\n user_.areaId,\n user_.locked,\n user_.lastLogin,\n user_.receiveNotifications\n FROM availabillity\n JOIN user_ ON availabillity.userId = user_.id\n WHERE availabillity.date = $1\n AND user_.areaId = $2;\n ",
"query": "\n SELECT\n availabillity.id,\n availabillity.userId,\n availabillity.date,\n availabillity.startTime,\n availabillity.endTime,\n availabillity.comment,\n user_.name,\n user_.email,\n user_.password,\n user_.salt,\n user_.role AS \"role: Role\",\n user_.function AS \"function: Functions\",\n user_.areaId,\n user_.locked,\n user_.lastLogin,\n user_.receiveNotifications\n FROM availabillity\n JOIN user_ ON availabillity.userId = user_.id\n WHERE availabillity.date = $1\n AND user_.areaId = $2;\n ",
"describe": {
"columns": [
{
@ -71,8 +71,12 @@
},
{
"ordinal": 11,
"name": "function: Function",
"name": "function: Functions",
"type_info": {
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -84,6 +88,9 @@
}
}
}
}
}
}
},
{
"ordinal": 12,
@ -131,5 +138,5 @@
false
]
},
"hash": "a1288bdb944dc72d5591d8686f533d124d9edacaf62539f7908c797efe44a68d"
"hash": "a2ff81071585a31385044f022553dc1e5f81fd3727f47825991adcfae5546324"
}

View File

@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id,\n name,\n email,\n password,\n salt,\n role AS \"role: Role\",\n function AS \"function: Function\",\n areaId,\n locked,\n lastLogin,\n receiveNotifications\n FROM user_;\n ",
"query": "\n SELECT id,\n name,\n email,\n password,\n salt,\n role AS \"role: Role\",\n function AS \"function: Functions\",\n areaId,\n locked,\n lastLogin,\n receiveNotifications\n FROM user_;\n ",
"describe": {
"columns": [
{
@ -46,8 +46,12 @@
},
{
"ordinal": 6,
"name": "function: Function",
"name": "function: Functions",
"type_info": {
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -59,6 +63,9 @@
}
}
}
}
}
}
},
{
"ordinal": 7,
@ -98,5 +105,5 @@
false
]
},
"hash": "1d5bf64843b684258fcce0e606ea01a2037890ac736b7344e0008eae2b2a7ef6"
"hash": "aa60c8e32c6c226f0b2f9161fd27bc9bf986cb7a69a7f5449c10a1b5642d9360"
}

View File

@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id,\n name,\n email,\n password,\n salt,\n role AS \"role: Role\",\n function AS \"function: Function\",\n areaId,\n locked,\n lastLogin,\n receiveNotifications\n FROM user_\n WHERE areaId = $1;\n ",
"query": "\n SELECT id,\n name,\n email,\n password,\n salt,\n role AS \"role: Role\",\n function AS \"function: Functions\",\n areaId,\n locked,\n lastLogin,\n receiveNotifications\n FROM user_\n WHERE id = $1;\n ",
"describe": {
"columns": [
{
@ -46,8 +46,12 @@
},
{
"ordinal": 6,
"name": "function: Function",
"name": "function: Functions",
"type_info": {
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -59,6 +63,9 @@
}
}
}
}
}
}
},
{
"ordinal": 7,
@ -100,5 +107,5 @@
false
]
},
"hash": "82a9b85a96c255c1bc0728ac6d3b4debcbbe0dbdf4b75e585d8e0f44fbd7a982"
"hash": "abcd0f243fc7b93ea20c4dbd3c9b18ada4dc45893dd2f8f25873cb6819ee986e"
}

View File

@ -26,6 +26,10 @@
}
},
{
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -36,6 +40,9 @@
]
}
}
}
}
}
},
"Int4"
]

View File

@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n availabillity.id,\n availabillity.userId,\n availabillity.date,\n availabillity.startTime,\n availabillity.endTime,\n availabillity.comment,\n user_.name,\n user_.email,\n user_.password,\n user_.salt,\n user_.role AS \"role: Role\",\n user_.function AS \"function: Function\",\n user_.areaId,\n user_.locked,\n user_.lastLogin,\n user_.receiveNotifications\n FROM availabillity\n LEFT JOIN assignment ON availabillity.Id = assignment.availabillityId\n JOIN user_ ON availabillity.userId = user_.id\n WHERE availabillity.id = $1;\n ",
"query": "\n SELECT\n availabillity.id,\n availabillity.userId,\n availabillity.date,\n availabillity.startTime,\n availabillity.endTime,\n availabillity.comment,\n user_.name,\n user_.email,\n user_.password,\n user_.salt,\n user_.role AS \"role: Role\",\n user_.function AS \"function: Functions\",\n user_.areaId,\n user_.locked,\n user_.lastLogin,\n user_.receiveNotifications\n FROM availabillity\n LEFT JOIN assignment ON availabillity.Id = assignment.availabillityId\n JOIN user_ ON availabillity.userId = user_.id\n WHERE availabillity.id = $1;\n ",
"describe": {
"columns": [
{
@ -71,8 +71,12 @@
},
{
"ordinal": 11,
"name": "function: Function",
"name": "function: Functions",
"type_info": {
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -84,6 +88,9 @@
}
}
}
}
}
}
},
{
"ordinal": 12,
@ -130,5 +137,5 @@
false
]
},
"hash": "f48192661c91b4f48bb46f8ea5d60911ddeafc408d3a897dd4ab1b45fe06dd4d"
"hash": "b06a1cfc8ba53c2f95ed5b74e9b6d73e723750b3679e2dbe970ed03e01886c90"
}

View File

@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n user_.id AS userId,\n user_.name,\n user_.email,\n user_.password,\n user_.salt,\n user_.role AS \"role: Role\",\n user_.function AS \"function: Function\",\n user_.areaId,\n user_.locked,\n user_.lastLogin,\n user_.receiveNotifications,\n area.id,\n area.name AS areaName\n FROM user_\n JOIN area ON user_.areaId = area.id\n ",
"query": "\n SELECT\n user_.id AS userId,\n user_.name,\n user_.email,\n user_.password,\n user_.salt,\n user_.role AS \"role: Role\",\n function AS \"function: Functions\",\n user_.areaId,\n user_.locked,\n user_.lastLogin,\n user_.receiveNotifications,\n area.id,\n area.name AS areaName\n FROM user_\n JOIN area ON user_.areaId = area.id\n ",
"describe": {
"columns": [
{
@ -46,8 +46,12 @@
},
{
"ordinal": 6,
"name": "function: Function",
"name": "function: Functions",
"type_info": {
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -59,6 +63,9 @@
}
}
}
}
}
}
},
{
"ordinal": 7,
@ -110,5 +117,5 @@
false
]
},
"hash": "2defbc675e894d30483e057d78344490b06c3cd5b3b3ab474ef755b67d4b6ea0"
"hash": "cd25453504b28008dbe82aa89e8d942ad500b61beb640d2af9030872de069fb6"
}

View File

@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id,\n name,\n email,\n password,\n salt,\n role AS \"role: Role\",\n function AS \"function: Function\",\n areaId,\n locked,\n lastLogin,\n receiveNotifications\n FROM user_\n WHERE email = $1 AND locked = FALSE AND password IS NOT NULL AND salt IS NOT NULL;\n ",
"query": "\n SELECT id,\n name,\n email,\n password,\n salt,\n role AS \"role: Role\",\n function AS \"function: Functions\",\n areaId,\n locked,\n lastLogin,\n receiveNotifications\n FROM user_\n WHERE email = $1 AND locked = FALSE AND password IS NOT NULL AND salt IS NOT NULL;\n ",
"describe": {
"columns": [
{
@ -46,8 +46,12 @@
},
{
"ordinal": 6,
"name": "function: Function",
"name": "function: Functions",
"type_info": {
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -59,6 +63,9 @@
}
}
}
}
}
}
},
{
"ordinal": 7,
@ -100,5 +107,5 @@
false
]
},
"hash": "76bf18e05733214925ddd0cbe090a69f839c140377f043ca8181cd9a0af5e70e"
"hash": "db1a44c82fca70aa0a0530a07b75bd2a596a16deb60ca89fedb26c8ad89dbdce"
}

View File

@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n availabillity.id,\n availabillity.userId,\n availabillity.date,\n availabillity.startTime,\n availabillity.endTime,\n availabillity.comment,\n user_.name,\n user_.email,\n user_.password,\n user_.salt,\n user_.role AS \"role: Role\",\n user_.function AS \"function: Function\",\n user_.areaId,\n user_.locked,\n user_.lastLogin,\n user_.receiveNotifications\n FROM availabillity\n JOIN user_ ON availabillity.userId = user_.id\n WHERE availabillity.date = $1\n AND user_.areaId = $2\n AND ((availabillity.startTime IS NULL AND availabillity.endTime IS NULL)\n OR (availabillity.startTime <= $3 AND availabillity.endTime >= $4));\n ",
"query": "\n SELECT\n availabillity.id,\n availabillity.userId,\n availabillity.date,\n availabillity.startTime,\n availabillity.endTime,\n availabillity.comment,\n user_.name,\n user_.email,\n user_.password,\n user_.salt,\n user_.role AS \"role: Role\",\n user_.function AS \"function: Functions\",\n user_.areaId,\n user_.locked,\n user_.lastLogin,\n user_.receiveNotifications\n FROM availabillity\n JOIN user_ ON availabillity.userId = user_.id\n WHERE availabillity.date = $1\n AND user_.areaId = $2\n AND ((availabillity.startTime IS NULL AND availabillity.endTime IS NULL)\n OR (availabillity.startTime <= $3 AND availabillity.endTime >= $4));\n ",
"describe": {
"columns": [
{
@ -71,8 +71,12 @@
},
{
"ordinal": 11,
"name": "function: Function",
"name": "function: Functions",
"type_info": {
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -84,6 +88,9 @@
}
}
}
}
}
}
},
{
"ordinal": 12,
@ -133,5 +140,5 @@
false
]
},
"hash": "e5c0fdebea352e78f5d34fd0774f8802090ce15f811d1b2506ff8bc12fe8fad9"
"hash": "efe07f8477c7416eae9c0b433cf24b7dc8abf38ce56c0ad46039a5bbbdd6865b"
}

View File

@ -20,6 +20,10 @@
}
},
{
"Custom": {
"name": "function[]",
"kind": {
"Array": {
"Custom": {
"name": "function",
"kind": {
@ -30,6 +34,9 @@
]
}
}
}
}
}
},
"Int4",
"Int4"

View File

@ -24,7 +24,7 @@ CREATE TABLE user_
password TEXT ,
salt TEXT ,
role role NOT NULL,
function function NOT NULL,
function function ARRAY NOT NULL,
areaId INTEGER NOT NULL REFERENCES area (id) ON DELETE CASCADE,
locked BOOLEAN NOT NULL DEFAULT false,
lastLogin TIMESTAMP WITH TIME ZONE,

View File

@ -48,7 +48,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/delete/2".to_string(),
role: Role::Admin,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_delete(&context.db_pool, app, &config).await;
@ -75,7 +75,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/delete/2".to_string(),
role: Role::Admin,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_delete(&context.db_pool, app, &config).await;
@ -97,7 +97,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/delete/2".to_string(),
role: Role::Admin,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_delete(&context.db_pool, app, &config).await;

View File

@ -46,7 +46,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/edit/1".to_string(),
role: Role::Admin,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_get(&context.db_pool, app, &config).await;
@ -64,7 +64,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/edit/1".to_string(),
role: Role::AreaManager,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_get(&context.db_pool, app, &config).await;
@ -79,7 +79,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/edit/2".to_string(),
role: Role::Admin,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_get(&context.db_pool, app, &config).await;

View File

@ -35,7 +35,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/new".to_string(),
role: Role::Admin,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_get(&context.db_pool, app, &config).await;
@ -53,7 +53,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/new".to_string(),
role: Role::AreaManager,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
let response = test_get(&context.db_pool, app, &config).await;

View File

@ -50,7 +50,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/edit/1".to_string(),
role: Role::Admin,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
@ -77,7 +77,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/edit/1".to_string(),
role: Role::AreaManager,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
@ -97,7 +97,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/edit/2".to_string(),
role: Role::Admin,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};

View File

@ -43,7 +43,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/new".to_string(),
role: Role::Admin,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
@ -70,7 +70,7 @@ mod tests {
let config = RequestConfig {
uri: "/area/new".to_string(),
role: Role::AreaManager,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};

View File

@ -2,7 +2,7 @@ use rinja::Template;
use crate::{
filters,
models::{Availability, AvailabilityTime, AvailabillityAssignmentState, Event, Function},
models::{Availability, AvailabilityTime, AvailabillityAssignmentState, Event},
};
pub mod delete;

View File

@ -70,7 +70,7 @@ pub async fn post(
let context = AssignmentContext {
event: event.clone(),
availabillity: availabillity.clone(),
user_function: availabillity.user.as_ref().unwrap().function,
user_function: availabillity.user.as_ref().unwrap().function.clone(),
assignments_for_event,
assignments_for_availabillity,
};

View File

@ -106,7 +106,7 @@ async fn produces_template(context: &DbTestContext) {
let config = RequestConfig {
uri: "/events/1/edit".to_string(),
role: Role::Admin,
function: crate::models::Function::Posten,
function: vec![crate::models::Function::Posten],
user_area: 1,
};
let response = test_get(&context.db_pool, app, &config).await;

View File

@ -5,7 +5,7 @@ use sqlx::PgPool;
use crate::{
endpoints::IdPath,
filters,
models::{Availability, AvailabilityTime, AvailabillityAssignmentState, Event, Function, Role, User, Vehicle},
models::{Availability, AvailabilityTime, AvailabillityAssignmentState, Event, Role, User, Vehicle},
utils::{
event_planning_template::{
generate_availabillity_assignment_list, generate_status_whether_staff_is_required,

View File

@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use crate::{
models::{Area, Availability, AvailabilityTime, Function, Role, User},
models::{Area, Availability, AvailabilityTime, Functions, Role, User},
utils::ApplicationError,
END_OF_DAY, START_OF_DAY,
};
@ -33,7 +33,7 @@ struct Export {
struct ExportAvailabillity {
name: String,
area: String,
function: Function,
function: Functions,
date: NaiveDate,
whole_day: bool,
start_time: NaiveTime,

View File

@ -41,7 +41,7 @@ async fn works_when_user_is_admin(context: &DbTestContext) {
let config = RequestConfig {
uri: "/locations/new".to_string(),
role: Role::Admin,
function: crate::models::Function::Posten,
function: vec![crate::models::Function::Posten],
user_area: 1,
};
@ -69,7 +69,7 @@ async fn uses_area_id_of_area_manager(context: &DbTestContext) {
let config = RequestConfig {
uri: "/locations/new".to_string(),
role: Role::AreaManager,
function: crate::models::Function::Posten,
function: vec![crate::models::Function::Posten],
user_area: 1,
};

View File

@ -34,7 +34,9 @@ pub async fn get_edit(
email: Some(user_in_db.email),
name: Some(user_in_db.name),
role: Some(user_in_db.role as u8),
function: Some(user_in_db.function as u8),
is_posten: Some(user_in_db.function.is_posten()),
is_wachhabender: Some(user_in_db.function.is_wachhabender()),
is_fuehrungsassistent: Some(user_in_db.function.is_fuehrungsassistent()),
area_id: Some(user_in_db.area_id),
};

View File

@ -25,7 +25,9 @@ pub async fn get_new(
email: None,
name: None,
role: None,
function: None,
is_posten: None,
is_wachhabender: None,
is_fuehrungsassistent: None,
area_id: None,
};

View File

@ -1,5 +1,6 @@
use crate::{
models::{Area, Function, Role, User},
filters,
models::{Area, Role, User},
utils::{ApplicationError, TemplateResponse},
};

View File

@ -39,7 +39,9 @@ pub struct NewOrEditUserTemplate {
email: Option<String>,
name: Option<String>,
role: Option<u8>,
function: Option<u8>,
is_posten: Option<bool>,
is_wachhabender: Option<bool>,
is_fuehrungsassistent: Option<bool>,
area_id: Option<i32>,
}

View File

@ -87,7 +87,7 @@ mod tests {
let config = RequestConfig {
uri: "/users/edit/1".to_string(),
role: Role::Admin,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};
@ -113,7 +113,7 @@ mod tests {
assert_eq!(new_name, updated_user.name);
assert_eq!(new_mail, updated_user.email);
assert_eq!(Role::AreaManager, updated_user.role);
assert_eq!(Function::Fuehrungsassistent, updated_user.function);
assert!(updated_user.function.is_fuehrungsassistent());
assert_eq!(2, updated_user.area_id);
}
@ -123,7 +123,7 @@ mod tests {
let config = RequestConfig {
uri: "/users/edit/1".to_string(),
role: Role::Admin,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
};

View File

@ -1,6 +1,6 @@
use maud::html;
use crate::models::Function;
use crate::models::Functions;
pub fn show_area_query(a: &Option<i32>, first: bool) -> rinja::Result<String> {
let char = if first { '?' } else { '&' };
@ -40,15 +40,17 @@ pub fn invert(b: &bool) -> rinja::Result<bool> {
Ok(!b)
}
pub fn show_tree(f: &Function) -> rinja::Result<String> {
pub fn show_tree(f: &Functions) -> rinja::Result<String> {
let html = html! {
div class="tags" {
@if f.is_posten() {
span class="tag is-primary is-light" { "Posten"}
@if *f == Function::Fuehrungsassistent || *f == Function::Wachhabender {
span class="tag is-primary has-background-primary-85 has-text-primary-85-invert" { "Führungsassistent"}
}
@if *f == Function::Wachhabender {
span class="tag is-primary" { "Wachhabender"}
@if f.is_wachhabender() {
span class="tag is-primary has-background-primary-85 has-text-primary-85-invert" { "Wachhabender"}
}
@if f.is_fuehrungsassistent() {
span class="tag is-primary" { "Führungsassistent"}
}
}
};

View File

@ -2,7 +2,7 @@ use chrono::NaiveTime;
use garde::Validate;
use super::{
start_time_lies_before_end_time, Assignment, Availability, AvailabilityTime, Event, Function,
start_time_lies_before_end_time, Assignment, Availability, AvailabilityTime, Event, Function, Functions,
};
#[derive(Validate)]
@ -26,7 +26,7 @@ pub struct AssignmentChangeset {
pub struct AssignmentContext {
pub event: Event,
pub availabillity: Availability,
pub user_function: Function,
pub user_function: Functions,
pub assignments_for_event: Vec<Assignment>,
pub assignments_for_availabillity: Vec<Assignment>,
}
@ -50,7 +50,7 @@ fn user_of_availability_has_function(
value: &Function,
context: &AssignmentContext,
) -> garde::Result {
if *value > context.user_function {
if !context.user_function.contains(value) {
return Err(garde::Error::new(
"user has not the required function for this assignment",
));
@ -60,7 +60,7 @@ fn user_of_availability_has_function(
}
fn event_has_free_slot_for_function(
_value: &Function,
value: &Function,
context: &AssignmentContext,
) -> garde::Result {
let list: Vec<&Assignment> = context
@ -75,7 +75,7 @@ fn event_has_free_slot_for_function(
.iter()
.filter(|a| a.function == Function::Posten)
.count();
if match context.user_function {
if match *value {
Function::Posten => a >= context.event.amount_of_posten as usize,
Function::Fuehrungsassistent => context.event.voluntary_fuehrungsassistent && a >= 1,
Function::Wachhabender => context.event.voluntary_wachhabender && a >= 1,

View File

@ -3,7 +3,7 @@ use sqlx::{query, PgPool};
use crate::{END_OF_DAY, START_OF_DAY};
use super::{Area, AvailabilityChangeset, Function, Result, Role, User};
use super::{Area, AvailabilityChangeset, Functions, Result, Role, User};
#[derive(Clone, Debug)]
pub struct Availability {
@ -87,7 +87,7 @@ impl Availability {
user_.password,
user_.salt,
user_.role AS "role: Role",
user_.function AS "function: Function",
user_.function AS "function: Functions",
user_.areaId,
user_.locked,
user_.lastLogin,
@ -115,7 +115,7 @@ impl Availability {
password: r.password.clone(),
salt: r.salt.clone(),
role: r.role,
function: r.function,
function: r.function.clone(),
area_id: r.areaid,
area: None,
locked: r.locked,
@ -154,7 +154,7 @@ impl Availability {
user_.password,
user_.salt,
user_.role AS "role: Role",
user_.function AS "function: Function",
user_.function AS "function: Functions",
user_.areaId,
user_.locked,
user_.lastLogin,
@ -186,7 +186,7 @@ impl Availability {
password: r.password.clone(),
salt: r.salt.clone(),
role: r.role,
function: r.function,
function: r.function.clone(),
area_id: r.areaid,
area: None,
locked: r.locked,
@ -220,7 +220,7 @@ impl Availability {
user_.password,
user_.salt,
user_.role AS "role: Role",
user_.function AS "function: Function",
user_.function AS "function: Functions",
user_.areaId,
user_.locked,
user_.lastLogin,
@ -245,7 +245,7 @@ impl Availability {
password: r.password.clone(),
salt: r.salt.clone(),
role: r.role,
function: r.function,
function: r.function.clone(),
area_id: r.areaid,
area: None,
locked: r.locked,
@ -302,7 +302,7 @@ impl Availability {
user_.password,
user_.salt,
user_.role AS "role: Role",
user_.function AS "function: Function",
user_.function AS "function: Functions",
user_.areaId,
user_.locked,
user_.lastLogin,
@ -334,7 +334,7 @@ impl Availability {
password: r.password.clone(),
salt: r.salt.clone(),
role: r.role,
function: r.function,
function: r.function.clone(),
area_id: r.areaid,
area: Some(Area {
id: r.areaid,

View File

@ -1,6 +1,7 @@
use std::fmt::Display;
use serde::Serialize;
use sqlx::postgres::{PgHasArrayType, PgTypeInfo};
use crate::utils::ApplicationError;
@ -12,6 +13,54 @@ pub enum Function {
Wachhabender = 10,
}
#[derive(sqlx::Type, Debug, Clone, PartialEq, Eq, Serialize, PartialOrd, Ord)]
#[sqlx(no_pg_array)]
pub struct Functions(Vec<Function>);
//impl sqlx::Type<Postgres> for Functions {
// fn type_info() -> sqlx::postgres::PgTypeInfo {
// // Array type name is the name of the element type prefixed with `_`
// sqlx::postgres::PgTypeInfo::with_name("_functions")
// }
//}
impl PgHasArrayType for Functions {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::with_name("function[]")
}
}
impl Display for Functions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut iterator = self.0.iter().peekable();
while let Some(p) = iterator.next() {
write!(f, "{}", p.to_string());
if iterator.peek().is_some() {
write!(f, ", ");
}
}
todo!()
}
}
impl Functions {
pub fn contains(&self, f: &Function) -> bool {
self.0.contains(f)
}
pub fn is_posten(&self) -> bool {
self.0.contains(&Function::Posten)
}
pub fn is_fuehrungsassistent(&self) -> bool {
self.0.contains(&Function::Fuehrungsassistent)
}
pub fn is_wachhabender(&self) -> bool {
self.0.contains(&Function::Wachhabender)
}
}
impl Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {

View File

@ -28,7 +28,7 @@ pub use availabillity_assignment_state::AvailabillityAssignmentState;
use chrono::NaiveTime;
pub use event::Event;
pub use event_changeset::{EventChangeset, EventContext};
pub use function::Function;
pub use function::{Function, Functions};
pub use location::Location;
pub use password_reset::{NoneToken, PasswordReset, Token};
pub use registration::Registration;

View File

@ -1,7 +1,7 @@
use chrono::{DateTime, Utc};
use sqlx::PgPool;
use super::{Area, Function, Result, Role, UserChangeset};
use super::{function::Functions, Area, Function, Result, Role, UserChangeset};
#[derive(Clone, Debug)]
pub struct User {
@ -11,7 +11,7 @@ pub struct User {
pub password: Option<String>,
pub salt: Option<String>,
pub role: Role,
pub function: Function,
pub function: Functions,
pub area_id: i32,
pub area: Option<Area>,
pub locked: bool,
@ -45,7 +45,7 @@ impl User {
password: &str,
salt: &str,
role: Role,
function: Function,
function: &[Function],
area_id: i32,
) -> Result<i32> {
sqlx::query!(
@ -59,7 +59,7 @@ impl User {
password,
salt,
role as Role,
function as Function,
function as &[Function],
area_id
)
.fetch_one(pool)
@ -76,7 +76,7 @@ impl User {
password,
salt,
role AS "role: Role",
function AS "function: Function",
function AS "function: Functions",
areaId,
locked,
lastLogin,
@ -116,7 +116,7 @@ impl User {
password,
salt,
role AS "role: Role",
function AS "function: Function",
function AS "function: Functions",
areaId,
locked,
lastLogin,
@ -156,7 +156,7 @@ impl User {
password,
salt,
role AS "role: Role",
function AS "function: Function",
function AS "function: Functions",
areaId,
locked,
lastLogin,
@ -176,7 +176,7 @@ impl User {
password: record.password.clone(),
salt: record.salt.clone(),
role: record.role,
function: record.function,
function: record.function.clone(),
area_id: record.areaid,
area: None,
locked: record.locked,
@ -198,7 +198,7 @@ impl User {
user_.password,
user_.salt,
user_.role AS "role: Role",
user_.function AS "function: Function",
function AS "function: Functions",
user_.areaId,
user_.locked,
user_.lastLogin,
@ -221,7 +221,7 @@ impl User {
password: record.password.clone(),
salt: record.salt.clone(),
role: record.role,
function: record.function,
function: record.function.clone(),
area_id: record.areaid,
area: Some(Area {
id: record.areaid,
@ -245,7 +245,7 @@ impl User {
password,
salt,
role AS "role: Role",
function AS "function: Function",
function AS "function: Functions",
areaId,
locked,
lastLogin,
@ -267,7 +267,7 @@ impl User {
password: record.password.clone(),
salt: record.salt.clone(),
role: record.role,
function: record.function,
function: record.function.clone(),
area_id: record.areaid,
area: None,
locked: record.locked,

View File

@ -90,7 +90,7 @@ pub async fn handle_command(
&hash,
&salt,
Role::Admin,
Function::Wachhabender,
&[Function::Posten, Function::Wachhabender, Function::Fuehrungsassistent],
1,
)
.await?;

View File

@ -16,7 +16,7 @@ use sqlx::{Pool, Postgres};
pub struct RequestConfig {
pub uri: String,
pub role: Role,
pub function: Function,
pub function: Vec<Function>,
pub user_area: i32,
}
@ -25,7 +25,7 @@ impl RequestConfig {
Self {
uri: uri.to_string(),
role: Role::Staff,
function: Function::Posten,
function: vec![Function::Posten],
user_area: 1,
}
}
@ -50,7 +50,7 @@ where
&HASH,
&SALT,
config.role,
config.function,
&config.function,
config.user_area,
)
.await

View File

@ -71,13 +71,13 @@
hx-post="/assignments/new?event={{ event.id }}&availabillity={{ availabillity.id }}&function=1" {% if
!further_posten_required || status !=AvailabillityAssignmentState::Unassigned|ref %}disabled{% endif %}>
als Posten planen</a>
{% if u.function == Function::Wachhabender || u.function == Function::Fuehrungsassistent %}
{% if u.function.is_fuehrungsassistent() %}
<a class="dropdown-item"
hx-post="/assignments/new?event={{ event.id }}&availabillity={{ availabillity.id }}&function=5" {% if
!further_fuehrungsassistent_required || status !=AvailabillityAssignmentState::Unassigned|ref
%}disabled{% endif %}>als Führungsassistent planen</a>
{% endif %}
{% if u.function == Function::Wachhabender %}
{% if u.function.is_fuehrungsassistent() %}
<a class="dropdown-item"
hx-post="/assignments/new?event={{ event.id }}&availabillity={{ availabillity.id }}&function=10" {% if
!further_wachhabender_required || status !=AvailabillityAssignmentState::Unassigned|ref %}disabled{%

View File

@ -68,11 +68,6 @@
<div class="control">
<div class="select is-fullwidth">
<select name="function">
<option value="1" {{ function|is_some_and_eq(1|ref)|ref|cond_show("selected") }}>Posten</option>
<option value="5" {{ function|is_some_and_eq(5|ref)|ref|cond_show("selected") }}>Führungsassistent
</option>
<option value="10" {{ function|is_some_and_eq(10|ref)|ref|cond_show("selected") }}>Wachhabender
</option>
</select>
</div>
</div>

View File

@ -56,15 +56,7 @@
{% endmatch %}
</td>
<td>
{% match u.function %}
{% when Function::Posten %}
<span class="tag is-primary is-light">Posten</span>
{% when Function::Fuehrungsassistent %}
<span class="tag is-primary is-light">Führungsassistent</span>
{% when Function::Wachhabender %}
<span class="tag is-primary">Wachhabender</span>
{% else %}
{% endmatch %}
{{ u.function|show_tree|safe }}
</td>
{% if user.role == Role::Admin %}
<td>