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

@ -29,13 +29,20 @@
}, },
{ {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
}, },

View File

@ -1,6 +1,6 @@
{ {
"db_name": "PostgreSQL", "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": { "describe": {
"columns": [ "columns": [
{ {
@ -46,16 +46,23 @@
}, },
{ {
"ordinal": 6, "ordinal": 6,
"name": "function: Function", "name": "function: Functions",
"type_info": { "type_info": {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
} }
@ -100,5 +107,5 @@
false false
] ]
}, },
"hash": "3338639844455180fdc70262cb982042ee2ff5cc8ab0fd6101bf5d4182f58530" "hash": "4da130f5ff77ea010db74c51e5dfc966aeae7ff1c4fa44395a0136bbd4a760c5"
} }

View File

@ -1,6 +1,6 @@
{ {
"db_name": "PostgreSQL", "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": { "describe": {
"columns": [ "columns": [
{ {
@ -71,16 +71,23 @@
}, },
{ {
"ordinal": 11, "ordinal": 11,
"name": "function: Function", "name": "function: Functions",
"type_info": { "type_info": {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
} }
@ -138,5 +145,5 @@
false false
] ]
}, },
"hash": "d3705fa03f98a5b83c65e29fe98d8c6015dfbff58460b420b9634bf2a0e38e4e" "hash": "6adecc71eae15d0ef809e16cfedf42ab8ec9c1e0c7eb423c0eee5be56f6ddf26"
} }

View File

@ -1,6 +1,6 @@
{ {
"db_name": "PostgreSQL", "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": { "describe": {
"columns": [ "columns": [
{ {
@ -71,16 +71,23 @@
}, },
{ {
"ordinal": 11, "ordinal": 11,
"name": "function: Function", "name": "function: Functions",
"type_info": { "type_info": {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
} }
@ -131,5 +138,5 @@
false false
] ]
}, },
"hash": "a1288bdb944dc72d5591d8686f533d124d9edacaf62539f7908c797efe44a68d" "hash": "a2ff81071585a31385044f022553dc1e5f81fd3727f47825991adcfae5546324"
} }

View File

@ -1,6 +1,6 @@
{ {
"db_name": "PostgreSQL", "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": { "describe": {
"columns": [ "columns": [
{ {
@ -46,16 +46,23 @@
}, },
{ {
"ordinal": 6, "ordinal": 6,
"name": "function: Function", "name": "function: Functions",
"type_info": { "type_info": {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
} }
@ -98,5 +105,5 @@
false false
] ]
}, },
"hash": "1d5bf64843b684258fcce0e606ea01a2037890ac736b7344e0008eae2b2a7ef6" "hash": "aa60c8e32c6c226f0b2f9161fd27bc9bf986cb7a69a7f5449c10a1b5642d9360"
} }

View File

@ -1,6 +1,6 @@
{ {
"db_name": "PostgreSQL", "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": { "describe": {
"columns": [ "columns": [
{ {
@ -46,16 +46,23 @@
}, },
{ {
"ordinal": 6, "ordinal": 6,
"name": "function: Function", "name": "function: Functions",
"type_info": { "type_info": {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
} }
@ -100,5 +107,5 @@
false false
] ]
}, },
"hash": "82a9b85a96c255c1bc0728ac6d3b4debcbbe0dbdf4b75e585d8e0f44fbd7a982" "hash": "abcd0f243fc7b93ea20c4dbd3c9b18ada4dc45893dd2f8f25873cb6819ee986e"
} }

View File

@ -27,13 +27,20 @@
}, },
{ {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
}, },

View File

@ -1,6 +1,6 @@
{ {
"db_name": "PostgreSQL", "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": { "describe": {
"columns": [ "columns": [
{ {
@ -71,16 +71,23 @@
}, },
{ {
"ordinal": 11, "ordinal": 11,
"name": "function: Function", "name": "function: Functions",
"type_info": { "type_info": {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
} }
@ -130,5 +137,5 @@
false false
] ]
}, },
"hash": "f48192661c91b4f48bb46f8ea5d60911ddeafc408d3a897dd4ab1b45fe06dd4d" "hash": "b06a1cfc8ba53c2f95ed5b74e9b6d73e723750b3679e2dbe970ed03e01886c90"
} }

View File

@ -1,6 +1,6 @@
{ {
"db_name": "PostgreSQL", "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": { "describe": {
"columns": [ "columns": [
{ {
@ -46,16 +46,23 @@
}, },
{ {
"ordinal": 6, "ordinal": 6,
"name": "function: Function", "name": "function: Functions",
"type_info": { "type_info": {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
} }
@ -110,5 +117,5 @@
false false
] ]
}, },
"hash": "2defbc675e894d30483e057d78344490b06c3cd5b3b3ab474ef755b67d4b6ea0" "hash": "cd25453504b28008dbe82aa89e8d942ad500b61beb640d2af9030872de069fb6"
} }

View File

@ -1,6 +1,6 @@
{ {
"db_name": "PostgreSQL", "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": { "describe": {
"columns": [ "columns": [
{ {
@ -46,16 +46,23 @@
}, },
{ {
"ordinal": 6, "ordinal": 6,
"name": "function: Function", "name": "function: Functions",
"type_info": { "type_info": {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
} }
@ -100,5 +107,5 @@
false false
] ]
}, },
"hash": "76bf18e05733214925ddd0cbe090a69f839c140377f043ca8181cd9a0af5e70e" "hash": "db1a44c82fca70aa0a0530a07b75bd2a596a16deb60ca89fedb26c8ad89dbdce"
} }

View File

@ -1,6 +1,6 @@
{ {
"db_name": "PostgreSQL", "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": { "describe": {
"columns": [ "columns": [
{ {
@ -71,16 +71,23 @@
}, },
{ {
"ordinal": 11, "ordinal": 11,
"name": "function: Function", "name": "function: Functions",
"type_info": { "type_info": {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
} }
@ -133,5 +140,5 @@
false false
] ]
}, },
"hash": "e5c0fdebea352e78f5d34fd0774f8802090ce15f811d1b2506ff8bc12fe8fad9" "hash": "efe07f8477c7416eae9c0b433cf24b7dc8abf38ce56c0ad46039a5bbbdd6865b"
} }

View File

@ -21,13 +21,20 @@
}, },
{ {
"Custom": { "Custom": {
"name": "function", "name": "function[]",
"kind": { "kind": {
"Enum": [ "Array": {
"posten", "Custom": {
"fuehrungsassistent", "name": "function",
"wachhabender" "kind": {
] "Enum": [
"posten",
"fuehrungsassistent",
"wachhabender"
]
}
}
}
} }
} }
}, },

View File

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

View File

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

View File

@ -46,7 +46,7 @@ mod tests {
let config = RequestConfig { let config = RequestConfig {
uri: "/area/edit/1".to_string(), uri: "/area/edit/1".to_string(),
role: Role::Admin, role: Role::Admin,
function: Function::Posten, function: vec![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;
@ -64,7 +64,7 @@ mod tests {
let config = RequestConfig { let config = RequestConfig {
uri: "/area/edit/1".to_string(), uri: "/area/edit/1".to_string(),
role: Role::AreaManager, role: Role::AreaManager,
function: Function::Posten, function: vec![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;
@ -79,7 +79,7 @@ mod tests {
let config = RequestConfig { let config = RequestConfig {
uri: "/area/edit/2".to_string(), uri: "/area/edit/2".to_string(),
role: Role::Admin, role: Role::Admin,
function: Function::Posten, function: vec![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

@ -35,7 +35,7 @@ mod tests {
let config = RequestConfig { let config = RequestConfig {
uri: "/area/new".to_string(), uri: "/area/new".to_string(),
role: Role::Admin, role: Role::Admin,
function: Function::Posten, function: vec![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;
@ -53,7 +53,7 @@ mod tests {
let config = RequestConfig { let config = RequestConfig {
uri: "/area/new".to_string(), uri: "/area/new".to_string(),
role: Role::AreaManager, role: Role::AreaManager,
function: Function::Posten, function: vec![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

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

View File

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

View File

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

View File

@ -70,7 +70,7 @@ pub async fn post(
let context = AssignmentContext { let context = AssignmentContext {
event: event.clone(), event: event.clone(),
availabillity: availabillity.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_event,
assignments_for_availabillity, assignments_for_availabillity,
}; };

View File

@ -106,7 +106,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: crate::models::Function::Posten, function: vec![crate::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

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

View File

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

View File

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

View File

@ -28,15 +28,17 @@ pub async fn get_edit(
}; };
let template = NewOrEditUserTemplate { let template = NewOrEditUserTemplate {
user: user.into_inner(), user: user.into_inner(),
id: Some(user_in_db.id), id: Some(user_in_db.id),
areas, areas,
email: Some(user_in_db.email), email: Some(user_in_db.email),
name: Some(user_in_db.name), name: Some(user_in_db.name),
role: Some(user_in_db.role as u8), 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()),
area_id: Some(user_in_db.area_id), 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),
};
Ok(template.to_response()?) Ok(template.to_response()?)
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
use maud::html; use maud::html;
use crate::models::Function; use crate::models::Functions;
pub fn show_area_query(a: &Option<i32>, first: bool) -> rinja::Result<String> { pub fn show_area_query(a: &Option<i32>, first: bool) -> rinja::Result<String> {
let char = if first { '?' } else { '&' }; let char = if first { '?' } else { '&' };
@ -40,15 +40,17 @@ pub fn invert(b: &bool) -> rinja::Result<bool> {
Ok(!b) Ok(!b)
} }
pub fn show_tree(f: &Function) -> rinja::Result<String> { pub fn show_tree(f: &Functions) -> rinja::Result<String> {
let html = html! { let html = html! {
div class="tags" { div class="tags" {
span class="tag is-primary is-light" { "Posten"} @if f.is_posten() {
@if *f == Function::Fuehrungsassistent || *f == Function::Wachhabender { span class="tag is-primary is-light" { "Posten"}
span class="tag is-primary has-background-primary-85 has-text-primary-85-invert" { "Führungsassistent"}
} }
@if *f == Function::Wachhabender { @if f.is_wachhabender() {
span class="tag is-primary" { "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 garde::Validate;
use super::{ 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)] #[derive(Validate)]
@ -26,7 +26,7 @@ pub struct AssignmentChangeset {
pub struct AssignmentContext { pub struct AssignmentContext {
pub event: Event, pub event: Event,
pub availabillity: Availability, pub availabillity: Availability,
pub user_function: Function, pub user_function: Functions,
pub assignments_for_event: Vec<Assignment>, pub assignments_for_event: Vec<Assignment>,
pub assignments_for_availabillity: Vec<Assignment>, pub assignments_for_availabillity: Vec<Assignment>,
} }
@ -50,7 +50,7 @@ fn user_of_availability_has_function(
value: &Function, value: &Function,
context: &AssignmentContext, context: &AssignmentContext,
) -> garde::Result { ) -> garde::Result {
if *value > context.user_function { if !context.user_function.contains(value) {
return Err(garde::Error::new( return Err(garde::Error::new(
"user has not the required function for this assignment", "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( fn event_has_free_slot_for_function(
_value: &Function, value: &Function,
context: &AssignmentContext, context: &AssignmentContext,
) -> garde::Result { ) -> garde::Result {
let list: Vec<&Assignment> = context let list: Vec<&Assignment> = context
@ -75,7 +75,7 @@ fn event_has_free_slot_for_function(
.iter() .iter()
.filter(|a| a.function == Function::Posten) .filter(|a| a.function == Function::Posten)
.count(); .count();
if match context.user_function { if match *value {
Function::Posten => a >= context.event.amount_of_posten as usize, Function::Posten => a >= context.event.amount_of_posten as usize,
Function::Fuehrungsassistent => context.event.voluntary_fuehrungsassistent && a >= 1, Function::Fuehrungsassistent => context.event.voluntary_fuehrungsassistent && a >= 1,
Function::Wachhabender => context.event.voluntary_wachhabender && 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 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)] #[derive(Clone, Debug)]
pub struct Availability { pub struct Availability {
@ -87,7 +87,7 @@ impl Availability {
user_.password, user_.password,
user_.salt, user_.salt,
user_.role AS "role: Role", user_.role AS "role: Role",
user_.function AS "function: Function", user_.function AS "function: Functions",
user_.areaId, user_.areaId,
user_.locked, user_.locked,
user_.lastLogin, user_.lastLogin,
@ -115,7 +115,7 @@ impl Availability {
password: r.password.clone(), password: r.password.clone(),
salt: r.salt.clone(), salt: r.salt.clone(),
role: r.role, role: r.role,
function: r.function, function: r.function.clone(),
area_id: r.areaid, area_id: r.areaid,
area: None, area: None,
locked: r.locked, locked: r.locked,
@ -154,7 +154,7 @@ impl Availability {
user_.password, user_.password,
user_.salt, user_.salt,
user_.role AS "role: Role", user_.role AS "role: Role",
user_.function AS "function: Function", user_.function AS "function: Functions",
user_.areaId, user_.areaId,
user_.locked, user_.locked,
user_.lastLogin, user_.lastLogin,
@ -186,7 +186,7 @@ impl Availability {
password: r.password.clone(), password: r.password.clone(),
salt: r.salt.clone(), salt: r.salt.clone(),
role: r.role, role: r.role,
function: r.function, function: r.function.clone(),
area_id: r.areaid, area_id: r.areaid,
area: None, area: None,
locked: r.locked, locked: r.locked,
@ -220,7 +220,7 @@ impl Availability {
user_.password, user_.password,
user_.salt, user_.salt,
user_.role AS "role: Role", user_.role AS "role: Role",
user_.function AS "function: Function", user_.function AS "function: Functions",
user_.areaId, user_.areaId,
user_.locked, user_.locked,
user_.lastLogin, user_.lastLogin,
@ -245,7 +245,7 @@ impl Availability {
password: r.password.clone(), password: r.password.clone(),
salt: r.salt.clone(), salt: r.salt.clone(),
role: r.role, role: r.role,
function: r.function, function: r.function.clone(),
area_id: r.areaid, area_id: r.areaid,
area: None, area: None,
locked: r.locked, locked: r.locked,
@ -302,7 +302,7 @@ impl Availability {
user_.password, user_.password,
user_.salt, user_.salt,
user_.role AS "role: Role", user_.role AS "role: Role",
user_.function AS "function: Function", user_.function AS "function: Functions",
user_.areaId, user_.areaId,
user_.locked, user_.locked,
user_.lastLogin, user_.lastLogin,
@ -334,7 +334,7 @@ impl Availability {
password: r.password.clone(), password: r.password.clone(),
salt: r.salt.clone(), salt: r.salt.clone(),
role: r.role, role: r.role,
function: r.function, function: r.function.clone(),
area_id: r.areaid, area_id: r.areaid,
area: Some(Area { area: Some(Area {
id: r.areaid, id: r.areaid,

View File

@ -1,6 +1,7 @@
use std::fmt::Display; use std::fmt::Display;
use serde::Serialize; use serde::Serialize;
use sqlx::postgres::{PgHasArrayType, PgTypeInfo};
use crate::utils::ApplicationError; use crate::utils::ApplicationError;
@ -12,6 +13,54 @@ pub enum Function {
Wachhabender = 10, 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 { impl Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -68,11 +68,6 @@
<div class="control"> <div class="control">
<div class="select is-fullwidth"> <div class="select is-fullwidth">
<select name="function"> <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> </select>
</div> </div>
</div> </div>

View File

@ -56,15 +56,7 @@
{% endmatch %} {% endmatch %}
</td> </td>
<td> <td>
{% match u.function %} {{ u.function|show_tree|safe }}
{% 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 %}
</td> </td>
{% if user.role == Role::Admin %} {% if user.role == Role::Admin %}
<td> <td>