Compare commits
185 Commits
8a3c2eaec5
...
197d0d724a
Author | SHA1 | Date |
---|---|---|
![]() |
197d0d724a | |
![]() |
7888dfad78 | |
![]() |
4429516a22 | |
![]() |
4bbeb93d64 | |
![]() |
909f7bba5a | |
![]() |
2baa101a8f | |
![]() |
a3a36de985 | |
![]() |
4244acfb4d | |
![]() |
4fa99b8a04 | |
![]() |
14dbe7f5d9 | |
![]() |
dc7c62ffe5 | |
![]() |
da8178b0bc | |
![]() |
02f998fc38 | |
![]() |
4de882ef85 | |
![]() |
fe836e281e | |
![]() |
8894f183f2 | |
![]() |
5b237febf8 | |
![]() |
497c1772f7 | |
![]() |
2e38b55167 | |
![]() |
1a250dc250 | |
![]() |
ef3bd7c319 | |
![]() |
ea93e27a9d | |
![]() |
a5cebc8535 | |
![]() |
72649c9522 | |
![]() |
b5d94971bc | |
![]() |
ca0a69b17d | |
![]() |
1505d0229d | |
![]() |
e2e18db460 | |
![]() |
8adad075bf | |
![]() |
f826cee63c | |
![]() |
0dbf88ad1c | |
![]() |
8185a74edc | |
![]() |
162116998c | |
![]() |
ac73489aed | |
![]() |
f4c3f7a39e | |
![]() |
23de3579af | |
![]() |
ba4ba8f2f8 | |
![]() |
8b1cd8130e | |
![]() |
48ea35562e | |
![]() |
a35a3580e0 | |
![]() |
15a6ba1c52 | |
![]() |
d89fe01ddd | |
![]() |
f292ce5331 | |
![]() |
269541293c | |
![]() |
545d2a7ccf | |
![]() |
dfd72d2d69 | |
![]() |
f2edb1a45c | |
![]() |
efda1ffc1c | |
![]() |
b8095492ec | |
![]() |
4e6ba3d684 | |
![]() |
1b91d84b5f | |
![]() |
47ad0a6133 | |
![]() |
fec2f17bea | |
![]() |
fd56966435 | |
![]() |
d8310ed6e7 | |
![]() |
3ffb0a38e8 | |
![]() |
e9b8977728 | |
![]() |
9acd06cb04 | |
![]() |
b17dbf46e0 | |
![]() |
7f2f5ab7ed | |
![]() |
58c457be86 | |
![]() |
36c7db40a7 | |
![]() |
0b165bc24c | |
![]() |
bf83e6a300 | |
![]() |
ac74ab489d | |
![]() |
f3347ba140 | |
![]() |
39dbfabea7 | |
![]() |
0a0cf5265c | |
![]() |
176a0b65c5 | |
![]() |
7fda1fc14b | |
![]() |
66738298a9 | |
![]() |
5d14109dbd | |
![]() |
44efd910c6 | |
![]() |
ecc3976c27 | |
![]() |
93270a10fd | |
![]() |
ff179360cc | |
![]() |
1b21bcf769 | |
![]() |
b6bd3eba56 | |
![]() |
6477e5dabd | |
![]() |
24f91ce9b5 | |
![]() |
6022d792dc | |
![]() |
9e3adf6179 | |
![]() |
6564056f16 | |
![]() |
343ce8241c | |
![]() |
7f6e1ff18e | |
![]() |
a31534d9b7 | |
![]() |
24204b1f3c | |
![]() |
27323bfba5 | |
![]() |
1397fe90ce | |
![]() |
89321306bc | |
![]() |
185b7e3fb6 | |
![]() |
9ffe739b24 | |
![]() |
9fb6bd4d10 | |
![]() |
fe37258b35 | |
![]() |
6195692d3d | |
![]() |
fc58d55274 | |
![]() |
9fcee133eb | |
![]() |
fed27210eb | |
![]() |
aeea3067b0 | |
![]() |
38838352e2 | |
![]() |
d251b4c7f7 | |
![]() |
7dbc0481b9 | |
![]() |
0aa4cdd2b0 | |
![]() |
1d5f16a59e | |
![]() |
fddae62669 | |
![]() |
599fff26d4 | |
![]() |
cd8c01c080 | |
![]() |
a70bc6ded8 | |
![]() |
7ce2cca052 | |
![]() |
cf4dc63495 | |
![]() |
dc9441d925 | |
![]() |
8438b8dc51 | |
![]() |
00f4afa2ab | |
![]() |
9f113958ca | |
![]() |
b3dd2b1d47 | |
![]() |
adf00b2739 | |
![]() |
8ebaffd71a | |
![]() |
383f8ebde5 | |
![]() |
4cd7103121 | |
![]() |
4267a76adb | |
![]() |
a2a57ec852 | |
![]() |
29a4b244dc | |
![]() |
4329ee4af9 | |
![]() |
c2dd25fc7c | |
![]() |
3b241529b7 | |
![]() |
40b93e3d8b | |
![]() |
c06cb767da | |
![]() |
dbb089315f | |
![]() |
5c59fec1cf | |
![]() |
102c8428c8 | |
![]() |
67d5950926 | |
![]() |
ee7d30b339 | |
![]() |
87bd4f4fa1 | |
![]() |
9a9ffcfdaf | |
![]() |
f3ec62e121 | |
![]() |
1ca9b99612 | |
![]() |
6b273288bd | |
![]() |
d1d0acf622 | |
![]() |
68dd73e333 | |
![]() |
94ba51bc46 | |
![]() |
24ecea0d65 | |
![]() |
5e702cd177 | |
![]() |
f966b1521f | |
![]() |
2252819800 | |
![]() |
931f3ba10d | |
![]() |
a60c5987ab | |
![]() |
80bec733bd | |
![]() |
c63a671dc4 | |
![]() |
009b0f3f27 | |
![]() |
f4030b86af | |
![]() |
e0b552d18b | |
![]() |
74989df119 | |
![]() |
b5803caf44 | |
![]() |
e03f2936e7 | |
![]() |
6c3bb7521f | |
![]() |
85bc95fea9 | |
![]() |
0a3a3c3b56 | |
![]() |
df4f744f6d | |
![]() |
e11b0db526 | |
![]() |
7f41d5eb1e | |
![]() |
4a907600b7 | |
![]() |
47f0587cd9 | |
![]() |
cffc9854f8 | |
![]() |
af2ac1bc3e | |
![]() |
49300900d6 | |
![]() |
86da8758a4 | |
![]() |
3ae8424aea | |
![]() |
98d2316b08 | |
![]() |
6622680baf | |
![]() |
21423ef305 | |
![]() |
c93c241dc9 | |
![]() |
4378fa2d7d | |
![]() |
8dd4af1bb6 | |
![]() |
f345942e46 | |
![]() |
da2baa75bb | |
![]() |
2c702fc67d | |
![]() |
d9b93e4236 | |
![]() |
1c4c164c39 | |
![]() |
e407a3b780 | |
![]() |
24f958b00d | |
![]() |
db4c5eec1c | |
![]() |
0a1c85d6bd | |
![]() |
c2e6dc5223 | |
![]() |
19a5673231 | |
![]() |
9feed46d4e |
|
@ -155,6 +155,15 @@ yarn lint:
|
|||
- apk add --no-cache git
|
||||
- yarn lint
|
||||
|
||||
translations lint:
|
||||
image: alpine
|
||||
stage: prepare
|
||||
before_script:
|
||||
- apk add gettext
|
||||
script:
|
||||
- find resources/lang -type f -name '*.po' -exec sh -c 'msgfmt "${1%.*}.po" -o"${1%.*}.mo"' shell {} \;
|
||||
- '[[ $(find resources/lang -type f -name "*.po" | wc -l) == $(find resources/lang -type f -name "*.mo" | wc -l) ]]'
|
||||
|
||||
#
|
||||
# Build
|
||||
#
|
||||
|
@ -177,6 +186,7 @@ build-image:
|
|||
- composer validate
|
||||
- yarn check
|
||||
- yarn lint
|
||||
- translations lint
|
||||
- generate-version
|
||||
dependencies:
|
||||
- generate-version
|
||||
|
|
|
@ -13,10 +13,14 @@ Please ensure that your pull requests follow the [PSR-12](https://www.php-fig.or
|
|||
You can check that by running
|
||||
```bash
|
||||
composer run phpcs
|
||||
# with docker
|
||||
docker exec engelsystem_dev-es_workspace-1 composer run phpcs
|
||||
```
|
||||
You may auto fix reported issues by running
|
||||
```bash
|
||||
composer run phpcbf
|
||||
# with docker
|
||||
docker exec engelsystem_dev-es_workspace-1 composer run phpcbf
|
||||
```
|
||||
|
||||
## Pre-commit hooks
|
||||
|
@ -68,7 +72,7 @@ docker compose exec es_workspace yarn build
|
|||
docker compose exec -e THEMES=0,1 es_workspace yarn build
|
||||
|
||||
# Update the translation files
|
||||
docker compose exec es_workspace find /var/www/resources/lang -type f -name '*.po' -exec sh -c 'file="{}"; msgfmt "${file%.*}.po" -o "${file%.*}.mo"' \;
|
||||
docker compose exec es_workspace find /var/www/resources/lang -type f -name '*.po' -exec sh -c 'msgfmt "${1%.*}.po" -o"${1%.*}.mo"' shell {} \;
|
||||
|
||||
# Run the migrations
|
||||
docker compose exec es_workspace bin/migrate
|
||||
|
@ -114,7 +118,7 @@ The following instructions explain how to get, build and run the latest Engelsys
|
|||
```
|
||||
* Generate translation files
|
||||
```bash
|
||||
find resources/lang/ -type f -name '*.po' -exec sh -c 'file="{}"; msgfmt "${file%.*}.po" -o "${file%.*}.mo"' \;
|
||||
find resources/lang/ -type f -name '*.po' -exec sh -c 'msgfmt "${1%.*}.po" -o"${1%.*}.mo"' shell {} \;
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
|
|
@ -40,7 +40,7 @@ The Engelsystem may be installed manually or by using the provided [docker setup
|
|||
* Recommended: Directory Listing should be disabled.
|
||||
* There must be a MySQL database set up with a user who has full rights to that database.
|
||||
* If necessary, create a `config/config.php` to override values from `config/config.default.php`.
|
||||
* To edit values from the `footer_items`, `themes`, `locales`, `tshirt_sizes` or `headers` lists, directly modify the `config/config.default.php` file or rename it to `config/config.php`.
|
||||
* To disable/remove values from the `themes`, `tshirt_sizes`, `headers`, `header_items`, `footer_items`, or `locales` lists, set the value of the entry to `null`.
|
||||
* To import the database, the `bin/migrate` script has to be run. If you can't execute scripts, you can use the `initial-install.sql` file from the release zip.
|
||||
* In the browser, login with credentials `admin` : `asdfasdf` and change the password.
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you want to contact us directly regarding a security concern, please write an e-mail to contact@engelsystem.de and explain your findings.
|
||||
Thank you!
|
||||
|
||||
## Use of external reporting / bug bounty services
|
||||
|
||||
We kindly ask you to not use any external reporting / bug bounty service. We do not collaborate with any external service and experiences in the past showed that these services usually add a lot of unnecessary overhead.
|
||||
|
||||
Please send security critical bug reports to contact@engelsystem.de.
|
||||
|
||||
If you feel like we are not reacting fast enough (generally no more than 14 days should go by until an initial response; This is a volunteer project mostly used internally after all), please feel free to go for full disclosure via our github issue tracker, and tag the issue there by creating a title prefixed with [SECURITY].
|
||||
|
||||
If you find a critical vulnerability that warrants a CVE, we will also take care of issuing a CVE without any bug bounty platform having to be involved.
|
|
@ -3,10 +3,24 @@
|
|||
# immediate exit after an error
|
||||
set -e
|
||||
|
||||
testing() {
|
||||
echo
|
||||
echo "🔎 Checking ${1}"
|
||||
}
|
||||
|
||||
testing 'JS & CSS 🎨'
|
||||
yarn check
|
||||
yarn lint
|
||||
|
||||
testing 'PHP ⚙️'
|
||||
composer validate
|
||||
composer phpcs
|
||||
composer phpstan
|
||||
./vendor/bin/phpunit
|
||||
|
||||
testing 'translations 🗺️'
|
||||
find resources/lang -type f -name '*.po' -exec sh -c 'msgfmt "${1%.*}.po" -o"${1%.*}.mo"' shell {} \;
|
||||
[ "$(find resources/lang -type f -name '*.po' | wc -l)" -eq "$(find resources/lang -type f -name '*.mo' | wc -l)" ]
|
||||
find resources/lang -type f -name '*.mo' -exec rm {} \;
|
||||
|
||||
echo '✅ Done 🎉'
|
||||
|
|
|
@ -35,38 +35,40 @@
|
|||
"ext-pdo": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-xml": "*",
|
||||
"doctrine/dbal": "^3.5",
|
||||
"doctrine/dbal": "^3.6",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"gettext/gettext": "^5.7",
|
||||
"gettext/translator": "^1.1",
|
||||
"guzzlehttp/guzzle": "^7.5",
|
||||
"illuminate/container": "^9.43",
|
||||
"illuminate/database": "^9.43",
|
||||
"illuminate/support": "^9.43",
|
||||
"league/oauth2-client": "^2.6",
|
||||
"guzzlehttp/guzzle": "^7.8",
|
||||
"illuminate/container": "^10.23",
|
||||
"illuminate/database": "^10.23",
|
||||
"illuminate/support": "^10.23",
|
||||
"league/oauth2-client": "^2.7",
|
||||
"league/openapi-psr7-validator": "^0.21",
|
||||
"nikic/fast-route": "^1.3",
|
||||
"nyholm/psr7": "^1.5",
|
||||
"nyholm/psr7": "^1.8",
|
||||
"psr/container": "^2.0",
|
||||
"psr/http-message": "^1.1",
|
||||
"psr/http-server-middleware": "^1.0",
|
||||
"psr/log": "^3.0",
|
||||
"rcrowe/twigbridge": "^0.14.0",
|
||||
"respect/validation": "^1.1",
|
||||
"symfony/http-foundation": "^6.2",
|
||||
"symfony/mailer": "^6.2",
|
||||
"symfony/psr-http-message-bridge": "^2.1",
|
||||
"twig/twig": "^3.4",
|
||||
"symfony/http-foundation": "^6.3",
|
||||
"symfony/mailer": "^6.3",
|
||||
"symfony/psr-http-message-bridge": "^2.3",
|
||||
"twig/twig": "^3.7",
|
||||
"vlucas/phpdotenv": "^5.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"dms/phpunit-arraysubset-asserts": "^0.4",
|
||||
"fakerphp/faker": "^1.20",
|
||||
"dms/phpunit-arraysubset-asserts": "^0.5",
|
||||
"fakerphp/faker": "^1.23",
|
||||
"fig/log-test": "^1.1",
|
||||
"filp/whoops": "^2.14",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"slevomat/coding-standard": "^8.6",
|
||||
"filp/whoops": "^2.15",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"slevomat/coding-standard": "^8.13",
|
||||
"squizlabs/php_codesniffer": "^3.7",
|
||||
"symfony/var-dumper": "^6.2"
|
||||
"symfony/var-dumper": "^6.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -28,7 +28,6 @@ return [
|
|||
\Engelsystem\Renderer\TwigServiceProvider::class,
|
||||
\Engelsystem\Middleware\RouteDispatcherServiceProvider::class,
|
||||
\Engelsystem\Middleware\RequestHandlerServiceProvider::class,
|
||||
\Engelsystem\Middleware\SessionHandlerServiceProvider::class,
|
||||
\Engelsystem\Http\Validation\ValidationServiceProvider::class,
|
||||
\Engelsystem\Http\RedirectServiceProvider::class,
|
||||
|
||||
|
@ -38,6 +37,7 @@ return [
|
|||
\Engelsystem\Http\HttpClientServiceProvider::class,
|
||||
\Engelsystem\Helpers\DumpServerServiceProvider::class,
|
||||
\Engelsystem\Helpers\UuidServiceProvider::class,
|
||||
\Engelsystem\Controllers\Api\UsesAuthServiceProvider::class,
|
||||
],
|
||||
|
||||
// Application middleware
|
||||
|
@ -50,9 +50,11 @@ return [
|
|||
\Engelsystem\Middleware\SetLocale::class,
|
||||
\Engelsystem\Middleware\ETagHandler::class,
|
||||
\Engelsystem\Middleware\AddHeaders::class,
|
||||
\Engelsystem\Middleware\TrimInput::class,
|
||||
|
||||
// The application code
|
||||
\Engelsystem\Middleware\ErrorHandler::class,
|
||||
\Engelsystem\Middleware\ApiRouteHandler::class,
|
||||
\Engelsystem\Middleware\VerifyCsrfToken::class,
|
||||
\Engelsystem\Middleware\RouteDispatcher::class,
|
||||
\Engelsystem\Middleware\SessionHandler::class,
|
||||
|
@ -74,6 +76,7 @@ return [
|
|||
'message.created' => \Engelsystem\Events\Listener\Messages::class . '@created',
|
||||
|
||||
'news.created' => \Engelsystem\Events\Listener\News::class . '@created',
|
||||
'news.updated' => \Engelsystem\Events\Listener\News::class . '@updated',
|
||||
|
||||
'oauth2.login' => \Engelsystem\Events\Listener\OAuth2::class . '@login',
|
||||
|
||||
|
@ -81,5 +84,7 @@ return [
|
|||
\Engelsystem\Events\Listener\Shift::class . '@deletedEntryCreateWorklog',
|
||||
\Engelsystem\Events\Listener\Shift::class . '@deletedEntrySendEmail',
|
||||
],
|
||||
|
||||
'shift.updating' => \Engelsystem\Events\Listener\Shift::class . '@updatedShiftSendEmail',
|
||||
],
|
||||
];
|
||||
|
|
|
@ -30,14 +30,24 @@ return [
|
|||
|
||||
// Header links
|
||||
// Available link placeholders: %lang%
|
||||
// To disable a header_item in the config.php, you can set its value to null
|
||||
'header_items' => [
|
||||
//'Foo' => 'https://foo.bar/batz-%lang%.html',
|
||||
// Name can be a translation string, permission is a engelsystem privilege
|
||||
// 'Name' => 'URL',
|
||||
// 'Name' => ['URL', 'permission'],
|
||||
|
||||
//'Foo' => ['https://foo.bar/batz-%lang%.html', 'logout'], // Permission: for logged-in users
|
||||
],
|
||||
|
||||
// Footer links
|
||||
// To disable a footer item in the config.php, you can set its value to null
|
||||
'footer_items' => [
|
||||
// Name can be a translation string, permission is a engelsystem privilege
|
||||
// 'Name' => 'URL',
|
||||
// 'Name' => ['URL', 'permission'],
|
||||
|
||||
// URL to the angel faq and job description
|
||||
'FAQ' => env('FAQ_URL', '/faq'),
|
||||
'faq.faq' => [env('FAQ_URL', '/faq'), 'faq.view'],
|
||||
|
||||
// Contact email address, linked on every page
|
||||
'Contact' => env('CONTACT_EMAIL', 'mailto:ticket@c3heaven.de'),
|
||||
|
@ -131,7 +141,14 @@ return [
|
|||
// Default theme, 1=style1.css
|
||||
'theme' => env('THEME', 1),
|
||||
|
||||
// Supported themes
|
||||
// To disable a theme in the config.php, you can set its value to null
|
||||
'themes' => [
|
||||
16 => [
|
||||
'name' => 'Engelsystem cccamp23 (2023)',
|
||||
'type' => 'dark',
|
||||
'navbar_classes' => 'navbar-dark',
|
||||
],
|
||||
15 => [
|
||||
'name' => 'Engelsystem rC3 (2021)',
|
||||
'type' => 'dark',
|
||||
|
@ -224,6 +241,16 @@ return [
|
|||
// Users are able to sign up
|
||||
'registration_enabled' => (bool) env('REGISTRATION_ENABLED', true),
|
||||
|
||||
// Required user fields
|
||||
'required_user_fields' => [
|
||||
'pronoun' => (bool) env('PRONOUN_REQUIRED', false),
|
||||
'firstname' => (bool) env('FIRSTNAME_REQUIRED', false),
|
||||
'lastname' => (bool) env('LASTNAME_REQUIRED', false),
|
||||
'tshirt_size' => (bool) env('TSHIRT_SIZE_REQUIRED', true),
|
||||
'mobile' => (bool) env('MOBILE_REQUIRED', false),
|
||||
'dect' => (bool) env('DECT_REQUIRED', false),
|
||||
],
|
||||
|
||||
// Only arrived angels can sign up for shifts
|
||||
'signup_requires_arrival' => (bool) env('SIGNUP_REQUIRES_ARRIVAL', false),
|
||||
|
||||
|
@ -268,7 +295,7 @@ return [
|
|||
|
||||
// Regular expression describing a FALSE username.
|
||||
// Per default usernames must only contain alphanumeric chars, "-", "_" or ".".
|
||||
'username_regex' => (string) env('USERNAME_REGEX', '/([^\p{L}\p{N}\-_.]+)/ui'),
|
||||
'username_regex' => (string) env('USERNAME_REGEX', '/([^\p{L}\p{N}_.-]+)/ui'),
|
||||
|
||||
// Enables first name and last name
|
||||
'enable_user_name' => (bool) env('ENABLE_USER_NAME', false),
|
||||
|
@ -318,7 +345,15 @@ return [
|
|||
'voucher_start' => env('VOUCHER_START', null) ?: null,
|
||||
],
|
||||
|
||||
# Instruction in accordance with § 43 Para. 1 of the German Infection Protection Act (IfSG)
|
||||
'ifsg_enabled' => (bool) env('IFSG_ENABLED', false),
|
||||
|
||||
# Instruction only onsite in accordance with § 43 Para. 1 of the German Infection Protection Act (IfSG)
|
||||
'ifsg_light_enabled' => (bool) env('IFSG_LIGHT_ENABLED', false)
|
||||
&& env('IFSG_ENABLED', false),
|
||||
|
||||
// Available locales in /resources/lang/
|
||||
// To disable a locale in the config.php, you can set its value to null
|
||||
'locales' => [
|
||||
'de_DE' => 'Deutsch',
|
||||
'en_US' => 'English',
|
||||
|
@ -327,21 +362,28 @@ return [
|
|||
// The default locale to use
|
||||
'default_locale' => env('DEFAULT_LOCALE', 'en_US'),
|
||||
|
||||
// Available T-Shirt sizes, set value to null if not available
|
||||
// Available T-Shirt sizes
|
||||
// To disable a t-shirt size in the config.php, you can set its value to null
|
||||
'tshirt_sizes' => [
|
||||
'S' => 'Small Straight-Cut',
|
||||
'S-G' => 'Small Fitted-Cut',
|
||||
'S-F' => 'Small Fitted-Cut',
|
||||
'M' => 'Medium Straight-Cut',
|
||||
'M-G' => 'Medium Fitted-Cut',
|
||||
'M-F' => 'Medium Fitted-Cut',
|
||||
'L' => 'Large Straight-Cut',
|
||||
'L-G' => 'Large Fitted-Cut',
|
||||
'L-F' => 'Large Fitted-Cut',
|
||||
'XL' => 'XLarge Straight-Cut',
|
||||
'XL-G' => 'XLarge Fitted-Cut',
|
||||
'XL-F' => 'XLarge Fitted-Cut',
|
||||
'2XL' => '2XLarge Straight-Cut',
|
||||
'3XL' => '3XLarge Straight-Cut',
|
||||
'4XL' => '4XLarge Straight-Cut',
|
||||
],
|
||||
|
||||
// Whether to show the current day of the event (-2, -1, 0, 1, 2…) in footer and on the dashboard.
|
||||
// The event start date has to be set for it to appear.
|
||||
'enable_show_day_of_event' => false,
|
||||
// If true there will be a day 0 (-1, 0, 1…). If false there won't (-1, 1…)
|
||||
'event_has_day0' => true,
|
||||
|
||||
'metrics' => [
|
||||
// User work buckets in seconds
|
||||
'work' => [1 * 60 * 60, 1.5 * 60 * 60, 2 * 60 * 60, 3 * 60 * 60, 5 * 60 * 60, 10 * 60 * 60, 20 * 60 * 60],
|
||||
|
@ -370,6 +412,8 @@ return [
|
|||
|
||||
// Add additional headers
|
||||
'add_headers' => (bool) env('ADD_HEADERS', true),
|
||||
// Predefined headers
|
||||
// To disable a header in the config.php, you can set its value to null
|
||||
'headers' => [
|
||||
'X-Content-Type-Options' => 'nosniff',
|
||||
'X-Frame-Options' => 'sameorigin',
|
||||
|
|
|
@ -8,6 +8,8 @@ use FastRoute\RouteCollector;
|
|||
|
||||
// Pages
|
||||
$route->get('/', 'HomeController@index');
|
||||
$route->get('/register', 'RegistrationController@view');
|
||||
$route->post('/register', 'RegistrationController@save');
|
||||
$route->get('/credits', 'CreditsController@index');
|
||||
$route->get('/health', 'HealthController@index');
|
||||
|
||||
|
@ -38,7 +40,14 @@ $route->addGroup(
|
|||
$route->post('/theme', 'SettingsController@saveTheme');
|
||||
$route->get('/language', 'SettingsController@language');
|
||||
$route->post('/language', 'SettingsController@saveLanguage');
|
||||
$route->get('/certificates', 'SettingsController@certificate');
|
||||
$route->post('/certificates/ifsg', 'SettingsController@saveIfsgCertificate');
|
||||
$route->post('/certificates/driving', 'SettingsController@saveDrivingLicense');
|
||||
$route->get('/api', 'SettingsController@api');
|
||||
$route->post('/api', 'SettingsController@apiKeyReset');
|
||||
$route->get('/oauth', 'SettingsController@oauth');
|
||||
$route->get('/sessions', 'SettingsController@sessions');
|
||||
$route->post('/sessions', 'SettingsController@sessionsDelete');
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -62,6 +71,11 @@ $route->addGroup('/angeltypes', function (RouteCollector $route): void {
|
|||
$route->get('/about', 'AngelTypesController@about');
|
||||
});
|
||||
|
||||
// Shifts
|
||||
$route->addGroup('/shifts', function (RouteCollector $route): void {
|
||||
$route->get('/random', 'ShiftsController@random');
|
||||
});
|
||||
|
||||
// News
|
||||
$route->get('/meetings', 'NewsController@meetings');
|
||||
$route->addGroup(
|
||||
|
@ -101,7 +115,42 @@ $route->addGroup(
|
|||
);
|
||||
|
||||
// API
|
||||
$route->get('/api[/{resource:.+}]', 'ApiController@index');
|
||||
$route->addGroup(
|
||||
'/api',
|
||||
function (RouteCollector $route): void {
|
||||
$route->get('', 'Api\IndexController@index');
|
||||
|
||||
$route->addGroup(
|
||||
'/v0-beta',
|
||||
function (RouteCollector $route): void {
|
||||
$route->addRoute(['OPTIONS'], '[/{resource:.+}]', 'Api\IndexController@options');
|
||||
$route->get('', 'Api\IndexController@indexV0');
|
||||
$route->get('/openapi', 'Api\IndexController@openApiV0');
|
||||
$route->get('/info', 'Api\IndexController@info');
|
||||
|
||||
$route->get('/angeltypes', 'Api\AngelTypeController@index');
|
||||
$route->get('/angeltypes/{angeltype_id:\d+}/shifts', 'Api\ShiftsController@entriesByAngeltype');
|
||||
|
||||
$route->get('/locations', 'Api\LocationsController@index');
|
||||
$route->get('/locations/{location_id:\d+}/shifts', 'Api\ShiftsController@entriesByLocation');
|
||||
|
||||
$route->get('/news', 'Api\NewsController@index');
|
||||
|
||||
$route->get('/users/{user_id:(?:\d+|self)}', 'Api\UsersController@user');
|
||||
$route->get('/users/{user_id:(?:\d+|self)}/angeltypes', 'Api\AngelTypeController@ofUser');
|
||||
$route->get('/users/{user_id:(?:\d+|self)}/shifts', 'Api\ShiftsController@entriesByUser');
|
||||
|
||||
$route->addRoute(
|
||||
['POST', 'PUT', 'DELETE', 'PATCH'],
|
||||
'/[{resource:.+}]',
|
||||
'Api\IndexController@notImplemented'
|
||||
);
|
||||
$route->get('/[{resource:.+}]', 'Api\IndexController@notFound');
|
||||
}
|
||||
);
|
||||
$route->get('/[{resource:.+}]', 'Api\IndexController@notFound');
|
||||
}
|
||||
);
|
||||
|
||||
// Feeds
|
||||
$route->get('/atom', 'FeedController@atom');
|
||||
|
@ -146,6 +195,27 @@ $route->addGroup(
|
|||
}
|
||||
);
|
||||
|
||||
// Shifts
|
||||
$route->addGroup(
|
||||
'/shifts',
|
||||
function (RouteCollector $route): void {
|
||||
$route->get('/history', 'Admin\\ShiftsController@history');
|
||||
$route->post('/history', 'Admin\\ShiftsController@deleteTransaction');
|
||||
}
|
||||
);
|
||||
|
||||
// Shift types
|
||||
$route->addGroup(
|
||||
'/shifttypes',
|
||||
function (RouteCollector $route): void {
|
||||
$route->get('', 'Admin\\ShiftTypesController@index');
|
||||
$route->post('', 'Admin\\ShiftTypesController@delete');
|
||||
$route->get('/{shift_type_id:\d+}', 'Admin\\ShiftTypesController@view');
|
||||
$route->get('/edit[/{shift_type_id:\d+}]', 'Admin\\ShiftTypesController@edit');
|
||||
$route->post('/edit[/{shift_type_id:\d+}]', 'Admin\\ShiftTypesController@save');
|
||||
}
|
||||
);
|
||||
|
||||
// Questions
|
||||
$route->addGroup(
|
||||
'/questions',
|
||||
|
@ -157,14 +227,14 @@ $route->addGroup(
|
|||
}
|
||||
);
|
||||
|
||||
// Rooms
|
||||
// Locations
|
||||
$route->addGroup(
|
||||
'/rooms',
|
||||
'/locations',
|
||||
function (RouteCollector $route): void {
|
||||
$route->get('', 'Admin\\RoomsController@index');
|
||||
$route->post('', 'Admin\\RoomsController@delete');
|
||||
$route->get('/edit[/{room_id:\d+}]', 'Admin\\RoomsController@edit');
|
||||
$route->post('/edit[/{room_id:\d+}]', 'Admin\\RoomsController@save');
|
||||
$route->get('', 'Admin\\LocationsController@index');
|
||||
$route->post('', 'Admin\\LocationsController@delete');
|
||||
$route->get('/edit[/{location_id:\d+}]', 'Admin\\LocationsController@edit');
|
||||
$route->post('/edit[/{location_id:\d+}]', 'Admin\\LocationsController@save');
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -24,9 +24,11 @@ class AngelTypeFactory extends Factory
|
|||
|
||||
'restricted' => $this->faker->boolean(),
|
||||
'requires_driver_license' => $this->faker->boolean(),
|
||||
'no_self_signup' => $this->faker->boolean(),
|
||||
'requires_ifsg_certificate' => $this->faker->boolean(),
|
||||
'shift_self_signup' => $this->faker->boolean(),
|
||||
'show_on_dashboard' => $this->faker->boolean(),
|
||||
'hide_register' => $this->faker->boolean(),
|
||||
'hide_on_shift_view' => $this->faker->boolean(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace Database\Factories\Engelsystem\Models;
|
||||
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Location;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class RoomFactory extends Factory
|
||||
class LocationFactory extends Factory
|
||||
{
|
||||
/** @var string */
|
||||
protected $model = Room::class; // phpcs:ignore
|
||||
protected $model = Location::class; // phpcs:ignore
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
|
@ -18,6 +18,7 @@ class RoomFactory extends Factory
|
|||
'name' => $this->faker->unique()->firstName(),
|
||||
'map_url' => $this->faker->url(),
|
||||
'description' => $this->faker->text(),
|
||||
'dect' => $this->faker->optional()->numberBetween(1000, 9999),
|
||||
];
|
||||
}
|
||||
}
|
|
@ -16,12 +16,12 @@ class NewsFactory extends Factory
|
|||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'title' => $this->faker->text(50),
|
||||
'text' => $this->faker->realText(),
|
||||
'is_meeting' => $this->faker->boolean(),
|
||||
'is_pinned' => $this->faker->boolean(.1),
|
||||
'is_important' => $this->faker->boolean(.1),
|
||||
'user_id' => User::factory(),
|
||||
'title' => $this->faker->text(50),
|
||||
'text' => $this->faker->realText(),
|
||||
'is_meeting' => $this->faker->boolean(),
|
||||
'is_pinned' => $this->faker->boolean(.1),
|
||||
'is_highlighted' => $this->faker->boolean(.1),
|
||||
'user_id' => User::factory(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories\Engelsystem\Models;
|
||||
|
||||
use Engelsystem\Models\OAuth;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class OAuthFactory extends Factory
|
||||
{
|
||||
/** @var class-string */
|
||||
protected $model = OAuth::class; // phpcs:ignore
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'provider' => $this->faker->unique()->word(),
|
||||
'identifier' => $this->faker->unique()->word(),
|
||||
'access_token' => $this->faker->unique()->word(),
|
||||
'refresh_token' => $this->faker->unique()->word(),
|
||||
'expires_at' => $this->faker->dateTimeInInterval('+5 days', '+3 months')->format('Y-m-d'),
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories\Engelsystem\Models;
|
||||
|
||||
use Engelsystem\Models\Session;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class SessionFactory extends Factory
|
||||
{
|
||||
/** @var string */
|
||||
protected $model = Session::class; // phpcs:ignore
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->faker->lexify('????????????????????????????????'),
|
||||
'payload' => $this->faker->text(100),
|
||||
'user_id' => $this->faker->optional()->passthrough(User::factory()),
|
||||
];
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ declare(strict_types=1);
|
|||
namespace Database\Factories\Engelsystem\Models\Shifts;
|
||||
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
@ -17,11 +17,12 @@ class NeededAngelTypeFactory extends Factory
|
|||
|
||||
public function definition(): array
|
||||
{
|
||||
$forRoom = $this->faker->boolean();
|
||||
$type = $this->faker->numberBetween(0, 2);
|
||||
|
||||
return [
|
||||
'room_id' => $forRoom ? Room::factory() : null,
|
||||
'shift_id' => $forRoom ? null : Shift::factory(),
|
||||
'location_id' => $type == 0 ? Location::factory() : null,
|
||||
'shift_id' => $type == 1 ? null : Shift::factory(),
|
||||
'shift_type_id' => $type == 2 ? null : Shift::factory(),
|
||||
'angel_type_id' => AngelType::factory(),
|
||||
'count' => $this->faker->numberBetween(1, 5),
|
||||
];
|
||||
|
|
|
@ -18,6 +18,7 @@ class ScheduleFactory extends Factory
|
|||
'name' => $this->faker->unique()->words(4, true),
|
||||
'url' => $this->faker->parse('https://{{safeEmailDomain}}/{{slug}}.xml'),
|
||||
'shift_type' => $this->faker->numberBetween(1, 5),
|
||||
'needed_from_shift_type' => $this->faker->boolean(.2),
|
||||
'minutes_before' => 15,
|
||||
'minutes_after' => 15,
|
||||
];
|
||||
|
|
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Database\Factories\Engelsystem\Models\Shifts;
|
||||
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftType;
|
||||
use Engelsystem\Models\User\User;
|
||||
|
@ -25,7 +25,7 @@ class ShiftFactory extends Factory
|
|||
'start' => $start,
|
||||
'end' => $this->faker->dateTimeInInterval($start, '+3 hours'),
|
||||
'shift_type_id' => ShiftType::factory(),
|
||||
'room_id' => Room::factory(),
|
||||
'location_id' => Location::factory(),
|
||||
'transaction_id' => $this->faker->optional()->uuid(),
|
||||
'created_by' => User::factory(),
|
||||
'updated_by' => $this->faker->optional(.3)->boolean() ? User::factory() : null,
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Database\Factories\Engelsystem\Models\User;
|
||||
|
||||
use Engelsystem\Models\User\Contact;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class ContactFactory extends Factory
|
||||
|
@ -15,6 +16,7 @@ class ContactFactory extends Factory
|
|||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'dect' => $this->faker->optional()->numberBetween(1000, 9999),
|
||||
'email' => $this->faker->unique()->optional()->safeEmail(),
|
||||
'mobile' => $this->faker->optional(.2)->phoneNumber(),
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Database\Factories\Engelsystem\Models\User;
|
||||
|
||||
use Engelsystem\Models\User\License;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class LicenseFactory extends Factory
|
||||
|
@ -21,13 +22,19 @@ class LicenseFactory extends Factory
|
|||
$drive_forklift = ($drive_car && $this->faker->boolean(.1))
|
||||
|| ($drive_12t && $this->faker->boolean(.7));
|
||||
|
||||
$ifsg_certificate = $this->faker->boolean(0.1);
|
||||
$ifsg_certificate_light = $this->faker->boolean(0.5) && !$ifsg_certificate;
|
||||
|
||||
return [
|
||||
'has_car' => $drive_car && $this->faker->boolean(.7),
|
||||
'drive_forklift' => $drive_forklift,
|
||||
'drive_car' => $drive_car,
|
||||
'drive_3_5t' => $drive_3_5t,
|
||||
'drive_7_5t' => $drive_7_5t,
|
||||
'drive_12t' => $drive_12t,
|
||||
'user_id' => User::factory(),
|
||||
'has_car' => $drive_car && $this->faker->boolean(.7),
|
||||
'drive_forklift' => $drive_forklift,
|
||||
'drive_car' => $drive_car,
|
||||
'drive_3_5t' => $drive_3_5t,
|
||||
'drive_7_5t' => $drive_7_5t,
|
||||
'drive_12t' => $drive_12t,
|
||||
'ifsg_certificate' => $ifsg_certificate,
|
||||
'ifsg_certificate_light' => $ifsg_certificate_light,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Database\Factories\Engelsystem\Models\User;
|
||||
|
||||
use Engelsystem\Models\User\PasswordReset;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class PasswordResetFactory extends Factory
|
||||
|
@ -15,6 +16,7 @@ class PasswordResetFactory extends Factory
|
|||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'token' => bin2hex(random_bytes(16)),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Database\Factories\Engelsystem\Models\User;
|
|||
|
||||
use Carbon\Carbon;
|
||||
use Engelsystem\Models\User\PersonalData;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class PersonalDataFactory extends Factory
|
||||
|
@ -19,6 +20,7 @@ class PersonalDataFactory extends Factory
|
|||
$departure = $this->faker->optional()->dateTimeThisMonth('2 weeks');
|
||||
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'first_name' => $this->faker->optional(.7)->firstName(),
|
||||
'last_name' => $this->faker->optional()->lastName(),
|
||||
'pronoun' => $this->faker->optional(.3)->pronoun(),
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Database\Factories\Engelsystem\Models\User;
|
||||
|
||||
use Engelsystem\Models\User\Settings;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class SettingsFactory extends Factory
|
||||
|
@ -15,6 +16,7 @@ class SettingsFactory extends Factory
|
|||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'language' => $this->faker->locale(),
|
||||
'theme' => $this->faker->numberBetween(1, 20),
|
||||
'email_human' => $this->faker->boolean(),
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Database\Factories\Engelsystem\Models\User;
|
|||
|
||||
use Carbon\Carbon;
|
||||
use Engelsystem\Models\User\State;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class StateFactory extends Factory
|
||||
|
@ -18,8 +19,10 @@ class StateFactory extends Factory
|
|||
$arrival = $this->faker->optional()->dateTimeThisMonth();
|
||||
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'arrived' => (bool) $arrival,
|
||||
'arrival_date' => $arrival ? Carbon::instance($arrival) : null,
|
||||
'user_info' => $this->faker->optional(.1)->text(),
|
||||
'active' => $this->faker->boolean(.3),
|
||||
'force_active' => $this->faker->boolean(.1),
|
||||
'got_shirt' => $this->faker->boolean(),
|
||||
|
|
|
@ -19,6 +19,7 @@ class UserFactory extends Factory
|
|||
'password' => crypt(random_bytes(16), '$1$salt$'),
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
'api_key' => bin2hex(random_bytes(32)),
|
||||
'updated_at' => $this->faker->dateTimeInInterval('-3 months', 'now'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
802
db/install.sql
802
db/install.sql
|
@ -1,802 +0,0 @@
|
|||
-- phpMyAdmin SQL Dump
|
||||
-- version 4.5.2
|
||||
-- http://www.phpmyadmin.net
|
||||
--
|
||||
-- Host: localhost
|
||||
-- Erstellungszeit: 27. Sep 2016 um 17:48
|
||||
-- Server-Version: 10.1.10-MariaDB
|
||||
-- PHP-Version: 7.0.4
|
||||
|
||||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||
SET time_zone = "+00:00";
|
||||
|
||||
--
|
||||
-- Datenbank: `engelsystem`
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `AngelTypes`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `AngelTypes`;
|
||||
CREATE TABLE `AngelTypes` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` varchar(50) NOT NULL DEFAULT '',
|
||||
`restricted` int(1) NOT NULL,
|
||||
`description` text NOT NULL,
|
||||
`requires_driver_license` tinyint(1) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `EventConfig`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `EventConfig`;
|
||||
CREATE TABLE `EventConfig` (
|
||||
`event_name` varchar(255) DEFAULT NULL,
|
||||
`buildup_start_date` int(11) DEFAULT NULL,
|
||||
`event_start_date` int(11) DEFAULT NULL,
|
||||
`event_end_date` int(11) DEFAULT NULL,
|
||||
`teardown_end_date` int(11) DEFAULT NULL,
|
||||
`event_welcome_msg` varchar(255) DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `GroupPrivileges`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `GroupPrivileges`;
|
||||
CREATE TABLE `GroupPrivileges` (
|
||||
`id` int(11) NOT NULL,
|
||||
`group_id` int(11) NOT NULL,
|
||||
`privilege_id` int(11) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `GroupPrivileges`
|
||||
--
|
||||
|
||||
INSERT INTO `GroupPrivileges` (`id`, `group_id`, `privilege_id`) VALUES
|
||||
(85, -7, 10),
|
||||
(87, -7, 18),
|
||||
(86, -7, 21),
|
||||
(216, -6, 5),
|
||||
(212, -6, 6),
|
||||
(207, -6, 7),
|
||||
(211, -6, 12),
|
||||
(208, -6, 13),
|
||||
(210, -6, 14),
|
||||
(214, -6, 16),
|
||||
(209, -6, 21),
|
||||
(213, -6, 28),
|
||||
(206, -6, 31),
|
||||
(215, -6, 33),
|
||||
(257, -6, 38),
|
||||
(219, -5, 14),
|
||||
(221, -5, 25),
|
||||
(220, -5, 33),
|
||||
(241, -4, 5),
|
||||
(238, -4, 14),
|
||||
(240, -4, 16),
|
||||
(237, -4, 19),
|
||||
(242, -4, 25),
|
||||
(235, -4, 27),
|
||||
(239, -4, 28),
|
||||
(236, -4, 32),
|
||||
(218, -4, 39),
|
||||
(258, -3, 31),
|
||||
(247, -2, 3),
|
||||
(246, -2, 4),
|
||||
(255, -2, 8),
|
||||
(252, -2, 9),
|
||||
(254, -2, 11),
|
||||
(248, -2, 15),
|
||||
(251, -2, 17),
|
||||
(256, -2, 24),
|
||||
(253, -2, 26),
|
||||
(245, -2, 30),
|
||||
(244, -2, 34),
|
||||
(249, -2, 35),
|
||||
(243, -2, 36),
|
||||
(250, -2, 37),
|
||||
(88, -1, 1),
|
||||
(23, -1, 2),
|
||||
(24, -1, 5);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `Groups`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `Groups`;
|
||||
CREATE TABLE `Groups` (
|
||||
`Name` varchar(35) NOT NULL,
|
||||
`UID` int(11) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `Groups`
|
||||
--
|
||||
|
||||
INSERT INTO `Groups` (`Name`, `UID`) VALUES
|
||||
('6-Developer', -7),
|
||||
('5-Bürokrat', -6),
|
||||
('4-Team Coordinator', -5),
|
||||
('3-Shift Coordinator', -4),
|
||||
('Shirt-Manager', -3),
|
||||
('2-Engel', -2),
|
||||
('1-Gast', -1);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `LogEntries`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `LogEntries`;
|
||||
CREATE TABLE `LogEntries` (
|
||||
`id` int(11) NOT NULL,
|
||||
`timestamp` int(11) NOT NULL,
|
||||
`nick` text NOT NULL,
|
||||
`message` text NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `Messages`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `Messages`;
|
||||
CREATE TABLE `Messages` (
|
||||
`id` int(11) NOT NULL,
|
||||
`Datum` int(11) NOT NULL,
|
||||
`SUID` int(11) NOT NULL DEFAULT '0',
|
||||
`RUID` int(11) NOT NULL DEFAULT '0',
|
||||
`isRead` char(1) NOT NULL DEFAULT 'N',
|
||||
`Text` text NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Fuers interen Communikationssystem';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `NeededAngelTypes`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `NeededAngelTypes`;
|
||||
CREATE TABLE `NeededAngelTypes` (
|
||||
`id` int(11) NOT NULL,
|
||||
`room_id` int(11) DEFAULT NULL,
|
||||
`shift_id` int(11) DEFAULT NULL,
|
||||
`angel_type_id` int(11) NOT NULL,
|
||||
`count` int(11) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `News`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `News`;
|
||||
CREATE TABLE `News` (
|
||||
`ID` int(11) NOT NULL,
|
||||
`Datum` int(11) NOT NULL,
|
||||
`Betreff` varchar(150) NOT NULL DEFAULT '',
|
||||
`Text` text NOT NULL,
|
||||
`UID` int(11) NOT NULL DEFAULT '0',
|
||||
`Treffen` tinyint(4) NOT NULL DEFAULT '0'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `NewsComments`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `NewsComments`;
|
||||
CREATE TABLE `NewsComments` (
|
||||
`ID` bigint(11) NOT NULL,
|
||||
`Refid` int(11) NOT NULL DEFAULT '0',
|
||||
`Datum` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
|
||||
`Text` text NOT NULL,
|
||||
`UID` int(11) NOT NULL DEFAULT '0'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `Privileges`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `Privileges`;
|
||||
CREATE TABLE `Privileges` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` varchar(128) NOT NULL,
|
||||
`desc` varchar(1024) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `Privileges`
|
||||
--
|
||||
|
||||
INSERT INTO `Privileges` (`id`, `name`, `desc`) VALUES
|
||||
(1, 'start', 'Startseite für Gäste/Nicht eingeloggte User'),
|
||||
(2, 'login', 'Logindialog'),
|
||||
(3, 'news', 'Anzeigen der News-Seite'),
|
||||
(4, 'logout', 'User darf sich ausloggen'),
|
||||
(5, 'register', 'Einen neuen Engel registerieren'),
|
||||
(6, 'admin_rooms', 'Räume administrieren'),
|
||||
(7, 'admin_angel_types', 'Engel Typen administrieren'),
|
||||
(8, 'user_settings', 'User profile settings'),
|
||||
(9, 'user_messages', 'Writing and reading messages from user to user'),
|
||||
(10, 'admin_groups', 'Manage usergroups and their rights'),
|
||||
(11, 'user_questions', 'Let users ask questions'),
|
||||
(12, 'admin_questions', 'Answer user''s questions'),
|
||||
(13, 'admin_faq', 'Edit FAQs'),
|
||||
(14, 'admin_news', 'Administrate the news section'),
|
||||
(15, 'news_comments', 'User can comment news'),
|
||||
(16, 'admin_user', 'Administrate the angels'),
|
||||
(17, 'user_meetings', 'Lists meetings (news)'),
|
||||
(18, 'admin_language', 'Translate the system'),
|
||||
(19, 'admin_log', 'Display recent changes'),
|
||||
(20, 'user_wakeup', 'User wakeup-service organization'),
|
||||
(21, 'admin_import', 'Import rooms and shifts from pentabarf'),
|
||||
(22, 'credits', 'View credits'),
|
||||
(23, 'faq', 'View FAQ'),
|
||||
(24, 'user_shifts', 'Signup for shifts'),
|
||||
(25, 'user_shifts_admin', 'Signup other angels for shifts.'),
|
||||
(26, 'user_myshifts', 'Allow angels to view their own shifts and cancel them.'),
|
||||
(27, 'admin_arrive', 'Mark angels when they arrive.'),
|
||||
(28, 'admin_shifts', 'Create shifts'),
|
||||
(30, 'ical', 'iCal shift export'),
|
||||
(31, 'admin_active', 'Mark angels as active and if they got a t-shirt.'),
|
||||
(32, 'admin_free', 'Show a list of free/unemployed angels.'),
|
||||
(33, 'admin_user_angeltypes', 'Confirm restricted angel types'),
|
||||
(34, 'atom', ' Atom news export'),
|
||||
(35, 'shifts_json_export', 'Export shifts in JSON format'),
|
||||
(36, 'angeltypes', 'View angeltypes'),
|
||||
(37, 'user_angeltypes', 'Join angeltypes.'),
|
||||
(38, 'shifttypes', 'Administrate shift types'),
|
||||
(39, 'admin_event_config', 'Allow editing event config');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `Questions`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `Questions`;
|
||||
CREATE TABLE `Questions` (
|
||||
`QID` bigint(20) NOT NULL,
|
||||
`UID` int(11) NOT NULL DEFAULT '0',
|
||||
`Question` text NOT NULL,
|
||||
`AID` int(11) DEFAULT NULL,
|
||||
`Answer` text
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Fragen und Antworten';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `Room`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `Room`;
|
||||
CREATE TABLE `Room` (
|
||||
`RID` int(11) NOT NULL,
|
||||
`Name` varchar(35) NOT NULL DEFAULT '',
|
||||
`Man` text,
|
||||
`FromPentabarf` char(1) NOT NULL DEFAULT 'N',
|
||||
`show` char(1) NOT NULL DEFAULT 'Y',
|
||||
`Number` int(11) DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `Room`
|
||||
--
|
||||
|
||||
INSERT INTO `Room` (`RID`, `Name`, `Man`, `FromPentabarf`, `show`, `Number`) VALUES
|
||||
(1, 'Testraum', NULL, '', 'Y', 0);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `ShiftEntry`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `ShiftEntry`;
|
||||
CREATE TABLE `ShiftEntry` (
|
||||
`id` int(11) NOT NULL,
|
||||
`SID` int(11) NOT NULL DEFAULT '0',
|
||||
`TID` int(11) NOT NULL DEFAULT '0',
|
||||
`UID` int(11) NOT NULL DEFAULT '0',
|
||||
`Comment` text,
|
||||
`freeload_comment` text,
|
||||
`freeloaded` tinyint(1) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `Shifts`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `Shifts`;
|
||||
CREATE TABLE `Shifts` (
|
||||
`SID` int(11) NOT NULL,
|
||||
`title` text,
|
||||
`shifttype_id` int(11) NOT NULL,
|
||||
`start` int(11) NOT NULL,
|
||||
`end` int(11) NOT NULL,
|
||||
`RID` int(11) NOT NULL DEFAULT '0',
|
||||
`URL` text,
|
||||
`PSID` int(11) DEFAULT NULL,
|
||||
`created_by_user_id` int(11) DEFAULT NULL,
|
||||
`created_at_timestamp` int(11) NOT NULL,
|
||||
`edited_by_user_id` int(11) DEFAULT NULL,
|
||||
`edited_at_timestamp` int(11) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `ShiftTypes`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `ShiftTypes`;
|
||||
CREATE TABLE `ShiftTypes` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`angeltype_id` int(11) DEFAULT NULL,
|
||||
`description` text NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `ShiftTypes`
|
||||
--
|
||||
|
||||
INSERT INTO `ShiftTypes` (`id`, `name`, `angeltype_id`, `description`) VALUES
|
||||
(4, 'Schichttyp1', NULL, '');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `User`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `User`;
|
||||
CREATE TABLE `User` (
|
||||
`UID` int(11) NOT NULL,
|
||||
`Nick` varchar(23) NOT NULL DEFAULT '',
|
||||
`Name` varchar(23) DEFAULT NULL,
|
||||
`Vorname` varchar(23) DEFAULT NULL,
|
||||
`Alter` int(4) DEFAULT NULL,
|
||||
`Telefon` varchar(40) DEFAULT NULL,
|
||||
`DECT` varchar(5) DEFAULT NULL,
|
||||
`Handy` varchar(40) DEFAULT NULL,
|
||||
`email` varchar(123) DEFAULT NULL,
|
||||
`email_shiftinfo` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'User wants to be informed by mail about changes in his shifts',
|
||||
`jabber` varchar(200) DEFAULT NULL,
|
||||
`Size` varchar(4) DEFAULT NULL,
|
||||
`Passwort` varchar(128) DEFAULT NULL,
|
||||
`password_recovery_token` varchar(32) DEFAULT NULL,
|
||||
`Gekommen` tinyint(4) NOT NULL DEFAULT '0',
|
||||
`Aktiv` tinyint(4) NOT NULL DEFAULT '0',
|
||||
`force_active` tinyint(1) NOT NULL,
|
||||
`Tshirt` tinyint(4) DEFAULT '0',
|
||||
`color` tinyint(4) DEFAULT '10',
|
||||
`Sprache` char(64) NOT NULL,
|
||||
`Menu` char(1) NOT NULL DEFAULT 'L',
|
||||
`lastLogIn` int(11) NOT NULL,
|
||||
`CreateDate` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
|
||||
`Art` varchar(30) DEFAULT NULL,
|
||||
`kommentar` text,
|
||||
`Hometown` varchar(255) NOT NULL DEFAULT '',
|
||||
`api_key` varchar(32) NOT NULL,
|
||||
`got_voucher` int(11) NOT NULL,
|
||||
`arrival_date` int(11) DEFAULT NULL,
|
||||
`planned_arrival_date` int(11) NOT NULL,
|
||||
`planned_departure_date` int(11) DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `User`
|
||||
--
|
||||
|
||||
INSERT INTO `User` (`UID`, `Nick`, `Name`, `Vorname`, `Alter`, `Telefon`, `DECT`, `Handy`, `email`, `email_shiftinfo`, `jabber`, `Size`, `Passwort`, `password_recovery_token`, `Gekommen`, `Aktiv`, `force_active`, `Tshirt`, `color`, `Sprache`, `Menu`, `lastLogIn`, `CreateDate`, `Art`, `kommentar`, `Hometown`, `api_key`, `got_voucher`, `arrival_date`, `planned_arrival_date`, `planned_departure_date`) VALUES
|
||||
(1, 'admin', 'Gates', 'Bill', 42, '', '-', '', 'admin@example.com', 1, '', 'XL', '$6$rounds=5000$hjXbIhoRTH3vKiRa$Wl2P2iI5T9iRR.HHu/YFHswBW0WVn0yxCfCiX0Keco9OdIoDK6bIAADswP6KvMCJSwTGdV8PgA8g8Xfw5l8BD1', NULL, 1, 1, 0, 1, 0, 'de_DE.UTF-8', 'L', 1474990948, '0001-01-01 00:00:00', '', '', '', '038850abdd1feb264406be3ffa746235', 0, 1439490478, 1436964455, 1440161255);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `UserAngelTypes`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `UserAngelTypes`;
|
||||
CREATE TABLE `UserAngelTypes` (
|
||||
`id` int(11) NOT NULL,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`angeltype_id` int(11) NOT NULL,
|
||||
`confirm_user_id` int(11) DEFAULT NULL,
|
||||
`coordinator` tinyint(1) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `UserDriverLicenses`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `UserDriverLicenses`;
|
||||
CREATE TABLE `UserDriverLicenses` (
|
||||
`user_id` int(11) NOT NULL,
|
||||
`has_car` tinyint(1) NOT NULL,
|
||||
`has_license_car` tinyint(1) NOT NULL,
|
||||
`has_license_3_5t_transporter` tinyint(1) NOT NULL,
|
||||
`has_license_7_5t_truck` tinyint(1) NOT NULL,
|
||||
`has_license_12_5t_truck` tinyint(1) NOT NULL,
|
||||
`has_license_forklift` tinyint(1) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `UserDriverLicenses`
|
||||
--
|
||||
|
||||
INSERT INTO `UserDriverLicenses` (`user_id`, `has_car`, `has_license_car`, `has_license_3_5t_transporter`, `has_license_7_5t_truck`, `has_license_12_5t_truck`, `has_license_forklift`) VALUES
|
||||
(1, 1, 1, 1, 1, 1, 1);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `UserGroups`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `UserGroups`;
|
||||
CREATE TABLE `UserGroups` (
|
||||
`id` int(11) NOT NULL,
|
||||
`uid` int(11) NOT NULL,
|
||||
`group_id` int(11) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `UserGroups`
|
||||
--
|
||||
|
||||
INSERT INTO `UserGroups` (`id`, `uid`, `group_id`) VALUES
|
||||
(3, 1, -7),
|
||||
(4, 1, -6),
|
||||
(12, 1, -5),
|
||||
(2, 1, -4),
|
||||
(1, 1, -2);
|
||||
|
||||
--
|
||||
-- Indizes der exportierten Tabellen
|
||||
--
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `AngelTypes`
|
||||
--
|
||||
ALTER TABLE `AngelTypes`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `Name` (`name`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `GroupPrivileges`
|
||||
--
|
||||
ALTER TABLE `GroupPrivileges`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `group_id` (`group_id`,`privilege_id`),
|
||||
ADD KEY `privilege_id` (`privilege_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `Groups`
|
||||
--
|
||||
ALTER TABLE `Groups`
|
||||
ADD PRIMARY KEY (`UID`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `LogEntries`
|
||||
--
|
||||
ALTER TABLE `LogEntries`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `timestamp` (`timestamp`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `Messages`
|
||||
--
|
||||
ALTER TABLE `Messages`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `Datum` (`Datum`),
|
||||
ADD KEY `SUID` (`SUID`),
|
||||
ADD KEY `RUID` (`RUID`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `NeededAngelTypes`
|
||||
--
|
||||
ALTER TABLE `NeededAngelTypes`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `room_id` (`room_id`,`angel_type_id`),
|
||||
ADD KEY `shift_id` (`shift_id`),
|
||||
ADD KEY `angel_type_id` (`angel_type_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `News`
|
||||
--
|
||||
ALTER TABLE `News`
|
||||
ADD PRIMARY KEY (`ID`),
|
||||
ADD KEY `UID` (`UID`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `NewsComments`
|
||||
--
|
||||
ALTER TABLE `NewsComments`
|
||||
ADD PRIMARY KEY (`ID`),
|
||||
ADD KEY `Refid` (`Refid`),
|
||||
ADD KEY `UID` (`UID`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `Privileges`
|
||||
--
|
||||
ALTER TABLE `Privileges`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `name` (`name`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `Questions`
|
||||
--
|
||||
ALTER TABLE `Questions`
|
||||
ADD PRIMARY KEY (`QID`),
|
||||
ADD KEY `UID` (`UID`),
|
||||
ADD KEY `AID` (`AID`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `Room`
|
||||
--
|
||||
ALTER TABLE `Room`
|
||||
ADD PRIMARY KEY (`RID`),
|
||||
ADD UNIQUE KEY `Name` (`Name`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `ShiftEntry`
|
||||
--
|
||||
ALTER TABLE `ShiftEntry`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `TID` (`TID`),
|
||||
ADD KEY `UID` (`UID`),
|
||||
ADD KEY `SID` (`SID`,`TID`),
|
||||
ADD KEY `freeloaded` (`freeloaded`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `Shifts`
|
||||
--
|
||||
ALTER TABLE `Shifts`
|
||||
ADD PRIMARY KEY (`SID`),
|
||||
ADD UNIQUE KEY `PSID` (`PSID`),
|
||||
ADD KEY `RID` (`RID`),
|
||||
ADD KEY `shifttype_id` (`shifttype_id`),
|
||||
ADD KEY `created_by_user_id` (`created_by_user_id`),
|
||||
ADD KEY `edited_by_user_id` (`edited_by_user_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `ShiftTypes`
|
||||
--
|
||||
ALTER TABLE `ShiftTypes`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `angeltype_id` (`angeltype_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `User`
|
||||
--
|
||||
ALTER TABLE `User`
|
||||
ADD PRIMARY KEY (`UID`),
|
||||
ADD UNIQUE KEY `Nick` (`Nick`),
|
||||
ADD KEY `api_key` (`api_key`),
|
||||
ADD KEY `password_recovery_token` (`password_recovery_token`),
|
||||
ADD KEY `force_active` (`force_active`),
|
||||
ADD KEY `arrival_date` (`arrival_date`,`planned_arrival_date`),
|
||||
ADD KEY `planned_departure_date` (`planned_departure_date`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `UserAngelTypes`
|
||||
--
|
||||
ALTER TABLE `UserAngelTypes`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `user_id` (`user_id`,`angeltype_id`,`confirm_user_id`),
|
||||
ADD KEY `angeltype_id` (`angeltype_id`),
|
||||
ADD KEY `confirm_user_id` (`confirm_user_id`),
|
||||
ADD KEY `coordinator` (`coordinator`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `UserDriverLicenses`
|
||||
--
|
||||
ALTER TABLE `UserDriverLicenses`
|
||||
ADD PRIMARY KEY (`user_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `UserGroups`
|
||||
--
|
||||
ALTER TABLE `UserGroups`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `uid` (`uid`,`group_id`),
|
||||
ADD KEY `group_id` (`group_id`);
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für exportierte Tabellen
|
||||
--
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `AngelTypes`
|
||||
--
|
||||
ALTER TABLE `AngelTypes`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `GroupPrivileges`
|
||||
--
|
||||
ALTER TABLE `GroupPrivileges`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=259;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `LogEntries`
|
||||
--
|
||||
ALTER TABLE `LogEntries`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `Messages`
|
||||
--
|
||||
ALTER TABLE `Messages`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `NeededAngelTypes`
|
||||
--
|
||||
ALTER TABLE `NeededAngelTypes`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `News`
|
||||
--
|
||||
ALTER TABLE `News`
|
||||
MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `NewsComments`
|
||||
--
|
||||
ALTER TABLE `NewsComments`
|
||||
MODIFY `ID` bigint(11) NOT NULL AUTO_INCREMENT;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `Privileges`
|
||||
--
|
||||
ALTER TABLE `Privileges`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=40;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `Questions`
|
||||
--
|
||||
ALTER TABLE `Questions`
|
||||
MODIFY `QID` bigint(20) NOT NULL AUTO_INCREMENT;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `Room`
|
||||
--
|
||||
ALTER TABLE `Room`
|
||||
MODIFY `RID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `ShiftEntry`
|
||||
--
|
||||
ALTER TABLE `ShiftEntry`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `Shifts`
|
||||
--
|
||||
ALTER TABLE `Shifts`
|
||||
MODIFY `SID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=13;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `ShiftTypes`
|
||||
--
|
||||
ALTER TABLE `ShiftTypes`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `User`
|
||||
--
|
||||
ALTER TABLE `User`
|
||||
MODIFY `UID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `UserAngelTypes`
|
||||
--
|
||||
ALTER TABLE `UserAngelTypes`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `UserGroups`
|
||||
--
|
||||
ALTER TABLE `UserGroups`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=13;
|
||||
--
|
||||
-- Constraints der exportierten Tabellen
|
||||
--
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `GroupPrivileges`
|
||||
--
|
||||
ALTER TABLE `GroupPrivileges`
|
||||
ADD CONSTRAINT `groupprivileges_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `Groups` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `groupprivileges_ibfk_2` FOREIGN KEY (`privilege_id`) REFERENCES `Privileges` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `Messages`
|
||||
--
|
||||
ALTER TABLE `Messages`
|
||||
ADD CONSTRAINT `messages_ibfk_1` FOREIGN KEY (`SUID`) REFERENCES `User` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `messages_ibfk_2` FOREIGN KEY (`RUID`) REFERENCES `User` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `NeededAngelTypes`
|
||||
--
|
||||
ALTER TABLE `NeededAngelTypes`
|
||||
ADD CONSTRAINT `neededangeltypes_ibfk_1` FOREIGN KEY (`room_id`) REFERENCES `Room` (`RID`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `neededangeltypes_ibfk_2` FOREIGN KEY (`shift_id`) REFERENCES `Shifts` (`SID`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `neededangeltypes_ibfk_3` FOREIGN KEY (`angel_type_id`) REFERENCES `AngelTypes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `News`
|
||||
--
|
||||
ALTER TABLE `News`
|
||||
ADD CONSTRAINT `news_ibfk_1` FOREIGN KEY (`UID`) REFERENCES `User` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `NewsComments`
|
||||
--
|
||||
ALTER TABLE `NewsComments`
|
||||
ADD CONSTRAINT `newscomments_ibfk_1` FOREIGN KEY (`Refid`) REFERENCES `News` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `newscomments_ibfk_2` FOREIGN KEY (`UID`) REFERENCES `User` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `Questions`
|
||||
--
|
||||
ALTER TABLE `Questions`
|
||||
ADD CONSTRAINT `questions_ibfk_1` FOREIGN KEY (`UID`) REFERENCES `User` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `questions_ibfk_2` FOREIGN KEY (`AID`) REFERENCES `User` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `ShiftEntry`
|
||||
--
|
||||
ALTER TABLE `ShiftEntry`
|
||||
ADD CONSTRAINT `shiftentry_ibfk_1` FOREIGN KEY (`SID`) REFERENCES `Shifts` (`SID`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `shiftentry_ibfk_2` FOREIGN KEY (`UID`) REFERENCES `User` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `shiftentry_ibfk_3` FOREIGN KEY (`TID`) REFERENCES `AngelTypes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `Shifts`
|
||||
--
|
||||
ALTER TABLE `Shifts`
|
||||
ADD CONSTRAINT `shifts_ibfk_1` FOREIGN KEY (`RID`) REFERENCES `Room` (`RID`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `shifts_ibfk_2` FOREIGN KEY (`shifttype_id`) REFERENCES `ShiftTypes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `shifts_ibfk_3` FOREIGN KEY (`created_by_user_id`) REFERENCES `User` (`UID`) ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `shifts_ibfk_4` FOREIGN KEY (`edited_by_user_id`) REFERENCES `User` (`UID`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `ShiftTypes`
|
||||
--
|
||||
ALTER TABLE `ShiftTypes`
|
||||
ADD CONSTRAINT `shifttypes_ibfk_1` FOREIGN KEY (`angeltype_id`) REFERENCES `AngelTypes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `UserAngelTypes`
|
||||
--
|
||||
ALTER TABLE `UserAngelTypes`
|
||||
ADD CONSTRAINT `userangeltypes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `User` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `userangeltypes_ibfk_2` FOREIGN KEY (`angeltype_id`) REFERENCES `AngelTypes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `userangeltypes_ibfk_3` FOREIGN KEY (`confirm_user_id`) REFERENCES `User` (`UID`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `UserDriverLicenses`
|
||||
--
|
||||
ALTER TABLE `UserDriverLicenses`
|
||||
ADD CONSTRAINT `userdriverlicenses_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `User` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `UserGroups`
|
||||
--
|
||||
ALTER TABLE `UserGroups`
|
||||
ADD CONSTRAINT `usergroups_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `Groups` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `usergroups_ibfk_2` FOREIGN KEY (`uid`) REFERENCES `User` (`UID`) ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -29,24 +29,9 @@ class ImportInstallSql extends Migration
|
|||
'UserAngelTypes',
|
||||
'UserDriverLicenses',
|
||||
'UserGroups',
|
||||
'UserWorkLog',
|
||||
];
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
foreach ($this->oldTables as $table) {
|
||||
if ($this->schema->hasTable($table)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$sql = file_get_contents(__DIR__ . '/../install.sql');
|
||||
$this->schema->getConnection()->unprepared($sql);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
|
@ -54,6 +39,7 @@ class ImportInstallSql extends Migration
|
|||
{
|
||||
$this->schema->getConnection()->statement('SET FOREIGN_KEY_CHECKS=0;');
|
||||
|
||||
// Delete all remaining tables
|
||||
foreach ($this->oldTables as $table) {
|
||||
if ($this->schema->hasTable($table)) {
|
||||
$this->schema->dropIfExists($table);
|
||||
|
|
|
@ -8,24 +8,5 @@ use Engelsystem\Database\Migration\Migration;
|
|||
|
||||
class ImportUpdateSql extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if ($this->schema->hasTable('UserWorkLog')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sql = file_get_contents(__DIR__ . '/../update.sql');
|
||||
$this->schema->getConnection()->unprepared($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->dropIfExists('UserWorkLog');
|
||||
}
|
||||
// Do nothing as the tables will be created by later migrations and deleted by ImportInstall
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ class CreateWorklogsTable extends Migration
|
|||
->get();
|
||||
|
||||
foreach ($previousRecords as $previousRecord) {
|
||||
$worked_at = Carbon::createFromTimestamp($previousRecord->work_timestamp);
|
||||
$created_at = Carbon::createFromTimestamp($previousRecord->created_timestamp);
|
||||
$this->schema->getConnection()
|
||||
->table('worklogs')
|
||||
|
@ -44,7 +45,7 @@ class CreateWorklogsTable extends Migration
|
|||
'id' => $previousRecord->id,
|
||||
'user_id' => $previousRecord->user_id,
|
||||
'creator_id' => $previousRecord->created_user_id,
|
||||
'worked_at' => $previousRecord->work_timestamp,
|
||||
'worked_at' => $worked_at,
|
||||
'hours' => $previousRecord->work_hours,
|
||||
'comment' => $previousRecord->comment,
|
||||
'created_at' => $created_at,
|
||||
|
@ -87,11 +88,11 @@ class CreateWorklogsTable extends Migration
|
|||
->insert([
|
||||
'id' => $record->id,
|
||||
'user_id' => $record->user_id,
|
||||
'work_timestamp' => $record->worked_at->timestamp,
|
||||
'work_timestamp' => Carbon::createFromFormat('Y-m-d', $record->worked_at)->timestamp,
|
||||
'work_hours' => $record->hours,
|
||||
'comment' => $record->comment,
|
||||
'created_user_id' => $record->creator_id,
|
||||
'created_timestamp' => $record->created_at->timestamp,
|
||||
'created_timestamp' => Carbon::createFromFormat('Y-m-d H:i:s', $record->created_at)->timestamp,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class AddNameMinutesAndTimestampsToSchedules extends Migration
|
|||
|
||||
$this->schema->table('schedules', function (Blueprint $table): void {
|
||||
$table->string('name')->default('')->after('id');
|
||||
$table->integer('shift_type')->default(0)->after('name');
|
||||
$table->unsignedInteger('shift_type')->default(0)->after('name');
|
||||
$table->integer('minutes_before')->default(0)->after('shift_type');
|
||||
$table->integer('minutes_after')->default(0)->after('minutes_before');
|
||||
$table->timestamps();
|
||||
|
@ -36,7 +36,7 @@ class AddNameMinutesAndTimestampsToSchedules extends Migration
|
|||
|
||||
$this->schema->table('schedules', function (Blueprint $table): void {
|
||||
$table->string('name')->default(null)->change();
|
||||
$table->integer('shift_type')->default(null)->change();
|
||||
$table->unsignedInteger('shift_type')->default(null)->change();
|
||||
$table->integer('minutes_before')->default(null)->change();
|
||||
$table->integer('minutes_after')->default(null)->change();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Config\Config;
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Engelsystem\Helpers\Carbon;
|
||||
use Illuminate\Database\Schema\Builder as SchemaBuilder;
|
||||
use stdClass;
|
||||
|
||||
class CreateFirstUser extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
public function __construct(SchemaBuilder $schemaBuilder, protected Config $config)
|
||||
{
|
||||
parent::__construct($schemaBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$db = $this->schema->getConnection();
|
||||
if ($db->table('users')->count() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db->table('users')->insert([
|
||||
'name' => 'admin',
|
||||
'email' => 'admin@localhost',
|
||||
'password' => password_hash('asdfasdf', PASSWORD_DEFAULT),
|
||||
'api_key' => bin2hex(random_bytes(16)),
|
||||
'created_at' => Carbon::now(),
|
||||
]);
|
||||
|
||||
/** @var stdClass $admin */
|
||||
$admin = $db->table('users')->where('name', 'admin')->first();
|
||||
foreach (['users_contact', 'users_personal_data', 'users_state'] as $table) {
|
||||
$db->table($table)->insert(['user_id' => $admin->id]);
|
||||
}
|
||||
$db->table('users_settings')->insert(['user_id' => $admin->id, 'language' => 'en_US', 'theme' => 0]);
|
||||
}
|
||||
}
|
|
@ -6,14 +6,14 @@ namespace Engelsystem\Migrations;
|
|||
|
||||
use Engelsystem\Config\Config;
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Engelsystem\Helpers\Authenticator;
|
||||
use Illuminate\Database\Schema\Builder as SchemaBuilder;
|
||||
use stdClass;
|
||||
|
||||
class SetAdminPassword extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
public function __construct(SchemaBuilder $schemaBuilder, protected Authenticator $auth, protected Config $config)
|
||||
public function __construct(SchemaBuilder $schemaBuilder, protected Config $config)
|
||||
{
|
||||
parent::__construct($schemaBuilder);
|
||||
}
|
||||
|
@ -23,12 +23,21 @@ class SetAdminPassword extends Migration
|
|||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$admin = $this->auth->authenticate('admin', 'asdfasdf');
|
||||
$db = $this->schema->getConnection();
|
||||
/** @var stdClass $admin */
|
||||
$admin = $db->table('users')->where('name', 'admin')->first();
|
||||
$setupPassword = $this->config->get('setup_admin_password');
|
||||
if (!$admin || !$setupPassword) {
|
||||
|
||||
if (
|
||||
!$admin
|
||||
|| !password_verify('asdfasdf', $admin->password)
|
||||
|| !$setupPassword
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->auth->setPassword($admin, $setupPassword);
|
||||
$db->table('users')
|
||||
->where('id', $admin->id)
|
||||
->update(['password' => password_hash($setupPassword, PASSWORD_DEFAULT)]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use stdClass;
|
||||
|
||||
class FillPrivilegesAndGroupsRelatedTables extends Migration
|
||||
{
|
||||
use ChangesReferences;
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Inserts missing data into permissions & groups related tables
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$db = $this->schema->getConnection();
|
||||
if ($db->table('privileges')->count() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db->table('groups')
|
||||
->insert([
|
||||
['id' => 10, 'name' => 'Guest'],
|
||||
['id' => 20, 'name' => 'Angel'],
|
||||
['id' => 30, 'name' => 'Welcome Angel'],
|
||||
['id' => 35, 'name' => 'Voucher Angel'],
|
||||
['id' => 50, 'name' => 'Shirt Manager'],
|
||||
['id' => 60, 'name' => 'Shift Coordinator'],
|
||||
['id' => 65, 'name' => 'Team Coordinator'],
|
||||
['id' => 80, 'name' => 'Bureaucrat'],
|
||||
['id' => 85, 'name' => 'News Admin'],
|
||||
['id' => 90, 'name' => 'Developer'],
|
||||
]);
|
||||
|
||||
$db->table('privileges')
|
||||
->insert([
|
||||
['id' => 1, 'name' => 'start', 'description' => 'Startseite für Gäste/Nicht eingeloggte User'],
|
||||
['id' => 2, 'name' => 'login', 'description' => 'Logindialog'],
|
||||
['id' => 3, 'name' => 'news', 'description' => 'Anzeigen der News-Seite'],
|
||||
['id' => 4, 'name' => 'logout', 'description' => 'User darf sich ausloggen'],
|
||||
['id' => 5, 'name' => 'register', 'description' => 'Einen neuen Engel registerieren'],
|
||||
['id' => 6, 'name' => 'admin_rooms', 'description' => 'Räume administrieren'],
|
||||
['id' => 7, 'name' => 'admin_angel_types', 'description' => 'Engel Typen administrieren'],
|
||||
['id' => 8, 'name' => 'user_settings', 'description' => 'User profile settings'],
|
||||
['id' => 9, 'name' => 'user_messages',
|
||||
'description' => 'Writing and reading messages from user to user'],
|
||||
['id' => 10, 'name' => 'admin_groups', 'description' => 'Manage usergroups and their rights'],
|
||||
['id' => 14, 'name' => 'admin_news', 'description' => 'Administrate the news section'],
|
||||
['id' => 15, 'name' => 'news_comments', 'description' => 'User can comment news'],
|
||||
['id' => 16, 'name' => 'admin_user', 'description' => 'Administrate the angels'],
|
||||
['id' => 17, 'name' => 'user_meetings', 'description' => 'Lists meetings (news)'],
|
||||
['id' => 18, 'name' => 'admin_language', 'description' => 'Translate the system'],
|
||||
['id' => 19, 'name' => 'admin_log', 'description' => 'Display recent changes'],
|
||||
['id' => 21, 'name' => 'schedule.import', 'description' => 'Import rooms and shifts from schedule.xml'],
|
||||
['id' => 24, 'name' => 'user_shifts', 'description' => 'Signup for shifts'],
|
||||
['id' => 25, 'name' => 'user_shifts_admin', 'description' => 'Signup other angels for shifts.'],
|
||||
['id' => 26, 'name' => 'user_myshifts',
|
||||
'description' => 'Allow angels to view their own shifts and cancel them.'],
|
||||
['id' => 27, 'name' => 'admin_arrive', 'description' => 'Mark angels when they arrive.'],
|
||||
['id' => 28, 'name' => 'admin_shifts', 'description' => 'Create shifts'],
|
||||
['id' => 30, 'name' => 'ical', 'description' => 'iCal shift export'],
|
||||
['id' => 31, 'name' => 'admin_active',
|
||||
'description' => 'Mark angels as active and if they got a t-shirt.'],
|
||||
['id' => 32, 'name' => 'admin_free', 'description' => 'Show a list of free/unemployed angels.'],
|
||||
['id' => 33, 'name' => 'admin_user_angeltypes', 'description' => 'Confirm restricted angel types'],
|
||||
['id' => 34, 'name' => 'atom', 'description' => ' Atom news export'],
|
||||
['id' => 35, 'name' => 'shifts_json_export', 'description' => 'Export shifts in JSON format'],
|
||||
['id' => 36, 'name' => 'angeltypes', 'description' => 'View angeltypes'],
|
||||
['id' => 37, 'name' => 'user_angeltypes', 'description' => 'Join angeltypes.'],
|
||||
['id' => 38, 'name' => 'shifttypes', 'description' => 'Administrate shift types'],
|
||||
['id' => 39, 'name' => 'admin_event_config', 'description' => 'Allow editing event config'],
|
||||
['id' => 40, 'name' => 'view_rooms', 'description' => 'User can view rooms'],
|
||||
['id' => 41, 'name' => 'shiftentry_edit_angeltype_supporter',
|
||||
'description' => 'If user with this privilege is angeltype supporter, '
|
||||
. 'he can put users in shifts for their angeltype'],
|
||||
['id' => 43, 'name' => 'admin_user_worklog', 'description' => 'Manage user work log entries.'],
|
||||
['id' => 44, 'name' => 'faq.view', 'description' => 'View FAQ entries'],
|
||||
['id' => 45, 'name' => 'faq.edit', 'description' => 'Edit FAQ entries'],
|
||||
['id' => 46, 'name' => 'question.add', 'description' => 'Ask questions'],
|
||||
['id' => 47, 'name' => 'question.edit', 'description' => 'Answer questions'],
|
||||
['id' => 48, 'name' => 'user.edit.shirt', 'description' => 'Edit user shirts'],
|
||||
['id' => 49, 'name' => 'voucher.edit', 'description' => 'Edit vouchers'],
|
||||
]);
|
||||
|
||||
$db->table('group_privileges')->insert([
|
||||
['id' => 23, 'group_id' => 10, 'privilege_id' => 2],
|
||||
['id' => 24, 'group_id' => 10, 'privilege_id' => 5],
|
||||
['id' => 85, 'group_id' => 90, 'privilege_id' => 10],
|
||||
['id' => 86, 'group_id' => 90, 'privilege_id' => 21],
|
||||
['id' => 87, 'group_id' => 90, 'privilege_id' => 18],
|
||||
['id' => 88, 'group_id' => 10, 'privilege_id' => 1],
|
||||
['id' => 206, 'group_id' => 80, 'privilege_id' => 31],
|
||||
['id' => 207, 'group_id' => 80, 'privilege_id' => 7],
|
||||
['id' => 209, 'group_id' => 80, 'privilege_id' => 21],
|
||||
['id' => 210, 'group_id' => 80, 'privilege_id' => 14],
|
||||
['id' => 212, 'group_id' => 80, 'privilege_id' => 6],
|
||||
['id' => 213, 'group_id' => 80, 'privilege_id' => 28],
|
||||
['id' => 214, 'group_id' => 80, 'privilege_id' => 16],
|
||||
['id' => 215, 'group_id' => 80, 'privilege_id' => 33],
|
||||
['id' => 216, 'group_id' => 80, 'privilege_id' => 5],
|
||||
['id' => 218, 'group_id' => 60, 'privilege_id' => 39],
|
||||
['id' => 219, 'group_id' => 65, 'privilege_id' => 14],
|
||||
['id' => 220, 'group_id' => 65, 'privilege_id' => 33],
|
||||
['id' => 221, 'group_id' => 65, 'privilege_id' => 25],
|
||||
['id' => 235, 'group_id' => 60, 'privilege_id' => 27],
|
||||
['id' => 236, 'group_id' => 60, 'privilege_id' => 32],
|
||||
['id' => 237, 'group_id' => 60, 'privilege_id' => 19],
|
||||
['id' => 238, 'group_id' => 60, 'privilege_id' => 14],
|
||||
['id' => 239, 'group_id' => 60, 'privilege_id' => 28],
|
||||
['id' => 240, 'group_id' => 60, 'privilege_id' => 16],
|
||||
['id' => 241, 'group_id' => 60, 'privilege_id' => 5],
|
||||
['id' => 242, 'group_id' => 60, 'privilege_id' => 25],
|
||||
['id' => 243, 'group_id' => 20, 'privilege_id' => 36],
|
||||
['id' => 244, 'group_id' => 20, 'privilege_id' => 34],
|
||||
['id' => 245, 'group_id' => 20, 'privilege_id' => 30],
|
||||
['id' => 246, 'group_id' => 20, 'privilege_id' => 4],
|
||||
['id' => 247, 'group_id' => 20, 'privilege_id' => 3],
|
||||
['id' => 248, 'group_id' => 20, 'privilege_id' => 15],
|
||||
['id' => 249, 'group_id' => 20, 'privilege_id' => 35],
|
||||
['id' => 250, 'group_id' => 20, 'privilege_id' => 37],
|
||||
['id' => 251, 'group_id' => 20, 'privilege_id' => 17],
|
||||
['id' => 252, 'group_id' => 20, 'privilege_id' => 9],
|
||||
['id' => 253, 'group_id' => 20, 'privilege_id' => 26],
|
||||
['id' => 255, 'group_id' => 20, 'privilege_id' => 8],
|
||||
['id' => 256, 'group_id' => 20, 'privilege_id' => 24],
|
||||
['id' => 257, 'group_id' => 80, 'privilege_id' => 38],
|
||||
['id' => 258, 'group_id' => 50, 'privilege_id' => 31],
|
||||
['id' => 259, 'group_id' => 20, 'privilege_id' => 40],
|
||||
['id' => 260, 'group_id' => 85, 'privilege_id' => 14],
|
||||
['id' => 262, 'group_id' => 60, 'privilege_id' => 43],
|
||||
['id' => 263, 'group_id' => 20, 'privilege_id' => 41],
|
||||
['id' => 264, 'group_id' => 30, 'privilege_id' => 27],
|
||||
['id' => 265, 'group_id' => 10, 'privilege_id' => 44],
|
||||
['id' => 266, 'group_id' => 20, 'privilege_id' => 44],
|
||||
['id' => 267, 'group_id' => 60, 'privilege_id' => 45],
|
||||
['id' => 268, 'group_id' => 20, 'privilege_id' => 46],
|
||||
['id' => 269, 'group_id' => 60, 'privilege_id' => 47],
|
||||
['id' => 270, 'group_id' => 60, 'privilege_id' => 48],
|
||||
['id' => 271, 'group_id' => 50, 'privilege_id' => 48],
|
||||
['id' => 272, 'group_id' => 50, 'privilege_id' => 27],
|
||||
['id' => 273, 'group_id' => 60, 'privilege_id' => 49],
|
||||
['id' => 274, 'group_id' => 35, 'privilege_id' => 49],
|
||||
['id' => 275, 'group_id' => 35, 'privilege_id' => 27],
|
||||
]);
|
||||
|
||||
/** @var stdClass $admin */
|
||||
$admin = $db->table('users')->where('name', 'admin')->first();
|
||||
if (!$admin) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Angel, ShiCo, Team coordinator, Bureaucrat, Dev
|
||||
foreach ([20, 60, 65, 80, 90] as $group) {
|
||||
$db->table('users_groups')->insert(['user_id' => $admin->id, 'group_id' => $group]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ namespace Engelsystem\Migrations;
|
|||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ChangeApiKeyLength extends Migration
|
||||
{
|
||||
|
@ -24,6 +25,19 @@ class ChangeApiKeyLength extends Migration
|
|||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$connection = $this->schema->getConnection();
|
||||
$data = $connection->table('users')->get(['id', 'api_key']);
|
||||
foreach ($data as $user) {
|
||||
if (Str::length($user->api_key) <= 32) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$key = Str::substr($user->api_key, 0, 32);
|
||||
$connection->table('users')
|
||||
->where('id', $user->id)
|
||||
->update(['api_key' => $key]);
|
||||
}
|
||||
|
||||
$this->schema->table('users', function (Blueprint $table): void {
|
||||
$table->string('api_key', 32)->change();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
|
||||
class CreateApiPermissions extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('privileges')->insert([
|
||||
['name' => 'api', 'description' => 'Use the API'],
|
||||
]);
|
||||
$db->table('groups')->insert([
|
||||
['id' => 40, 'name' => 'API'],
|
||||
]);
|
||||
|
||||
$bureaucratGroup = 80;
|
||||
$apiId = $db->table('privileges')->where('name', 'api')->first()->id;
|
||||
$db->table('group_privileges')->insert([
|
||||
['group_id' => $bureaucratGroup, 'privilege_id' => $apiId],
|
||||
['group_id' => 40, 'privilege_id' => $apiId],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('privileges')
|
||||
->where('name', 'api')
|
||||
->delete();
|
||||
$db->table('groups')
|
||||
->where('id', 40)
|
||||
->delete();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
|
||||
class CleanupShortApiKeys extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('users')
|
||||
->where($db->raw('LENGTH(api_key)'), '<=', 42)
|
||||
->update(['api_key' => '']);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class AddIfsgCerificatesToUsersLicenses extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->table('users_licenses', function (Blueprint $table): void {
|
||||
$table->boolean('ifsg_certificate_light')->default(false)->after('drive_12t');
|
||||
$table->boolean('ifsg_certificate')->default(false)->after('ifsg_certificate_light');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->table('users_licenses', function (Blueprint $table): void {
|
||||
$table->dropColumn('ifsg_certificate_light');
|
||||
$table->dropColumn('ifsg_certificate');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class AddRequiresIfsgCerificateToAngeltypes extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->table('angel_types', function (Blueprint $table): void {
|
||||
$table->boolean('requires_ifsg_certificate')->default(false)->after('requires_driver_license');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->table('angel_types', function (Blueprint $table): void {
|
||||
$table->dropColumn('requires_ifsg_certificate');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class AngeltypesRenameNoSelfSignupToShiftSelfSignup extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->table('angel_types', function (Blueprint $table): void {
|
||||
$table->renameColumn('no_self_signup', 'shift_self_signup')->default(true);
|
||||
$connection = $this->schema->getConnection();
|
||||
$connection->table('angel_types')
|
||||
->update(['no_self_signup' => $connection->raw('NOT no_self_signup'),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->table('angel_types', function (Blueprint $table): void {
|
||||
$table->renameColumn('shift_self_signup', 'no_self_signup');
|
||||
$connection = $this->schema->getConnection();
|
||||
$connection->table('angel_types')
|
||||
->update(['shift_self_signup' => $connection->raw('NOT shift_self_signup'),
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class AddHideOnShiftViewToAngeltypes extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->table('angel_types', function (Blueprint $table): void {
|
||||
$table->boolean('hide_on_shift_view')->default(false)->after('hide_register');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->table('angel_types', function (Blueprint $table): void {
|
||||
$table->dropColumn('hide_on_shift_view');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class AddUserToSessionsTable extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->table('sessions', function (Blueprint $table): void {
|
||||
$this->referencesUser($table)->nullable()->index()->after('payload');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->table('sessions', function (Blueprint $table): void {
|
||||
$table->dropForeign('sessions_user_id_foreign');
|
||||
$table->dropColumn('user_id');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class NewsRenameImportantToHighlight extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->table('news', function (Blueprint $table): void {
|
||||
$table->renameColumn('is_important', 'is_highlighted');
|
||||
});
|
||||
|
||||
$this->schema->getConnection()
|
||||
->table('privileges')
|
||||
->where('name', 'news.important')
|
||||
->update(['name' => 'news.highlight', 'description' => 'Highlight News']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->table('news', function (Blueprint $table): void {
|
||||
$table->renameColumn('is_highlighted', 'is_important');
|
||||
});
|
||||
|
||||
$this->schema->getConnection()
|
||||
->table('privileges')
|
||||
->where('name', 'news.highlight')
|
||||
->update(['name' => 'news.important', 'description' => 'Make News Important']);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class RenameRoomsToLocations extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->rename('rooms', 'locations');
|
||||
|
||||
$this->schema->table('shifts', function (Blueprint $table): void {
|
||||
$table->renameColumn('room_id', 'location_id');
|
||||
});
|
||||
|
||||
$this->schema->table('needed_angel_types', function (Blueprint $table): void {
|
||||
$table->renameColumn('room_id', 'location_id');
|
||||
});
|
||||
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('privileges')->where('name', 'admin_rooms')->update([
|
||||
'name' => 'admin_locations',
|
||||
'description' => 'Manage locations',
|
||||
]);
|
||||
$db->table('privileges')->where('name', 'view_rooms')->update([
|
||||
'name' => 'view_locations',
|
||||
'description' => 'User can view locations',
|
||||
]);
|
||||
$db->table('privileges')->where('name', 'schedule.import')->update([
|
||||
'description' => 'Import locations and shifts from schedule.xml',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->rename('locations', 'rooms');
|
||||
|
||||
$this->schema->table('shifts', function (Blueprint $table): void {
|
||||
$table->renameColumn('location_id', 'room_id');
|
||||
});
|
||||
|
||||
$this->schema->table('needed_angel_types', function (Blueprint $table): void {
|
||||
$table->renameColumn('location_id', 'room_id');
|
||||
});
|
||||
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('privileges')->where('name', 'admin_locations')->update([
|
||||
'name' => 'admin_rooms',
|
||||
'description' => 'Räume administrieren',
|
||||
]);
|
||||
$db->table('privileges')->where('name', 'view_locations')->update([
|
||||
'name' => 'view_rooms',
|
||||
'description' => 'User can view rooms',
|
||||
]);
|
||||
$db->table('privileges')->where('name', 'schedule.import')->update([
|
||||
'description' => 'Import rooms and shifts from schedule.xml',
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class AddMissingScheduleForeignKeys extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$schemaManager = $this->schema->getConnection()->getDoctrineSchemaManager();
|
||||
|
||||
$hasShiftTypeReference = $schemaManager->introspectTable('schedules')
|
||||
->hasIndex('schedules_shift_type_foreign');
|
||||
if (!$hasShiftTypeReference) {
|
||||
$this->schema->table('schedules', function (Blueprint $table): void {
|
||||
$table->unsignedInteger('shift_type')->change();
|
||||
$this->addReference($table, 'shift_type', 'shift_types');
|
||||
});
|
||||
}
|
||||
|
||||
$hasShiftIdReference = $schemaManager->introspectTable('schedule_shift')
|
||||
->hasIndex('schedule_shift_schedule_id_foreign');
|
||||
if (!$hasShiftIdReference) {
|
||||
$this->schema->table('schedule_shift', function (Blueprint $table): void {
|
||||
$table->unsignedInteger('shift_id')->change();
|
||||
$this->addReference($table, 'shift_id', 'shifts');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
|
||||
class DegenderShirtSizes extends Migration
|
||||
{
|
||||
/** @var string[] */
|
||||
protected array $sizes = [
|
||||
'S-G' => 'S-F',
|
||||
'M-G' => 'M-F',
|
||||
'L-G' => 'L-F',
|
||||
'XL-G' => 'XL-F',
|
||||
];
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->migrate($this->sizes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->migrate(array_flip($this->sizes));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $sizes
|
||||
*/
|
||||
private function migrate(array $sizes): void
|
||||
{
|
||||
$connection = $this->schema->getConnection();
|
||||
foreach ($sizes as $from => $to) {
|
||||
$connection
|
||||
->table('users_personal_data')
|
||||
->where('shirt_size', $from)
|
||||
->update([
|
||||
'shirt_size' => $to,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class AddUserInfoToUsersState extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->table('users_state', function (Blueprint $table): void {
|
||||
$table->string('user_info')->nullable()->default(null)->after('arrival_date');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->table('users_state', function (Blueprint $table): void {
|
||||
$table->dropColumn('user_info');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
|
||||
class AddUserInfoPermissions extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('privileges')
|
||||
->insert([
|
||||
['name' => 'user.info.show', 'description' => 'Show User Info'],
|
||||
['name' => 'user.info.edit', 'description' => 'Edit User Info'],
|
||||
]);
|
||||
|
||||
$showUserInfo = $db->table('privileges')
|
||||
->where('name', 'user.info.show')
|
||||
->get(['id'])
|
||||
->first();
|
||||
|
||||
$editUserInfo = $db->table('privileges')
|
||||
->where('name', 'user.info.edit')
|
||||
->get(['id'])
|
||||
->first();
|
||||
|
||||
$buerocrat = 80;
|
||||
$shico = 60;
|
||||
$db->table('group_privileges')
|
||||
->insertOrIgnore([
|
||||
['group_id' => $buerocrat, 'privilege_id' => $editUserInfo->id],
|
||||
['group_id' => $shico, 'privilege_id' => $showUserInfo->id],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('privileges')
|
||||
->whereIn('name', ['user.info.edit', 'user.info.show'])
|
||||
->delete();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class AddUserIdToLogEntries extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->table('log_entries', function (Blueprint $table): void {
|
||||
$table->unsignedInteger('user_id')->after('id')->nullable()->default(null);
|
||||
$table->foreign('user_id')
|
||||
->references('id')->on('users')
|
||||
->onUpdate('cascade')
|
||||
->nullOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->table('log_entries', function (Blueprint $table): void {
|
||||
$table->dropForeign('log_entries_user_id_foreign');
|
||||
$table->dropColumn('user_id');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\Schema\Builder as SchemaBuilder;
|
||||
|
||||
class ChangeEditShirtRequireBureaucrat extends Migration
|
||||
{
|
||||
protected int $bureaucrat = 80;
|
||||
|
||||
protected int $shiCo = 60;
|
||||
|
||||
protected int $editShirt;
|
||||
|
||||
protected Connection $db;
|
||||
|
||||
public function __construct(SchemaBuilder $schema)
|
||||
{
|
||||
parent::__construct($schema);
|
||||
$this->db = $this->schema->getConnection();
|
||||
|
||||
$this->editShirt = $this->db->table('privileges')
|
||||
->where('name', 'user.edit.shirt')
|
||||
->get(['id'])
|
||||
->first()->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->movePermission($this->editShirt, $this->shiCo, $this->bureaucrat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->movePermission($this->editShirt, $this->bureaucrat, $this->shiCo);
|
||||
}
|
||||
|
||||
protected function movePermission(int $privilege, int $oldGroup, int $newGroup): void
|
||||
{
|
||||
$this->db->table('group_privileges')
|
||||
->insertOrIgnore(['group_id' => $newGroup, 'privilege_id' => $privilege]);
|
||||
|
||||
$this->db->table('group_privileges')
|
||||
->where(['group_id' => $oldGroup, 'privilege_id' => $privilege])
|
||||
->delete();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
|
||||
class AddLogsAllPermission extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('privileges')
|
||||
->insert([
|
||||
['name' => 'logs.all', 'description' => 'View all logs'],
|
||||
]);
|
||||
|
||||
$logsAll = $db->table('privileges')
|
||||
->where('name', 'logs.all')
|
||||
->get(['id'])
|
||||
->first();
|
||||
|
||||
$bureaucrat = 80;
|
||||
$db->table('group_privileges')
|
||||
->insertOrIgnore([
|
||||
['group_id' => $bureaucrat, 'privilege_id' => $logsAll->id],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('privileges')
|
||||
->where('name', 'logs.all')
|
||||
->delete();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class ScheduleShiftTypeNeededAngelTypes extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->table('schedules', function (Blueprint $table): void {
|
||||
$table->boolean('needed_from_shift_type')->after('shift_type')->default(false);
|
||||
});
|
||||
$this->schema->table('needed_angel_types', function (Blueprint $table): void {
|
||||
$this->references($table, 'shift_types')->after('shift_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->table('schedules', function (Blueprint $table): void {
|
||||
$table->dropColumn('needed_from_shift_type');
|
||||
});
|
||||
$this->schema->table('needed_angel_types', function (Blueprint $table): void {
|
||||
$table->dropForeign('needed_angel_types_shift_type_id_foreign');
|
||||
$table->dropColumn('shift_type_id');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
|
||||
class AddUserEditPermission extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('privileges')
|
||||
->insert([
|
||||
'name' => 'user.edit', 'description' => 'Edit user',
|
||||
]);
|
||||
|
||||
$editUser = $db->table('privileges')
|
||||
->where('name', 'user.edit')
|
||||
->get(['id'])
|
||||
->first();
|
||||
|
||||
$buerocrat = 80;
|
||||
$db->table('group_privileges')
|
||||
->insertOrIgnore([
|
||||
'group_id' => $buerocrat, 'privilege_id' => $editUser->id,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('privileges')
|
||||
->where('name', 'user.edit')
|
||||
->delete();
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ trait Reference
|
|||
$table->primary($fromColumn);
|
||||
}
|
||||
|
||||
$this->addReference($table, $fromColumn, $targetTable, $targetColumn ?: 'id');
|
||||
$this->addReference($table, $fromColumn, $targetTable, $targetColumn);
|
||||
|
||||
return $col;
|
||||
}
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
INSERT INTO `Privileges` (`id`, `name`, `desc`) VALUES (40, 'view_rooms', 'User can view rooms');
|
||||
INSERT INTO `GroupPrivileges` (`id`, `group_id`, `privilege_id`) VALUES (NULL, '-2', '40');
|
||||
|
||||
ALTER TABLE `UserAngelTypes` CHANGE `coordinator` `supporter` BOOLEAN;
|
||||
|
||||
ALTER TABLE `User` ADD COLUMN `email_by_human_allowed` BOOLEAN NOT NULL;
|
||||
|
||||
-- No Self Sign Up for some Angel Types
|
||||
ALTER TABLE AngelTypes ADD no_self_signup TINYINT(1) NOT NULL;
|
||||
|
||||
ALTER TABLE `AngelTypes`
|
||||
ADD `contact_user_id` INT NULL,
|
||||
ADD `contact_name` VARCHAR(250) NULL,
|
||||
ADD `contact_dect` VARCHAR(5) NULL,
|
||||
ADD `contact_email` VARCHAR(250) NULL,
|
||||
ADD INDEX (`contact_user_id`);
|
||||
ALTER TABLE `AngelTypes`
|
||||
ADD FOREIGN KEY (`contact_user_id`) REFERENCES `User`(`UID`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
INSERT INTO `Privileges` (`id`, `name`, `desc`) VALUES (NULL, 'shiftentry_edit_angeltype_supporter', 'If user with this privilege is angeltype supporter, he can put users in shifts for their angeltype');
|
||||
|
||||
-- DB Performance
|
||||
ALTER TABLE `Shifts` ADD INDEX(`start`);
|
||||
ALTER TABLE `NeededAngelTypes` ADD INDEX(`count`);
|
||||
|
||||
-- Security
|
||||
UPDATE `Groups` SET UID = UID * 10;
|
||||
INSERT INTO `Groups` (Name, UID) VALUES ('News Admin', -65);
|
||||
INSERT INTO `Privileges` (id, name, `desc`) VALUES (42, 'admin_news_html', 'Use HTML in news');
|
||||
INSERT INTO `GroupPrivileges` (group_id, privilege_id) VALUES (-65, 14), (-65, 42);
|
||||
|
||||
-- Add log level to LogEntries
|
||||
ALTER TABLE `LogEntries` CHANGE COLUMN `nick` `level` VARCHAR(20) NOT NULL;
|
||||
|
||||
-- Angeltype contact update
|
||||
ALTER TABLE `AngelTypes` DROP FOREIGN KEY angeltypes_ibfk_1;
|
||||
ALTER TABLE `AngelTypes` DROP `contact_user_id`;
|
||||
|
||||
-- Room update
|
||||
ALTER TABLE `Room` DROP `Number`;
|
||||
ALTER TABLE `Room` DROP `show`;
|
||||
ALTER TABLE `Room` DROP `Man`;
|
||||
ALTER TABLE `Room` ADD `from_frab` BOOLEAN NOT NULL AFTER `FromPentabarf`;
|
||||
UPDATE Room SET `from_frab` = (`FromPentabarf` = 'Y');
|
||||
ALTER TABLE `Room` DROP `FromPentabarf`;
|
||||
ALTER TABLE `Room` ADD `map_url` VARCHAR(300) NULL AFTER `from_frab`;
|
||||
ALTER TABLE `Room` ADD `description` TEXT NULL AFTER `map_url`;
|
||||
|
||||
-- Dashboard
|
||||
ALTER TABLE `AngelTypes` ADD `show_on_dashboard` BOOLEAN NOT NULL AFTER `contact_email`;
|
||||
UPDATE `AngelTypes` SET `show_on_dashboard` = TRUE;
|
||||
|
||||
-- Work Log
|
||||
CREATE TABLE `UserWorkLog` ( `id` INT NOT NULL AUTO_INCREMENT , `user_id` INT NOT NULL , `work_hours` DECIMAL NOT NULL , `comment` VARCHAR(200) NOT NULL , `created_user_id` INT NOT NULL , `created_timestamp` INT NOT NULL , PRIMARY KEY (`id`), INDEX (`user_id`), INDEX (`created_user_id`)) ENGINE = InnoDB;
|
||||
ALTER TABLE `UserWorkLog` ADD FOREIGN KEY (`created_user_id`) REFERENCES `User`(`UID`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE `UserWorkLog` ADD FOREIGN KEY (`user_id`) REFERENCES `User`(`UID`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE `UserWorkLog` ADD INDEX(`created_timestamp`);
|
||||
INSERT INTO `Privileges` (`id`, `name`, `desc`) VALUES (NULL, 'admin_user_worklog', 'Manage user work log entries.');
|
||||
ALTER TABLE `UserWorkLog` CHANGE `work_hours` `work_hours` DECIMAL(10,2) NOT NULL;
|
||||
ALTER TABLE `UserWorkLog` ADD `work_timestamp` INT NOT NULL AFTER `user_id`;
|
|
@ -8,7 +8,7 @@ RUN composer --no-ansi dump-autoload --optimize
|
|||
FROM alpine AS translation
|
||||
RUN apk add gettext
|
||||
COPY resources/lang/ /data
|
||||
RUN find /data -type f -name '*.po' -exec sh -c 'file="{}"; msgfmt "${file%.*}.po" -o "${file%.*}.mo"' \;
|
||||
RUN find /data -type f -name '*.po' -exec sh -c 'msgfmt "${1%.*}.po" -o"${1%.*}.mo"' shell {} \;
|
||||
|
||||
# Build the themes
|
||||
FROM node:20-alpine AS themes
|
||||
|
@ -26,6 +26,7 @@ COPY config/ /app/config
|
|||
COPY db/ /app/db
|
||||
COPY includes/ /app/includes
|
||||
COPY public/ /app/public
|
||||
COPY resources/api /app/resources/api
|
||||
COPY resources/views /app/resources/views
|
||||
COPY src/ /app/src
|
||||
COPY storage/ /app/storage
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use Engelsystem\Helpers\Carbon;
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\Models\UserAngelType;
|
||||
use Engelsystem\ShiftsFilter;
|
||||
use Engelsystem\ShiftsFilterRenderer;
|
||||
|
@ -17,7 +17,7 @@ use Illuminate\Support\Collection;
|
|||
*/
|
||||
function angeltypes_title()
|
||||
{
|
||||
return __('Angeltypes');
|
||||
return __('angeltypes.angeltypes');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,7 +48,7 @@ function angeltypes_controller()
|
|||
function angeltype_link($angeltype_id, $params = [])
|
||||
{
|
||||
$params = array_merge(['action' => 'view', 'angeltype_id' => $angeltype_id], $params);
|
||||
return page_link_to('angeltypes', $params);
|
||||
return url('/angeltypes', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,7 +59,7 @@ function angeltype_link($angeltype_id, $params = [])
|
|||
function angeltype_delete_controller()
|
||||
{
|
||||
if (!auth()->can('admin_angel_types')) {
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
$angeltype = AngelType::findOrFail(request()->input('angeltype_id'));
|
||||
|
@ -68,11 +68,11 @@ function angeltype_delete_controller()
|
|||
$angeltype->delete();
|
||||
engelsystem_log('Deleted angeltype: ' . AngelType_name_render($angeltype, true));
|
||||
success(sprintf(__('Angeltype %s deleted.'), $angeltype->name));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
return [
|
||||
sprintf(__('Delete angeltype %s'), $angeltype->name),
|
||||
sprintf(__('Delete angeltype %s'), htmlspecialchars($angeltype->name)),
|
||||
AngelType_delete_view($angeltype),
|
||||
];
|
||||
}
|
||||
|
@ -92,14 +92,14 @@ function angeltype_edit_controller()
|
|||
// Edit existing angeltype
|
||||
$angeltype = AngelType::findOrFail($request->input('angeltype_id'));
|
||||
|
||||
if (!auth()->user()->isAngelTypeSupporter($angeltype) && !auth()->can('admin_user_angeltypes')) {
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
if (!auth()->user()?->isAngelTypeSupporter($angeltype) && !auth()->can('admin_user_angeltypes')) {
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
} else {
|
||||
// New angeltype
|
||||
if ($supporter_mode) {
|
||||
// Supporters aren't allowed to create new angeltypes.
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
$angeltype = new AngelType();
|
||||
}
|
||||
|
@ -118,11 +118,13 @@ function angeltype_edit_controller()
|
|||
}
|
||||
|
||||
$angeltype->restricted = $request->has('restricted');
|
||||
$angeltype->no_self_signup = $request->has('no_self_signup');
|
||||
$angeltype->shift_self_signup = $request->has('shift_self_signup');
|
||||
$angeltype->show_on_dashboard = $request->has('show_on_dashboard');
|
||||
$angeltype->hide_register = $request->has('hide_register');
|
||||
$angeltype->hide_on_shift_view = $request->has('hide_on_shift_view');
|
||||
|
||||
$angeltype->requires_driver_license = $request->has('requires_driver_license');
|
||||
$angeltype->requires_ifsg_certificate = $request->has('requires_ifsg_certificate');
|
||||
}
|
||||
|
||||
$angeltype->description = strip_request_item_nl('description', $angeltype->description);
|
||||
|
@ -137,20 +139,22 @@ function angeltype_edit_controller()
|
|||
success('Angel type saved.');
|
||||
engelsystem_log(
|
||||
'Saved angeltype: ' . $angeltype->name . ($angeltype->restricted ? ', restricted' : '')
|
||||
. ($angeltype->no_self_signup ? ', no_self_signup' : '')
|
||||
. ($angeltype->shift_self_signup ? ', shift_self_signup' : '')
|
||||
. ($angeltype->requires_driver_license ? ', requires driver license' : '') . ', '
|
||||
. ($angeltype->requires_ifsg_certificate ? ', requires ifsg certificate' : '') . ', '
|
||||
. $angeltype->contact_name . ', '
|
||||
. $angeltype->contact_dect . ', '
|
||||
. $angeltype->contact_email . ', '
|
||||
. $angeltype->show_on_dashboard . ', '
|
||||
. $angeltype->hide_register
|
||||
. $angeltype->hide_register . ', '
|
||||
. $angeltype->hide_on_shift_view
|
||||
);
|
||||
throw_redirect(angeltype_link($angeltype->id));
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
sprintf(__('Edit %s'), $angeltype->name),
|
||||
sprintf(__('Edit %s'), htmlspecialchars((string) $angeltype->name)),
|
||||
AngelType_edit_view($angeltype, $supporter_mode),
|
||||
];
|
||||
}
|
||||
|
@ -165,7 +169,7 @@ function angeltype_controller()
|
|||
$user = auth()->user();
|
||||
|
||||
if (!auth()->can('angeltypes')) {
|
||||
throw_redirect(page_link_to('/'));
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
$angeltype = AngelType::findOrFail(request()->input('angeltype_id'));
|
||||
|
@ -191,7 +195,7 @@ function angeltype_controller()
|
|||
|
||||
$isSupporter = !is_null($user_angeltype) && $user_angeltype->supporter;
|
||||
return [
|
||||
sprintf(__('Team %s'), $angeltype->name),
|
||||
sprintf(__('Team %s'), htmlspecialchars($angeltype->name)),
|
||||
AngelType_view(
|
||||
$angeltype,
|
||||
$members,
|
||||
|
@ -220,9 +224,8 @@ function angeltype_controller_shiftsFilterDays(AngelType $angeltype)
|
|||
$days = [];
|
||||
foreach ($all_shifts as $shift) {
|
||||
$day = Carbon::make($shift['start'])->format('Y-m-d');
|
||||
$dayFormatted = Carbon::make($shift['start'])->format(__('Y-m-d'));
|
||||
if (!isset($days[$day])) {
|
||||
$days[$day] = $dayFormatted;
|
||||
$days[$day] = dateWithEventDay($day);
|
||||
}
|
||||
}
|
||||
ksort($days);
|
||||
|
@ -239,13 +242,13 @@ function angeltype_controller_shiftsFilterDays(AngelType $angeltype)
|
|||
function angeltype_controller_shiftsFilter(AngelType $angeltype, $days)
|
||||
{
|
||||
$request = request();
|
||||
$roomIds = Room::query()
|
||||
$locationIds = Location::query()
|
||||
->select('id')
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
$shiftsFilter = new ShiftsFilter(
|
||||
auth()->can('user_shifts_admin'),
|
||||
$roomIds,
|
||||
$locationIds,
|
||||
[$angeltype->id]
|
||||
);
|
||||
$selected_day = date('Y-m-d');
|
||||
|
@ -269,59 +272,70 @@ function angeltype_controller_shiftsFilter(AngelType $angeltype, $days)
|
|||
function angeltypes_list_controller()
|
||||
{
|
||||
$user = auth()->user();
|
||||
$admin_angeltypes = auth()->can('admin_angel_types');
|
||||
|
||||
if (!auth()->can('angeltypes')) {
|
||||
throw_redirect(page_link_to('/'));
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
$angeltypes = AngelTypes_with_user($user->id);
|
||||
foreach ($angeltypes as $angeltype) {
|
||||
$actions = [
|
||||
button(
|
||||
page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]),
|
||||
icon('eye') . __('view'),
|
||||
'btn-sm'
|
||||
url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]),
|
||||
icon('eye') . ($admin_angeltypes ? '' : __('View')),
|
||||
'btn-sm btn-info',
|
||||
'',
|
||||
($admin_angeltypes ? __('View') : '')
|
||||
),
|
||||
];
|
||||
|
||||
if (auth()->can('admin_angel_types')) {
|
||||
if ($admin_angeltypes) {
|
||||
$actions[] = button(
|
||||
page_link_to('angeltypes', ['action' => 'edit', 'angeltype_id' => $angeltype->id]),
|
||||
icon('pencil') . __('edit'),
|
||||
'btn-sm'
|
||||
url('/angeltypes', ['action' => 'edit', 'angeltype_id' => $angeltype->id]),
|
||||
icon('pencil'),
|
||||
'btn-sm',
|
||||
'',
|
||||
__('form.edit')
|
||||
);
|
||||
$actions[] = button(
|
||||
page_link_to('angeltypes', ['action' => 'delete', 'angeltype_id' => $angeltype->id]),
|
||||
icon('trash') . __('delete'),
|
||||
'btn-sm'
|
||||
url('/angeltypes', ['action' => 'delete', 'angeltype_id' => $angeltype->id]),
|
||||
icon('trash'),
|
||||
'btn-sm btn-danger',
|
||||
'',
|
||||
__('form.delete')
|
||||
);
|
||||
}
|
||||
|
||||
$angeltype->membership = AngelType_render_membership($angeltype);
|
||||
if (!empty($angeltype->user_angel_type_id)) {
|
||||
$actions[] = button(
|
||||
page_link_to(
|
||||
'user_angeltypes',
|
||||
url(
|
||||
'/user-angeltypes',
|
||||
['action' => 'delete', 'user_angeltype_id' => $angeltype->user_angel_type_id]
|
||||
),
|
||||
icon('box-arrow-right') . __('leave'),
|
||||
'btn-sm'
|
||||
icon('box-arrow-right') . ($admin_angeltypes ? '' : __('Leave')),
|
||||
'btn-sm',
|
||||
'',
|
||||
($admin_angeltypes ? __('Leave') : '')
|
||||
);
|
||||
} else {
|
||||
$actions[] = button(
|
||||
page_link_to('user_angeltypes', ['action' => 'add', 'angeltype_id' => $angeltype->id]),
|
||||
icon('box-arrow-in-right') . __('join'),
|
||||
'btn-sm'
|
||||
url('/user_angeltypes', ['action' => 'add', 'angeltype_id' => $angeltype->id]),
|
||||
icon('box-arrow-in-right') . ($admin_angeltypes ? '' : __('Join')),
|
||||
'btn-sm',
|
||||
'',
|
||||
($admin_angeltypes ? __('Join') : '')
|
||||
);
|
||||
}
|
||||
|
||||
$angeltype->is_restricted = $angeltype->restricted ? icon('mortarboard-fill') : '';
|
||||
$angeltype->no_self_signup_allowed = $angeltype->no_self_signup ? '' : icon('pencil-square');
|
||||
$angeltype->shift_self_signup_allowed = $angeltype->shift_self_signup ? icon('pencil-square') : '';
|
||||
|
||||
$angeltype->name = '<a href="'
|
||||
. page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id])
|
||||
. url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id])
|
||||
. '">'
|
||||
. $angeltype->name
|
||||
. htmlspecialchars($angeltype->name)
|
||||
. '</a>';
|
||||
|
||||
$angeltype->actions = table_buttons($actions);
|
||||
|
|
|
@ -17,7 +17,7 @@ function event_config_title()
|
|||
function event_config_edit_controller()
|
||||
{
|
||||
if (!auth()->can('admin_event_config')) {
|
||||
throw_redirect(page_link_to('/'));
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
$request = request();
|
||||
|
@ -117,8 +117,8 @@ function event_config_edit_controller()
|
|||
$teardown_end_date ? $teardown_end_date->format('Y-m-d H:i') : ''
|
||||
)
|
||||
);
|
||||
success(__('Settings saved.'));
|
||||
throw_redirect(page_link_to('admin_event_config'));
|
||||
success(__('settings.success'));
|
||||
throw_redirect(url('/admin_event_config'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\ShiftsFilter;
|
||||
use Engelsystem\ShiftsFilterRenderer;
|
||||
|
||||
/**
|
||||
* Room controllers for managing everything room related.
|
||||
* Location controllers for managing everything location related.
|
||||
*/
|
||||
|
||||
/**
|
||||
* View a room with its shifts.
|
||||
* View a location with its shifts.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function room_controller(): array
|
||||
function location_controller(): array
|
||||
{
|
||||
if (!auth()->can('view_rooms')) {
|
||||
throw_redirect(page_link_to());
|
||||
if (!auth()->can('view_locations')) {
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
$request = request();
|
||||
$room = load_room();
|
||||
$location = load_location();
|
||||
|
||||
$all_shifts = $room->shifts->sortBy('start');
|
||||
$all_shifts = $location->shifts->sortBy('start');
|
||||
$days = [];
|
||||
foreach ($all_shifts as $shift) {
|
||||
$day = $shift->start->format('Y-m-d');
|
||||
if (!isset($days[$day])) {
|
||||
$days[$day] = $shift->start->format(__('Y-m-d'));
|
||||
$days[$day] = dateWithEventDay($day);
|
||||
}
|
||||
}
|
||||
|
||||
$shiftsFilter = new ShiftsFilter(
|
||||
true,
|
||||
[$room->id],
|
||||
[$location->id],
|
||||
AngelType::query()->get('id')->pluck('id')->toArray()
|
||||
);
|
||||
$selected_day = date('Y-m-d');
|
||||
|
@ -53,17 +53,17 @@ function room_controller(): array
|
|||
$shiftCalendarRenderer = shiftCalendarRendererByShiftFilter($shiftsFilter);
|
||||
|
||||
return [
|
||||
$room->name,
|
||||
Room_view($room, $shiftsFilterRenderer, $shiftCalendarRenderer),
|
||||
htmlspecialchars($location->name),
|
||||
location_view($location, $shiftsFilterRenderer, $shiftCalendarRenderer),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch different room actions.
|
||||
* Dispatch different location actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function rooms_controller(): array
|
||||
function locations_controller(): array
|
||||
{
|
||||
$request = request();
|
||||
$action = $request->input('action');
|
||||
|
@ -72,36 +72,36 @@ function rooms_controller(): array
|
|||
}
|
||||
|
||||
return match ($action) {
|
||||
'view' => room_controller(),
|
||||
'list' => throw_redirect(page_link_to('admin/rooms')),
|
||||
default => throw_redirect(page_link_to('admin/rooms')),
|
||||
'view' => location_controller(),
|
||||
'list' => throw_redirect(url('/admin/locations')),
|
||||
default => throw_redirect(url('/admin/locations')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Room $room
|
||||
* @param Location $location
|
||||
* @return string
|
||||
*/
|
||||
function room_link(Room $room)
|
||||
function location_link(Location $location)
|
||||
{
|
||||
return page_link_to('rooms', ['action' => 'view', 'room_id' => $room->id]);
|
||||
return url('/locations', ['action' => 'view', 'location_id' => $location->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads room by request param room_id
|
||||
* Loads location by request param location_id
|
||||
*
|
||||
* @return Room
|
||||
* @return Location
|
||||
*/
|
||||
function load_room()
|
||||
function load_location()
|
||||
{
|
||||
if (!test_request_int('room_id')) {
|
||||
throw_redirect(page_link_to());
|
||||
if (!test_request_int('location_id')) {
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
$room = Room::find(request()->input('room_id'));
|
||||
if (!$room) {
|
||||
throw_redirect(page_link_to());
|
||||
$location = Location::find(request()->input('location_id'));
|
||||
if (!$location) {
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
return $room;
|
||||
return $location;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\Models\News;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\ShiftsFilter;
|
||||
|
||||
|
@ -15,22 +15,22 @@ function public_dashboard_controller()
|
|||
{
|
||||
$filter = null;
|
||||
if (request()->get('filtered')) {
|
||||
$requestRooms = check_request_int_array('rooms');
|
||||
$requestLocations = check_request_int_array('locations');
|
||||
$requestAngelTypes = check_request_int_array('types');
|
||||
|
||||
if (!$requestRooms && !$requestAngelTypes) {
|
||||
if (!$requestLocations && !$requestAngelTypes) {
|
||||
$sessionFilter = collect(session()->get('shifts-filter', []));
|
||||
$requestRooms = $sessionFilter->get('rooms', []);
|
||||
$requestLocations = $sessionFilter->get('locations', []);
|
||||
$requestAngelTypes = $sessionFilter->get('types', []);
|
||||
}
|
||||
|
||||
$angelTypes = collect(unrestricted_angeltypes());
|
||||
$rooms = $requestRooms ?: Room::orderBy('name')->get()->pluck('id')->toArray();
|
||||
$locations = $requestLocations ?: Location::orderBy('name')->get()->pluck('id')->toArray();
|
||||
$angelTypes = $requestAngelTypes ?: $angelTypes->pluck('id')->toArray();
|
||||
$filterValues = [
|
||||
'userShiftsAdmin' => false,
|
||||
'filled' => [],
|
||||
'rooms' => $rooms,
|
||||
'locations' => $locations,
|
||||
'types' => $angelTypes,
|
||||
'startTime' => null,
|
||||
'endTime' => null,
|
||||
|
@ -57,14 +57,14 @@ function public_dashboard_controller()
|
|||
}
|
||||
}
|
||||
|
||||
$important_news = News::whereIsImportant(true)
|
||||
$highlighted_news = News::whereIsHighlighted(true)
|
||||
->orderBy('updated_at')
|
||||
->limit(1)
|
||||
->get();
|
||||
|
||||
return [
|
||||
__('Public Dashboard'),
|
||||
public_dashboard_view($stats, $free_shifts, $important_news),
|
||||
public_dashboard_view($stats, $free_shifts, $highlighted_news),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ function public_dashboard_controller_free_shift(Shift $shift, ShiftsFilter $filt
|
|||
'duration' => round(($shift->end->timestamp - $shift->start->timestamp) / 3600),
|
||||
'shifttype_name' => $shift->shiftType->name,
|
||||
'title' => $shift->title,
|
||||
'room_name' => $shift->room->name,
|
||||
'location_name' => $shift->location->name,
|
||||
'needed_angels' => public_dashboard_needed_angels($shift->neededAngels, $filter),
|
||||
];
|
||||
|
||||
|
@ -136,5 +136,5 @@ function public_dashboard_needed_angels($needed_angels, ShiftsFilter $filter = n
|
|||
*/
|
||||
function public_dashboard_link(array $parameters = []): string
|
||||
{
|
||||
return page_link_to('public-dashboard', $parameters);
|
||||
return url('/public-dashboard', $parameters);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ function shift_entries_controller(): array
|
|||
{
|
||||
$user = auth()->user();
|
||||
if (!$user) {
|
||||
throw_redirect(page_link_to('login'));
|
||||
throw_redirect(url('/login'));
|
||||
}
|
||||
|
||||
$action = strip_request_item('action');
|
||||
|
@ -44,7 +44,7 @@ function shift_entry_create_controller(): array
|
|||
$request = request();
|
||||
|
||||
if ($user->isFreeloader()) {
|
||||
throw_redirect(page_link_to('user_myshifts'));
|
||||
throw_redirect(url('/user_myshifts'));
|
||||
}
|
||||
|
||||
$shift = Shift($request->input('shift_id'));
|
||||
|
@ -113,17 +113,21 @@ function shift_entry_create_controller_admin(Shift $shift, ?AngelType $angeltype
|
|||
}
|
||||
|
||||
/** @var User[]|Collection $users */
|
||||
$users = User::query()->orderBy('name')->get();
|
||||
$users = User::with('userAngelTypes')->orderBy('name')->get();
|
||||
$users_select = [];
|
||||
foreach ($users as $user) {
|
||||
$users_select[$user->id] = $user->displayName;
|
||||
$name = $user->displayName;
|
||||
if ($user->userAngelTypes->where('id', $angeltype->id)->isEmpty()) {
|
||||
$name = __('%s (not "%s")', [$name, $angeltype->name]);
|
||||
}
|
||||
$users_select[$user->id] = $name;
|
||||
}
|
||||
|
||||
$angeltypes_select = $angeltypes->pluck('name', 'id')->toArray();
|
||||
$room = $shift->room;
|
||||
$location = $shift->location;
|
||||
return [
|
||||
ShiftEntry_create_title(),
|
||||
ShiftEntry_create_view_admin($shift, $room, $angeltype, $angeltypes_select, $signup_user, $users_select),
|
||||
ShiftEntry_create_view_admin($shift, $location, $angeltype, $angeltypes_select, $signup_user, $users_select),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -167,10 +171,10 @@ function shift_entry_create_controller_supporter(Shift $shift, AngelType $angelt
|
|||
$users_select[$u->id] = $u->displayName;
|
||||
}
|
||||
|
||||
$room = $shift->room;
|
||||
$location = $shift->location;
|
||||
return [
|
||||
ShiftEntry_create_title(),
|
||||
ShiftEntry_create_view_supporter($shift, $room, $angeltype, $signup_user, $users_select),
|
||||
ShiftEntry_create_view_supporter($shift, $location, $angeltype, $signup_user, $users_select),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -250,10 +254,10 @@ function shift_entry_create_controller_user(Shift $shift, AngelType $angeltype):
|
|||
throw_redirect(shift_link($shift));
|
||||
}
|
||||
|
||||
$room = $shift->room;
|
||||
$location = $shift->location;
|
||||
return [
|
||||
ShiftEntry_create_title(),
|
||||
ShiftEntry_create_view_user($shift, $room, $angeltype, $comment),
|
||||
ShiftEntry_create_view_user($shift, $location, $angeltype, $comment),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -272,7 +276,7 @@ function shift_entry_create_link(Shift $shift, AngelType $angeltype, $params = [
|
|||
'shift_id' => $shift->id,
|
||||
'angeltype_id' => $angeltype->id,
|
||||
], $params);
|
||||
return page_link_to('shift_entries', $params);
|
||||
return url('/shift-entries', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -288,7 +292,7 @@ function shift_entry_create_link_admin(Shift $shift, $params = [])
|
|||
'action' => 'create',
|
||||
'shift_id' => $shift->id,
|
||||
], $params);
|
||||
return page_link_to('shift_entries', $params);
|
||||
return url('/shift-entries', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -301,7 +305,7 @@ function shift_entry_load()
|
|||
$request = request();
|
||||
|
||||
if (!$request->has('shift_entry_id') || !test_request_int('shift_entry_id')) {
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
throw_redirect(url('/user-shifts'));
|
||||
}
|
||||
$shiftEntry = ShiftEntry::findOrFail($request->input('shift_entry_id'));
|
||||
|
||||
|
@ -362,5 +366,5 @@ function shift_entry_delete_link($shiftEntry, $params = [])
|
|||
'action' => 'delete',
|
||||
'shift_entry_id' => $shiftEntry['shift_entry_id'] ?? $shiftEntry['id'],
|
||||
], $params);
|
||||
return page_link_to('shift_entries', $params);
|
||||
return url('/shift-entries', $params);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Shifts\ScheduleShift;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftType;
|
||||
|
@ -20,7 +20,7 @@ function shift_link($shift)
|
|||
$parameters['shift_id'] = $shift['shift_id'] ?? $shift['id'];
|
||||
}
|
||||
|
||||
return page_link_to('shifts', $parameters);
|
||||
return url('/shifts', $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,7 +29,7 @@ function shift_link($shift)
|
|||
*/
|
||||
function shift_delete_link(Shift $shift)
|
||||
{
|
||||
return page_link_to('user_shifts', ['delete_shift' => $shift->id]);
|
||||
return url('/user-shifts', ['delete_shift' => $shift->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,7 +38,7 @@ function shift_delete_link(Shift $shift)
|
|||
*/
|
||||
function shift_edit_link(Shift $shift)
|
||||
{
|
||||
return page_link_to('user_shifts', ['edit_shift' => $shift->id]);
|
||||
return url('/user-shifts', ['edit_shift' => $shift->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,11 +52,11 @@ function shift_edit_controller()
|
|||
$request = request();
|
||||
|
||||
if (!auth()->can('admin_shifts')) {
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
throw_redirect(url('/user-shifts'));
|
||||
}
|
||||
|
||||
if (!$request->has('edit_shift') || !test_request_int('edit_shift')) {
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
throw_redirect(url('/user-shifts'));
|
||||
}
|
||||
$shift_id = $request->input('edit_shift');
|
||||
|
||||
|
@ -67,14 +67,14 @@ function shift_edit_controller()
|
|||
));
|
||||
}
|
||||
|
||||
$rooms = [];
|
||||
foreach (Room::orderBy('name')->get() as $room) {
|
||||
$rooms[$room->id] = $room->name;
|
||||
$locations = [];
|
||||
foreach (Location::orderBy('name')->get() as $location) {
|
||||
$locations[$location->id] = $location->name;
|
||||
}
|
||||
$angeltypes = AngelType::all()->pluck('name', 'id')->toArray();
|
||||
$shifttypes = ShiftType::all()->pluck('name', 'id')->toArray();
|
||||
|
||||
$needed_angel_types = collect(NeededAngelTypes_by_shift($shift_id))->pluck('count', 'angel_type_id')->toArray();
|
||||
$needed_angel_types = collect(NeededAngelTypes_by_shift($shift))->pluck('count', 'angel_type_id')->toArray();
|
||||
foreach (array_keys($angeltypes) as $angeltype_id) {
|
||||
if (!isset($needed_angel_types[$angeltype_id])) {
|
||||
$needed_angel_types[$angeltype_id] = 0;
|
||||
|
@ -84,7 +84,7 @@ function shift_edit_controller()
|
|||
$shifttype_id = $shift->shift_type_id;
|
||||
$title = $shift->title;
|
||||
$description = $shift->description;
|
||||
$rid = $shift->room_id;
|
||||
$rid = $shift->location_id;
|
||||
$start = $shift->start;
|
||||
$end = $shift->end;
|
||||
|
||||
|
@ -97,12 +97,12 @@ function shift_edit_controller()
|
|||
if (
|
||||
$request->has('rid')
|
||||
&& preg_match('/^\d+$/', $request->input('rid'))
|
||||
&& isset($rooms[$request->input('rid')])
|
||||
&& isset($locations[$request->input('rid')])
|
||||
) {
|
||||
$rid = $request->input('rid');
|
||||
} else {
|
||||
$valid = false;
|
||||
error(__('Please select a room.'));
|
||||
error(__('Please select a location.'));
|
||||
}
|
||||
|
||||
if ($request->has('shifttype_id') && isset($shifttypes[$request->input('shifttype_id')])) {
|
||||
|
@ -154,13 +154,16 @@ function shift_edit_controller()
|
|||
$shift->shift_type_id = $shifttype_id;
|
||||
$shift->title = $title;
|
||||
$shift->description = $description;
|
||||
$shift->room_id = $rid;
|
||||
$shift->location_id = $rid;
|
||||
$shift->start = $start;
|
||||
$shift->end = $end;
|
||||
$shift->updatedBy()->associate(auth()->user());
|
||||
$shift->save();
|
||||
|
||||
mail_shift_change($oldShift, $shift);
|
||||
event('shift.updating', [
|
||||
'shift' => $shift,
|
||||
'oldShift' => $oldShift,
|
||||
]);
|
||||
|
||||
NeededAngelType::whereShiftId($shift_id)->delete();
|
||||
$needed_angel_types_info = [];
|
||||
|
@ -194,13 +197,16 @@ function shift_edit_controller()
|
|||
foreach ($angeltypes as $angeltype_id => $angeltype_name) {
|
||||
$angel_types_spinner .= form_spinner(
|
||||
'angeltype_count_' . $angeltype_id,
|
||||
$angeltype_name,
|
||||
$needed_angel_types[$angeltype_id]
|
||||
htmlspecialchars($angeltype_name),
|
||||
$needed_angel_types[$angeltype_id],
|
||||
[],
|
||||
ScheduleShift::whereShiftId($shift->id)->first() ? true : false,
|
||||
);
|
||||
}
|
||||
|
||||
$link = button(url('/shifts', ['action' => 'view', 'shift_id' => $shift_id]), icon('chevron-left'), 'btn-sm', '', __('general.back'));
|
||||
return page_with_title(
|
||||
shifts_title(),
|
||||
$link . ' ' . shifts_title(),
|
||||
[
|
||||
msg(),
|
||||
'<noscript>'
|
||||
|
@ -208,15 +214,18 @@ function shift_edit_controller()
|
|||
. '</noscript>',
|
||||
form([
|
||||
form_select('shifttype_id', __('Shifttype'), $shifttypes, $shifttype_id),
|
||||
form_text('title', __('Title'), $title),
|
||||
form_select('rid', __('Room:'), $rooms, $rid),
|
||||
form_text('title', __('title.title'), $title),
|
||||
form_select('rid', __('Location:'), $locations, $rid),
|
||||
form_text('start', __('Start:'), $start->format('Y-m-d H:i')),
|
||||
form_text('end', __('End:'), $end->format('Y-m-d H:i')),
|
||||
form_textarea('description', __('Additional description'), $description),
|
||||
form_info('', __('This description is for single shifts, otherwise please use the description in shift type.')),
|
||||
form_info(
|
||||
'',
|
||||
__('This description is for single shifts, otherwise please use the description in shift type.')
|
||||
),
|
||||
'<h2>' . __('Needed angels') . '</h2>',
|
||||
$angel_types_spinner,
|
||||
form_submit('submit', __('Save')),
|
||||
form_submit('submit', icon('save') . __('form.save')),
|
||||
]),
|
||||
]
|
||||
);
|
||||
|
@ -230,18 +239,18 @@ function shift_delete_controller()
|
|||
$request = request();
|
||||
|
||||
if (!auth()->can('user_shifts_admin')) {
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
throw_redirect(url('/user-shifts'));
|
||||
}
|
||||
|
||||
// Schicht komplett löschen (nur für admins/user mit user_shifts_admin privileg)
|
||||
if (!$request->has('delete_shift') || !preg_match('/^\d+$/', $request->input('delete_shift'))) {
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
throw_redirect(url('/user-shifts'));
|
||||
}
|
||||
$shift_id = $request->input('delete_shift');
|
||||
|
||||
$shift = Shift($shift_id);
|
||||
if (empty($shift)) {
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
throw_redirect(url('/user-shifts'));
|
||||
}
|
||||
|
||||
// Schicht löschen bestätigt
|
||||
|
@ -254,7 +263,7 @@ function shift_delete_controller()
|
|||
'name' => $shift->shiftType->name,
|
||||
'title' => $shift->title,
|
||||
'type' => $entry->angelType->name,
|
||||
'room' => $shift->room,
|
||||
'location' => $shift->location,
|
||||
'freeloaded' => $entry->freeloaded,
|
||||
]);
|
||||
}
|
||||
|
@ -267,21 +276,25 @@ function shift_delete_controller()
|
|||
. ' to ' . $shift->end->format('Y-m-d H:i')
|
||||
);
|
||||
success(__('Shift deleted.'));
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
throw_redirect(url('/user-shifts'));
|
||||
}
|
||||
|
||||
return page_with_title(shifts_title(), [
|
||||
error(sprintf(
|
||||
__('Do you want to delete the shift %s from %s to %s?'),
|
||||
$shift->shiftType->name,
|
||||
$shift->start->format(__('Y-m-d H:i')),
|
||||
$shift->end->format(__('H:i'))
|
||||
), true),
|
||||
form([
|
||||
form_hidden('delete_shift', $shift->id),
|
||||
form_submit('delete', __('delete')),
|
||||
]),
|
||||
]);
|
||||
$link = button(url('/shifts', ['action' => 'view', 'shift_id' => $shift_id]), icon('chevron-left'), 'btn-sm', '', __('general.back'));
|
||||
return page_with_title(
|
||||
$link . ' ' . shifts_title(),
|
||||
[
|
||||
error(sprintf(
|
||||
__('Do you want to delete the shift %s from %s to %s?'),
|
||||
$shift->shiftType->name,
|
||||
$shift->start->format(__('general.datetime')),
|
||||
$shift->end->format(__('H:i'))
|
||||
), true),
|
||||
form([
|
||||
form_hidden('delete_shift', $shift->id),
|
||||
form_submit('delete', icon('trash') . __('form.delete'), '', true, 'danger'),
|
||||
]),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -293,21 +306,21 @@ function shift_controller()
|
|||
$request = request();
|
||||
|
||||
if (!auth()->can('user_shifts')) {
|
||||
throw_redirect(page_link_to('/'));
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
if (!$request->has('shift_id')) {
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
throw_redirect(url('/user-shifts'));
|
||||
}
|
||||
|
||||
$shift = Shift($request->input('shift_id'));
|
||||
if (empty($shift)) {
|
||||
error(__('Shift could not be found.'));
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
throw_redirect(url('/user-shifts'));
|
||||
}
|
||||
|
||||
$shifttype = $shift->shiftType;
|
||||
$room = $shift->room;
|
||||
$location = $shift->location;
|
||||
/** @var AngelType[] $angeltypes */
|
||||
$angeltypes = AngelType::all();
|
||||
$user_shifts = Shifts_by_user($user->id);
|
||||
|
@ -338,8 +351,8 @@ function shift_controller()
|
|||
}
|
||||
|
||||
return [
|
||||
$shift->shiftType->name,
|
||||
Shift_view($shift, $shifttype, $room, $angeltypes, $shift_signup_state),
|
||||
htmlspecialchars($shift->shiftType->name),
|
||||
Shift_view($shift, $shifttype, $location, $angeltypes, $shift_signup_state),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -350,13 +363,13 @@ function shifts_controller()
|
|||
{
|
||||
$request = request();
|
||||
if (!$request->has('action')) {
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
throw_redirect(url('/user-shifts'));
|
||||
}
|
||||
|
||||
return match ($request->input('action')) {
|
||||
'view' => shift_controller(),
|
||||
'next' => shift_next_controller(), // throws redirect
|
||||
default => throw_redirect(page_link_to('/')),
|
||||
default => throw_redirect(url('/')),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -366,7 +379,7 @@ function shifts_controller()
|
|||
function shift_next_controller()
|
||||
{
|
||||
if (!auth()->can('user_shifts')) {
|
||||
throw_redirect(page_link_to('/'));
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
$upcoming_shifts = ShiftEntries_upcoming_for_user(auth()->user());
|
||||
|
@ -375,5 +388,5 @@ function shift_next_controller()
|
|||
throw_redirect(shift_link($upcoming_shifts[0]->shift));
|
||||
}
|
||||
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
throw_redirect(url('/user-shifts'));
|
||||
}
|
||||
|
|
|
@ -1,163 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Models\Shifts\ShiftType;
|
||||
|
||||
/**
|
||||
* @param ShiftType $shifttype
|
||||
* @return string
|
||||
*/
|
||||
function shifttype_link(ShiftType $shifttype)
|
||||
{
|
||||
return page_link_to('shifttypes', ['action' => 'view', 'shifttype_id' => $shifttype->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a shifttype.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function shifttype_delete_controller()
|
||||
{
|
||||
$request = request();
|
||||
if (!$request->has('shifttype_id')) {
|
||||
throw_redirect(page_link_to('shifttypes'));
|
||||
}
|
||||
|
||||
$shifttype = ShiftType::findOrFail($request->input('shifttype_id'));
|
||||
if ($request->hasPostData('delete')) {
|
||||
engelsystem_log('Deleted shifttype ' . $shifttype->name);
|
||||
success(sprintf(__('Shifttype %s deleted.'), $shifttype->name));
|
||||
|
||||
$shifttype->delete();
|
||||
throw_redirect(page_link_to('shifttypes'));
|
||||
}
|
||||
|
||||
return [
|
||||
sprintf(__('Delete shifttype %s'), $shifttype->name),
|
||||
ShiftType_delete_view($shifttype),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit or create shift type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function shifttype_edit_controller()
|
||||
{
|
||||
$shifttype_id = null;
|
||||
$name = '';
|
||||
$description = '';
|
||||
|
||||
$request = request();
|
||||
|
||||
if ($request->has('shifttype_id')) {
|
||||
$shifttype = ShiftType::findOrFail($request->input('shifttype_id'));
|
||||
$shifttype_id = $shifttype->id;
|
||||
$name = $shifttype->name;
|
||||
$description = $shifttype->description;
|
||||
}
|
||||
|
||||
if ($request->hasPostData('submit')) {
|
||||
$valid = true;
|
||||
|
||||
if ($request->has('name') && $request->input('name') != '') {
|
||||
$name = strip_request_item('name');
|
||||
} else {
|
||||
$valid = false;
|
||||
error(__('Please enter a name.'));
|
||||
}
|
||||
|
||||
if ($request->has('description')) {
|
||||
$description = strip_request_item_nl('description');
|
||||
}
|
||||
|
||||
if ($valid) {
|
||||
$shiftType = ShiftType::findOrNew($shifttype_id);
|
||||
$shiftType->name = $name;
|
||||
$shiftType->description = $description;
|
||||
$shiftType->save();
|
||||
|
||||
if ($shifttype_id) {
|
||||
engelsystem_log('Updated shifttype ' . $name);
|
||||
success(__('Updated shifttype.'));
|
||||
} else {
|
||||
$shifttype_id = $shiftType->id;
|
||||
|
||||
engelsystem_log('Created shifttype ' . $name);
|
||||
success(__('Created shifttype.'));
|
||||
}
|
||||
|
||||
throw_redirect(page_link_to('shifttypes', ['action' => 'view', 'shifttype_id' => $shifttype_id]));
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
shifttypes_title(),
|
||||
ShiftType_edit_view($name, $description, $shifttype_id),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function shifttype_controller()
|
||||
{
|
||||
$request = request();
|
||||
if (!$request->has('shifttype_id')) {
|
||||
throw_redirect(page_link_to('shifttypes'));
|
||||
}
|
||||
$shifttype = ShiftType::findOrFail($request->input('shifttype_id'));
|
||||
|
||||
return [
|
||||
$shifttype->name,
|
||||
ShiftType_view($shifttype),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* List all shift types.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function shifttypes_list_controller()
|
||||
{
|
||||
$shifttypes = ShiftType::all();
|
||||
|
||||
return [
|
||||
shifttypes_title(),
|
||||
ShiftTypes_list_view($shifttypes),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Text for shift type related links.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function shifttypes_title()
|
||||
{
|
||||
return __('Shifttypes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Route shift type actions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function shifttypes_controller()
|
||||
{
|
||||
$request = request();
|
||||
$action = 'list';
|
||||
if ($request->has('action')) {
|
||||
$action = $request->input('action');
|
||||
}
|
||||
|
||||
return match ($action) {
|
||||
'view' => shifttype_controller(),
|
||||
'edit' => shifttype_edit_controller(),
|
||||
'delete' => shifttype_delete_controller(),
|
||||
'list' => shifttypes_list_controller(),
|
||||
default => shifttypes_list_controller(),
|
||||
};
|
||||
}
|
|
@ -5,8 +5,6 @@ use Engelsystem\Models\AngelType;
|
|||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Models\UserAngelType;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Mailer\Exception\TransportException;
|
||||
|
||||
/**
|
||||
* Display a hint for team/angeltype supporters if there are unconfirmed users for his angeltype.
|
||||
|
@ -37,9 +35,9 @@ function user_angeltypes_unconfirmed_hint()
|
|||
|
||||
$unconfirmed_links = [];
|
||||
foreach ($unconfirmed_user_angeltypes as $user_angeltype) {
|
||||
$unconfirmed_links[] = '<a class="text-info" href="'
|
||||
. page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $user_angeltype->angel_type_id])
|
||||
. '">' . $user_angeltype->angelType->name
|
||||
$unconfirmed_links[] = '<a href="'
|
||||
. url('/angeltypes', ['action' => 'view', 'angeltype_id' => $user_angeltype->angel_type_id])
|
||||
. '">' . htmlspecialchars($user_angeltype->angelType->name)
|
||||
. ' (+' . $user_angeltype->count . ')'
|
||||
. '</a>';
|
||||
}
|
||||
|
@ -67,13 +65,13 @@ function user_angeltypes_delete_all_controller(): array
|
|||
|
||||
if (!$request->has('angeltype_id')) {
|
||||
error(__('Angeltype doesn\'t exist.'));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
$angeltype = AngelType::findOrFail($request->input('angeltype_id'));
|
||||
if (!auth()->user()->isAngelTypeSupporter($angeltype) && !auth()->can('admin_user_angeltypes')) {
|
||||
error(__('You are not allowed to delete all users for this angeltype.'));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
if ($request->hasPostData('deny_all')) {
|
||||
|
@ -83,7 +81,7 @@ function user_angeltypes_delete_all_controller(): array
|
|||
|
||||
engelsystem_log(sprintf('Denied all users for angeltype %s', AngelType_name_render($angeltype, true)));
|
||||
success(sprintf(__('Denied all users for angeltype %s.'), $angeltype->name));
|
||||
throw_redirect(page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
throw_redirect(url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -104,13 +102,13 @@ function user_angeltypes_confirm_all_controller(): array
|
|||
|
||||
if (!$request->has('angeltype_id')) {
|
||||
error(__('Angeltype doesn\'t exist.'));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
$angeltype = AngelType::findOrFail($request->input('angeltype_id'));
|
||||
if (!auth()->can('admin_user_angeltypes') && !$user->isAngelTypeSupporter($angeltype)) {
|
||||
error(__('You are not allowed to confirm all users for this angeltype.'));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
if ($request->hasPostData('confirm_all')) {
|
||||
|
@ -127,7 +125,7 @@ function user_angeltypes_confirm_all_controller(): array
|
|||
user_angeltype_confirm_email($user, $angeltype);
|
||||
}
|
||||
|
||||
throw_redirect(page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
throw_redirect(url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -148,7 +146,7 @@ function user_angeltype_confirm_controller(): array
|
|||
|
||||
if (!$request->has('user_angeltype_id')) {
|
||||
error(__('User angeltype doesn\'t exist.'));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
/** @var UserAngelType $user_angeltype */
|
||||
|
@ -156,7 +154,7 @@ function user_angeltype_confirm_controller(): array
|
|||
$angeltype = $user_angeltype->angelType;
|
||||
if (!$user->isAngelTypeSupporter($angeltype) && !auth()->can('admin_user_angeltypes')) {
|
||||
error(__('You are not allowed to confirm this users angeltype.'));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
$user_source = $user_angeltype->user;
|
||||
|
@ -173,7 +171,7 @@ function user_angeltype_confirm_controller(): array
|
|||
|
||||
user_angeltype_confirm_email($user_source, $angeltype);
|
||||
|
||||
throw_redirect(page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
throw_redirect(url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -188,23 +186,14 @@ function user_angeltype_confirm_email(User $user, AngelType $angeltype): void
|
|||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var EngelsystemMailer $mailer */
|
||||
$mailer = app(EngelsystemMailer::class);
|
||||
$mailer->sendViewTranslated(
|
||||
$user,
|
||||
'notification.angeltype.confirmed',
|
||||
'emails/angeltype-confirmed',
|
||||
['name' => $angeltype->name, 'angeltype' => $angeltype, 'username' => $user->displayName]
|
||||
);
|
||||
} catch (TransportException $e) {
|
||||
/** @var LoggerInterface $logger */
|
||||
$logger = app('logger');
|
||||
$logger->error(
|
||||
'Unable to send email "{title}" to user {user} with {exception}',
|
||||
['title' => __('notification.angeltype.confirmed'), 'user' => $user->name, 'exception' => $e]
|
||||
);
|
||||
}
|
||||
/** @var EngelsystemMailer $mailer */
|
||||
$mailer = app(EngelsystemMailer::class);
|
||||
$mailer->sendViewTranslated(
|
||||
$user,
|
||||
'notification.angeltype.confirmed',
|
||||
'emails/angeltype-confirmed',
|
||||
['name' => $angeltype->name, 'angeltype' => $angeltype, 'username' => $user->displayName]
|
||||
);
|
||||
}
|
||||
|
||||
function user_angeltype_add_email(User $user, AngelType $angeltype): void
|
||||
|
@ -213,23 +202,14 @@ function user_angeltype_add_email(User $user, AngelType $angeltype): void
|
|||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var EngelsystemMailer $mailer */
|
||||
$mailer = app(EngelsystemMailer::class);
|
||||
$mailer->sendViewTranslated(
|
||||
$user,
|
||||
'notification.angeltype.added',
|
||||
'emails/angeltype-added',
|
||||
['name' => $angeltype->name, 'angeltype' => $angeltype, 'username' => $user->displayName]
|
||||
);
|
||||
} catch (TransportException $e) {
|
||||
/** @var LoggerInterface $logger */
|
||||
$logger = app('logger');
|
||||
$logger->error(
|
||||
'Unable to send email "{title}" to user {user} with {exception}',
|
||||
['title' => __('notification.angeltype.added'), 'user' => $user->name, 'exception' => $e]
|
||||
);
|
||||
}
|
||||
/** @var EngelsystemMailer $mailer */
|
||||
$mailer = app(EngelsystemMailer::class);
|
||||
$mailer->sendViewTranslated(
|
||||
$user,
|
||||
'notification.angeltype.added',
|
||||
'emails/angeltype-added',
|
||||
['name' => $angeltype->name, 'angeltype' => $angeltype, 'username' => $user->displayName]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,7 +224,7 @@ function user_angeltype_delete_controller(): array
|
|||
|
||||
if (!$request->has('user_angeltype_id')) {
|
||||
error(__('User angeltype doesn\'t exist.'));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
/** @var UserAngelType $user_angeltype */
|
||||
|
@ -257,7 +237,7 @@ function user_angeltype_delete_controller(): array
|
|||
&& !auth()->can('admin_user_angeltypes')
|
||||
) {
|
||||
error(__('You are not allowed to delete this users angeltype.'));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
if ($request->hasPostData('delete')) {
|
||||
|
@ -266,7 +246,7 @@ function user_angeltype_delete_controller(): array
|
|||
engelsystem_log(sprintf('User %s removed from %s.', User_Nick_render($user_source, true), $angeltype->name));
|
||||
success(sprintf(__('User %s removed from %s.'), $user_source->displayName, $angeltype->name));
|
||||
|
||||
throw_redirect(page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
throw_redirect(url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -287,19 +267,19 @@ function user_angeltype_update_controller(): array
|
|||
|
||||
if (!auth()->can('admin_angel_types')) {
|
||||
error(__('You are not allowed to set supporter rights.'));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
if (!$request->has('user_angeltype_id')) {
|
||||
error(__('User angeltype doesn\'t exist.'));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
if ($request->has('supporter') && preg_match('/^[01]$/', $request->input('supporter'))) {
|
||||
$supporter = $request->input('supporter') == '1';
|
||||
} else {
|
||||
error(__('No supporter update given.'));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
/** @var UserAngelType $user_angeltype */
|
||||
|
@ -321,7 +301,7 @@ function user_angeltype_update_controller(): array
|
|||
));
|
||||
success(sprintf($msg, $angeltype->name, $user_source->displayName));
|
||||
|
||||
throw_redirect(page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
throw_redirect(url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -382,7 +362,7 @@ function user_angeltype_add_controller(): array
|
|||
|
||||
user_angeltype_add_email($user_source, $angeltype);
|
||||
|
||||
throw_redirect(page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
throw_redirect(url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -406,7 +386,7 @@ function user_angeltype_join_controller(AngelType $angeltype)
|
|||
$user_angeltype = UserAngelType::whereUserId($user->id)->where('angel_type_id', $angeltype->id)->first();
|
||||
if (!empty($user_angeltype)) {
|
||||
error(sprintf(__('You are already a %s.'), $angeltype->name));
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
$request = request();
|
||||
|
@ -434,11 +414,11 @@ function user_angeltype_join_controller(AngelType $angeltype)
|
|||
));
|
||||
}
|
||||
|
||||
throw_redirect(page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
throw_redirect(url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
|
||||
}
|
||||
|
||||
return [
|
||||
sprintf(__('Become a %s'), $angeltype->name),
|
||||
sprintf(__('Become a %s'), htmlspecialchars($angeltype->name)),
|
||||
UserAngelType_join_view($user, $angeltype),
|
||||
];
|
||||
}
|
||||
|
@ -452,7 +432,7 @@ function user_angeltypes_controller(): array
|
|||
{
|
||||
$request = request();
|
||||
if (!$request->has('action')) {
|
||||
throw_redirect(page_link_to('angeltypes'));
|
||||
throw_redirect(url('/angeltypes'));
|
||||
}
|
||||
|
||||
return match ($request->input('action')) {
|
||||
|
@ -462,6 +442,6 @@ function user_angeltypes_controller(): array
|
|||
'delete' => user_angeltype_delete_controller(),
|
||||
'update' => user_angeltype_update_controller(),
|
||||
'add' => user_angeltype_add_controller(),
|
||||
default => throw_redirect(page_link_to('angeltyps')),
|
||||
default => throw_redirect(url('/angeltyps')),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Models\User\User;
|
||||
|
||||
/**
|
||||
* Generates a hint, if user joined angeltypes that require a driving license and the user has no driver license
|
||||
* information provided.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
function user_driver_license_required_hint()
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
// User has already entered data, no hint needed.
|
||||
if ($user->license->wantsToDrive()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$angeltypes = $user->userAngelTypes;
|
||||
foreach ($angeltypes as $angeltype) {
|
||||
if ($angeltype->requires_driver_license) {
|
||||
return sprintf(
|
||||
__('You joined an angeltype which requires a driving license. Please edit your driving license information here: %s.'),
|
||||
'<a href="' . user_driver_license_edit_link() . '" class="text-info">' . __('driving license information') . '</a>'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Route user driver licenses actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function user_driver_licenses_controller()
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
if (!$user) {
|
||||
throw_redirect(page_link_to());
|
||||
}
|
||||
|
||||
$action = strip_request_item('action', 'edit');
|
||||
|
||||
return match ($action) {
|
||||
'edit' => user_driver_license_edit_controller(),
|
||||
default => user_driver_license_edit_controller(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Link to user driver license edit page for given user.
|
||||
*
|
||||
* @param User $user
|
||||
* @return string
|
||||
*/
|
||||
function user_driver_license_edit_link($user = null)
|
||||
{
|
||||
if (!$user) {
|
||||
return page_link_to('user_driver_licenses');
|
||||
}
|
||||
|
||||
return page_link_to('user_driver_licenses', ['user_id' => $user->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the user for the driver license.
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
function user_driver_license_load_user()
|
||||
{
|
||||
$request = request();
|
||||
$user_source = auth()->user();
|
||||
|
||||
if ($request->has('user_id')) {
|
||||
$user_source = User::find($request->input('user_id'));
|
||||
if (empty($user_source)) {
|
||||
throw_redirect(user_driver_license_edit_link());
|
||||
}
|
||||
}
|
||||
|
||||
return $user_source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a users driver license information.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function user_driver_license_edit_controller()
|
||||
{
|
||||
$user = auth()->user();
|
||||
$request = request();
|
||||
$user_source = user_driver_license_load_user();
|
||||
|
||||
// only privilege admin_user can edit other users driver license information
|
||||
if ($user->id != $user_source->id && !auth()->can('admin_user')) {
|
||||
throw_redirect(user_driver_license_edit_link());
|
||||
}
|
||||
|
||||
$driverLicense = $user_source->license;
|
||||
if ($request->hasPostData('submit')) {
|
||||
if ($request->has('wants_to_drive')) {
|
||||
$driverLicense->has_car = $request->has('has_car');
|
||||
$driverLicense->drive_car = $request->has('has_license_car');
|
||||
$driverLicense->drive_3_5t = $request->has('has_license_3_5t_transporter');
|
||||
$driverLicense->drive_7_5t = $request->has('has_license_7_5t_truck');
|
||||
$driverLicense->drive_12t = $request->has('has_license_12t_truck');
|
||||
$driverLicense->drive_forklift = $request->has('has_license_forklift');
|
||||
|
||||
if ($driverLicense->wantsToDrive()) {
|
||||
$driverLicense->save();
|
||||
|
||||
engelsystem_log('Driver license information updated.');
|
||||
success(__('Your driver license information has been saved.'));
|
||||
throw_redirect(user_link($user_source->id));
|
||||
} else {
|
||||
error(__('Please select at least one driving license.'));
|
||||
}
|
||||
} else {
|
||||
$driverLicense->has_car = false;
|
||||
$driverLicense->drive_car = false;
|
||||
$driverLicense->drive_3_5t = false;
|
||||
$driverLicense->drive_7_5t = false;
|
||||
$driverLicense->drive_12t = false;
|
||||
$driverLicense->drive_forklift = false;
|
||||
$driverLicense->save();
|
||||
|
||||
engelsystem_log('Driver license information removed.');
|
||||
success(__('Your driver license information has been removed.'));
|
||||
throw_redirect(user_link($user_source->id));
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
sprintf(__('Edit %s driving license information'), $user_source->displayName),
|
||||
UserDriverLicense_edit_view($user_source, $driverLicense),
|
||||
];
|
||||
}
|
|
@ -20,7 +20,7 @@ function users_controller()
|
|||
$request = request();
|
||||
|
||||
if (!$user) {
|
||||
throw_redirect(page_link_to());
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
$action = 'list';
|
||||
|
@ -55,7 +55,7 @@ function user_delete_controller()
|
|||
}
|
||||
|
||||
if (!auth()->can('admin_user')) {
|
||||
throw_redirect(page_link_to());
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
// You cannot delete yourself
|
||||
|
@ -91,7 +91,7 @@ function user_delete_controller()
|
|||
}
|
||||
|
||||
return [
|
||||
sprintf(__('Delete %s'), $user_source->displayName),
|
||||
sprintf(__('Delete %s'), htmlspecialchars($user_source->displayName)),
|
||||
User_delete_view($user_source),
|
||||
];
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ function user_delete_controller()
|
|||
*/
|
||||
function users_link()
|
||||
{
|
||||
return page_link_to('users');
|
||||
return url('/users');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,7 +110,7 @@ function users_link()
|
|||
*/
|
||||
function user_edit_link($userId)
|
||||
{
|
||||
return page_link_to('admin_user', ['user_id' => $userId]);
|
||||
return url('/admin-user', ['user_id' => $userId]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,7 +119,7 @@ function user_edit_link($userId)
|
|||
*/
|
||||
function user_delete_link($userId)
|
||||
{
|
||||
return page_link_to('users', ['action' => 'delete', 'user_id' => $userId]);
|
||||
return url('/users', ['action' => 'delete', 'user_id' => $userId]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,7 +128,7 @@ function user_delete_link($userId)
|
|||
*/
|
||||
function user_link($userId)
|
||||
{
|
||||
return page_link_to('users', ['action' => 'view', 'user_id' => $userId]);
|
||||
return url('/users', ['action' => 'view', 'user_id' => $userId]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,7 +149,7 @@ function user_edit_vouchers_controller()
|
|||
(!auth()->can('admin_user') && !auth()->can('voucher.edit'))
|
||||
|| !config('enable_voucher')
|
||||
) {
|
||||
throw_redirect(page_link_to());
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
if ($request->hasPostData('submit')) {
|
||||
|
@ -182,7 +182,7 @@ function user_edit_vouchers_controller()
|
|||
}
|
||||
|
||||
return [
|
||||
sprintf(__('%s\'s vouchers'), $user_source->displayName),
|
||||
sprintf(__('%s\'s vouchers'), htmlspecialchars($user_source->displayName)),
|
||||
User_edit_vouchers_view($user_source),
|
||||
];
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ function user_controller()
|
|||
$user_source = User::find($request->input('user_id'));
|
||||
if (!$user_source) {
|
||||
error(__('User not found.'));
|
||||
throw_redirect(page_link_to('/'));
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,7 +234,7 @@ function user_controller()
|
|||
}
|
||||
|
||||
if (empty($user_source->api_key)) {
|
||||
User_reset_api_key($user_source, false);
|
||||
auth()->resetApiKey($user_source);
|
||||
}
|
||||
|
||||
if ($user_source->state->force_active) {
|
||||
|
@ -244,7 +244,7 @@ function user_controller()
|
|||
}
|
||||
|
||||
return [
|
||||
$user_source->displayName,
|
||||
htmlspecialchars($user_source->displayName),
|
||||
User_view(
|
||||
$user_source,
|
||||
auth()->can('admin_user'),
|
||||
|
@ -271,7 +271,7 @@ function users_list_controller()
|
|||
$request = request();
|
||||
|
||||
if (!auth()->can('admin_user')) {
|
||||
throw_redirect(page_link_to());
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
$order_by = 'name';
|
||||
|
@ -343,13 +343,13 @@ function load_user()
|
|||
{
|
||||
$request = request();
|
||||
if (!$request->has('user_id')) {
|
||||
throw_redirect(page_link_to());
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
$user = User::find($request->input('user_id'));
|
||||
if (!$user) {
|
||||
error(__('User doesn\'t exist.'));
|
||||
throw_redirect(page_link_to());
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
return $user;
|
||||
|
@ -437,3 +437,57 @@ function shiftCalendarRendererByShiftFilter(ShiftsFilter $shiftsFilter)
|
|||
|
||||
return new ShiftCalendarRenderer($filtered_shifts, $needed_angeltypes, $shift_entries, $shiftsFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a hint, if user joined angeltypes that require a driving license and the user has no driver license
|
||||
* information provided.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
function user_driver_license_required_hint()
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
// User has already entered data, no hint needed.
|
||||
if ($user->license->wantsToDrive()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$angeltypes = $user->userAngelTypes;
|
||||
foreach ($angeltypes as $angeltype) {
|
||||
if ($angeltype->requires_driver_license) {
|
||||
return sprintf(
|
||||
__('angeltype.driving_license.required.info.here'),
|
||||
'<a href="' . url('/settings/certificates') . '">' . __('driving_license.info') . '</a>'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function user_ifsg_certificate_required_hint()
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
// User has already entered data, no hint needed.
|
||||
if (!config('ifsg_enabled') || $user->license->ifsg_light || $user->license->ifsg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$angeltypes = $user->userAngelTypes;
|
||||
foreach ($angeltypes as $angeltype) {
|
||||
if (
|
||||
$angeltype->requires_ifsg_certificate && !(
|
||||
$user->license->ifsg_certificate || $user->license->ifsg_certificate_light
|
||||
)
|
||||
) {
|
||||
return sprintf(
|
||||
__('angeltype.ifsg.required.info.here'),
|
||||
'<a href="' . url('/settings/certificates') . '">' . __('ifsg.info') . '</a>'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ if ($app->get('config')->get('maintenance')) {
|
|||
http_response_code(503);
|
||||
$url = $app->get(UrlGeneratorInterface::class);
|
||||
$maintenance = file_get_contents(__DIR__ . '/../resources/views/layouts/maintenance.html');
|
||||
$maintenance = str_replace('%APP_NAME%', $app->get('config')->get('app_name'), $maintenance);
|
||||
$maintenance = str_replace('%APP_NAME%', htmlspecialchars($app->get('config')->get('app_name')), $maintenance);
|
||||
$maintenance = str_replace('%ASSETS_PATH%', $url->to(''), $maintenance);
|
||||
echo $maintenance;
|
||||
die();
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Helpers\Translation\Translator;
|
||||
use Engelsystem\Mail\EngelsystemMailer;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
/**
|
||||
* @param User $recipientUser
|
||||
|
@ -18,38 +16,18 @@ function engelsystem_email_to_user($recipientUser, $title, $message, $notIfItsMe
|
|||
return true;
|
||||
}
|
||||
|
||||
/** @var Translator $translator */
|
||||
$translator = app()->get('translator');
|
||||
$locale = $translator->getLocale();
|
||||
|
||||
$status = true;
|
||||
try {
|
||||
/** @var EngelsystemMailer $mailer */
|
||||
$mailer = app('mailer');
|
||||
|
||||
$translator->setLocale($recipientUser->settings->language);
|
||||
$mailer->sendView(
|
||||
$recipientUser->contact->email ?: $recipientUser->email,
|
||||
$title,
|
||||
'emails/mail',
|
||||
['username' => $recipientUser->displayName, 'message' => $message]
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
$status = false;
|
||||
engelsystem_log(sprintf(
|
||||
'An exception occurred while sending a mail to %s in %s:%u: %s',
|
||||
$recipientUser->name,
|
||||
$e->getFile(),
|
||||
$e->getLine(),
|
||||
$e->getMessage()
|
||||
), LogLevel::CRITICAL);
|
||||
}
|
||||
|
||||
$translator->setLocale($locale);
|
||||
/** @var EngelsystemMailer $mailer */
|
||||
$mailer = app('mailer');
|
||||
$status = $mailer->sendViewTranslated(
|
||||
$recipientUser,
|
||||
$title,
|
||||
'emails/mail',
|
||||
['username' => $recipientUser->displayName, 'message' => $message]
|
||||
);
|
||||
|
||||
if (!$status) {
|
||||
error(sprintf(__('User %s could not be notified by email due to an error.'), $recipientUser->displayName));
|
||||
engelsystem_log(sprintf('User %s could not be notified by email due to an error.', $recipientUser->name));
|
||||
error(sprintf(__('User %s could not be notified by e-mail due to an error.'), $recipientUser->displayName));
|
||||
engelsystem_log(sprintf('User %s could not be notified by e-mail due to an error.', $recipientUser->name));
|
||||
}
|
||||
|
||||
return $status;
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
use Engelsystem\Renderer\Twig\Extensions\Globals;
|
||||
use Engelsystem\Helpers\Carbon;
|
||||
use Engelsystem\Helpers\DayOfEvent;
|
||||
|
||||
function theme_id(): int
|
||||
{
|
||||
|
@ -25,3 +27,16 @@ function theme_type(): string
|
|||
{
|
||||
return theme()['type'];
|
||||
}
|
||||
|
||||
function dateWithEventDay(string $day): string
|
||||
{
|
||||
$date = Carbon::createFromFormat('Y-m-d', $day);
|
||||
$dayOfEvent = DayOfEvent::get($date);
|
||||
$dateFormatted = $date->format(__('general.date'));
|
||||
|
||||
if (!config('enable_show_day_of_event') || is_null($dayOfEvent)) {
|
||||
return $dateFormatted;
|
||||
}
|
||||
|
||||
return $dateFormatted . ' (' . $dayOfEvent . ')';
|
||||
}
|
||||
|
|
|
@ -17,11 +17,12 @@ function msg()
|
|||
*
|
||||
* @param string $msg
|
||||
* @param bool $immediately
|
||||
* @param bool $immediatelyRaw
|
||||
* @return string
|
||||
*/
|
||||
function info($msg, $immediately = false)
|
||||
function info($msg, $immediately = false, $immediatelyRaw = false)
|
||||
{
|
||||
return alert(NotificationType::INFORMATION, $msg, $immediately);
|
||||
return alert(NotificationType::INFORMATION, $msg, $immediately, $immediatelyRaw);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,11 +30,12 @@ function info($msg, $immediately = false)
|
|||
*
|
||||
* @param string $msg
|
||||
* @param bool $immediately
|
||||
* @param bool $immediatelyRaw
|
||||
* @return string
|
||||
*/
|
||||
function warning($msg, $immediately = false)
|
||||
function warning($msg, $immediately = false, $immediatelyRaw = false)
|
||||
{
|
||||
return alert(NotificationType::WARNING, $msg, $immediately);
|
||||
return alert(NotificationType::WARNING, $msg, $immediately, $immediatelyRaw);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,11 +43,12 @@ function warning($msg, $immediately = false)
|
|||
*
|
||||
* @param string $msg
|
||||
* @param bool $immediately
|
||||
* @param bool $immediatelyRaw
|
||||
* @return string
|
||||
*/
|
||||
function error($msg, $immediately = false)
|
||||
function error($msg, $immediately = false, $immediatelyRaw = false)
|
||||
{
|
||||
return alert(NotificationType::ERROR, $msg, $immediately);
|
||||
return alert(NotificationType::ERROR, $msg, $immediately, $immediatelyRaw);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,24 +56,27 @@ function error($msg, $immediately = false)
|
|||
*
|
||||
* @param string $msg
|
||||
* @param bool $immediately
|
||||
* @param bool $immediatelyRaw
|
||||
* @return string
|
||||
*/
|
||||
function success($msg, $immediately = false)
|
||||
function success($msg, $immediately = false, $immediatelyRaw = false)
|
||||
{
|
||||
return alert(NotificationType::MESSAGE, $msg, $immediately);
|
||||
return alert(NotificationType::MESSAGE, $msg, $immediately, $immediatelyRaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an alert message with the given alert-* class or sets it in session
|
||||
*
|
||||
* @see \Engelsystem\Controllers\HasUserNotifications
|
||||
*
|
||||
* @param NotificationType $type
|
||||
* @param string $msg
|
||||
* @param bool $immediately
|
||||
* @param bool $immediatelyRaw
|
||||
* @return string
|
||||
*
|
||||
* @see \Engelsystem\Controllers\HasUserNotifications
|
||||
*
|
||||
*/
|
||||
function alert(NotificationType $type, $msg, $immediately = false)
|
||||
function alert(NotificationType $type, $msg, $immediately = false, $immediatelyRaw = false)
|
||||
{
|
||||
if (empty($msg)) {
|
||||
return '';
|
||||
|
@ -87,6 +93,7 @@ function alert(NotificationType $type, $msg, $immediately = false)
|
|||
['danger', 'warning', 'info', 'success'],
|
||||
$type->value
|
||||
);
|
||||
$msg = $immediatelyRaw ? $msg : htmlspecialchars($msg);
|
||||
return '<div class="alert alert-' . $type . '" role="alert">' . $msg . '</div>';
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,13 @@ namespace Engelsystem\Events\Listener;
|
|||
use Carbon\Carbon;
|
||||
use Engelsystem\Helpers\Shifts;
|
||||
use Engelsystem\Mail\EngelsystemMailer;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\Models\Shifts\Shift as ShiftModel;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Models\Worklog;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Mailer\Exception\TransportException;
|
||||
|
||||
class Shift
|
||||
{
|
||||
|
@ -26,7 +28,7 @@ class Shift
|
|||
string $name,
|
||||
string $title,
|
||||
string $type,
|
||||
Room $room,
|
||||
Location $location,
|
||||
bool $freeloaded
|
||||
): void {
|
||||
if ($freeloaded || $start > Carbon::now()) {
|
||||
|
@ -45,9 +47,9 @@ class Shift
|
|||
$name,
|
||||
$title,
|
||||
$type,
|
||||
$room->name,
|
||||
$start->format(__('Y-m-d H:i')),
|
||||
$end->format(__('Y-m-d H:i'))
|
||||
$location->name,
|
||||
$start->format(__('general.datetime')),
|
||||
$end->format(__('general.datetime'))
|
||||
);
|
||||
$workLog->save();
|
||||
|
||||
|
@ -64,34 +66,70 @@ class Shift
|
|||
string $name,
|
||||
string $title,
|
||||
string $type,
|
||||
Room $room,
|
||||
Location $location,
|
||||
bool $freeloaded
|
||||
): void {
|
||||
if (!$user->settings->email_shiftinfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
$subject = 'notification.shift.deleted';
|
||||
try {
|
||||
$this->mailer->sendViewTranslated(
|
||||
$user,
|
||||
'notification.shift.deleted',
|
||||
'emails/worklog-from-shift',
|
||||
[
|
||||
'name' => $name,
|
||||
'title' => $title,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'location' => $location,
|
||||
'freeloaded' => $freeloaded,
|
||||
'username' => $user->displayName,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function updatedShiftSendEmail(
|
||||
ShiftModel $shift,
|
||||
ShiftModel $oldShift
|
||||
): void {
|
||||
// Only send e-mail on relevant changes
|
||||
if (
|
||||
$oldShift->shift_type_id == $shift->shift_type_id
|
||||
&& $oldShift->title == $shift->title
|
||||
&& $oldShift->start == $shift->start
|
||||
&& $oldShift->end == $shift->end
|
||||
&& $oldShift->location_id == $shift->location_id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$shift->load(['shiftType', 'location']);
|
||||
$oldShift->load(['shiftType', 'location']);
|
||||
/** @var ShiftEntry[]|Collection $shiftEntries */
|
||||
$shiftEntries = $shift->shiftEntries()
|
||||
->with(['angelType', 'user.settings'])
|
||||
->get();
|
||||
|
||||
foreach ($shiftEntries as $shiftEntry) {
|
||||
$user = $shiftEntry->user;
|
||||
$angelType = $shiftEntry->angelType;
|
||||
|
||||
if (!$user->settings->email_shiftinfo || $shift->end < Carbon::now()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->mailer->sendViewTranslated(
|
||||
$user,
|
||||
$subject,
|
||||
'emails/worklog-from-shift',
|
||||
'notification.shift.updated',
|
||||
'emails/updated-shift',
|
||||
[
|
||||
'name' => $name,
|
||||
'title' => $title,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'room' => $room,
|
||||
'freeloaded' => $freeloaded,
|
||||
'username' => $user->displayName,
|
||||
'shift' => $shift,
|
||||
'oldShift' => $oldShift,
|
||||
'angelType' => $angelType,
|
||||
'username' => $user->displayName,
|
||||
]
|
||||
);
|
||||
} catch (TransportException $e) {
|
||||
$this->log->error(
|
||||
'Unable to send email "{title}" to user {user} with {exception}',
|
||||
['title' => $subject, 'user' => $user->name, 'exception' => $e]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,29 +24,25 @@ $includeFiles = [
|
|||
__DIR__ . '/../includes/view/AngelTypes_view.php',
|
||||
__DIR__ . '/../includes/view/EventConfig_view.php',
|
||||
__DIR__ . '/../includes/view/PublicDashboard_view.php',
|
||||
__DIR__ . '/../includes/view/Rooms_view.php',
|
||||
__DIR__ . '/../includes/view/Locations_view.php',
|
||||
__DIR__ . '/../includes/view/ShiftCalendarLane.php',
|
||||
__DIR__ . '/../includes/view/ShiftCalendarRenderer.php',
|
||||
__DIR__ . '/../includes/view/ShiftCalendarShiftRenderer.php',
|
||||
__DIR__ . '/../includes/view/ShiftsFilterRenderer.php',
|
||||
__DIR__ . '/../includes/view/Shifts_view.php',
|
||||
__DIR__ . '/../includes/view/ShiftEntry_view.php',
|
||||
__DIR__ . '/../includes/view/ShiftTypes_view.php',
|
||||
__DIR__ . '/../includes/view/UserAngelTypes_view.php',
|
||||
__DIR__ . '/../includes/view/UserDriverLicenses_view.php',
|
||||
__DIR__ . '/../includes/view/UserHintsRenderer.php',
|
||||
__DIR__ . '/../includes/view/User_view.php',
|
||||
|
||||
__DIR__ . '/../includes/controller/angeltypes_controller.php',
|
||||
__DIR__ . '/../includes/controller/event_config_controller.php',
|
||||
__DIR__ . '/../includes/controller/public_dashboard_controller.php',
|
||||
__DIR__ . '/../includes/controller/rooms_controller.php',
|
||||
__DIR__ . '/../includes/controller/locations_controller.php',
|
||||
__DIR__ . '/../includes/controller/shift_entries_controller.php',
|
||||
__DIR__ . '/../includes/controller/shifts_controller.php',
|
||||
__DIR__ . '/../includes/controller/shifttypes_controller.php',
|
||||
__DIR__ . '/../includes/controller/users_controller.php',
|
||||
__DIR__ . '/../includes/controller/user_angeltypes_controller.php',
|
||||
__DIR__ . '/../includes/controller/user_driver_licenses_controller.php',
|
||||
|
||||
__DIR__ . '/../includes/helper/legacy_helper.php',
|
||||
__DIR__ . '/../includes/helper/message_helper.php',
|
||||
|
@ -62,7 +58,6 @@ $includeFiles = [
|
|||
__DIR__ . '/../includes/pages/admin_groups.php',
|
||||
__DIR__ . '/../includes/pages/admin_shifts.php',
|
||||
__DIR__ . '/../includes/pages/admin_user.php',
|
||||
__DIR__ . '/../includes/pages/guest_login.php',
|
||||
__DIR__ . '/../includes/pages/user_myshifts.php',
|
||||
__DIR__ . '/../includes/pages/user_shifts.php',
|
||||
|
||||
|
|
|
@ -1,87 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
function mail_shift_change(Shift $old_shift, Shift $new_shift)
|
||||
{
|
||||
/** @var ShiftEntry[]|Collection $shiftEntries */
|
||||
$shiftEntries = $old_shift->shiftEntries()
|
||||
->with(['user', 'user.settings'])
|
||||
->get();
|
||||
$old_room = $old_shift->room;
|
||||
$new_room = $new_shift->room;
|
||||
|
||||
$noticeable_changes = false;
|
||||
|
||||
$message = __('A Shift you are registered on has changed:');
|
||||
$message .= "\n";
|
||||
|
||||
if ($old_shift->shift_type_id != $new_shift->shift_type_id) {
|
||||
$message .= sprintf(
|
||||
__('* Shift type changed from %s to %s'),
|
||||
$old_shift->shiftType->name,
|
||||
$new_shift->shiftType->name
|
||||
) . "\n";
|
||||
$noticeable_changes = true;
|
||||
}
|
||||
|
||||
if ($old_shift->title != $new_shift->title) {
|
||||
$message .= sprintf(__('* Shift title changed from %s to %s'), $old_shift->title, $new_shift->title) . "\n";
|
||||
$noticeable_changes = true;
|
||||
}
|
||||
|
||||
if ($old_shift->start->timestamp != $new_shift->start->timestamp) {
|
||||
$message .= sprintf(
|
||||
__('* Shift Start changed from %s to %s'),
|
||||
$old_shift->start->format(__('Y-m-d H:i')),
|
||||
$new_shift->start->format(__('Y-m-d H:i'))
|
||||
) . "\n";
|
||||
$noticeable_changes = true;
|
||||
}
|
||||
|
||||
if ($old_shift->end->timestamp != $new_shift->end->timestamp) {
|
||||
$message .= sprintf(
|
||||
__('* Shift End changed from %s to %s'),
|
||||
$old_shift->end->format(__('Y-m-d H:i')),
|
||||
$new_shift->end->format(__('Y-m-d H:i'))
|
||||
) . "\n";
|
||||
$noticeable_changes = true;
|
||||
}
|
||||
|
||||
if ($old_shift->room_id != $new_shift->room_id) {
|
||||
$message .= sprintf(__('* Shift Location changed from %s to %s'), $old_room->name, $new_room->name) . "\n";
|
||||
$noticeable_changes = true;
|
||||
}
|
||||
|
||||
if (!$noticeable_changes) {
|
||||
// There are no changes worth sending an E-Mail
|
||||
return;
|
||||
}
|
||||
|
||||
$message .= "\n";
|
||||
$message .= __('The updated Shift:') . "\n";
|
||||
|
||||
$message .= $new_shift->shiftType->name . "\n";
|
||||
$message .= $new_shift->title . "\n";
|
||||
$message .= $new_shift->start->format(__('Y-m-d H:i')) . ' - ' . $new_shift->end->format(__('H:i')) . "\n";
|
||||
$message .= $new_room->name . "\n\n";
|
||||
$message .= url('/shifts', ['action' => 'view', 'shift_id' => $new_shift->id]) . "\n";
|
||||
|
||||
foreach ($shiftEntries as $shiftEntry) {
|
||||
$user = $shiftEntry->user;
|
||||
if ($user->settings->email_shiftinfo) {
|
||||
engelsystem_email_to_user(
|
||||
$user,
|
||||
__('Your Shift has changed'),
|
||||
$message,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mail_shift_assign(User $user, Shift $shift)
|
||||
{
|
||||
|
@ -89,13 +9,11 @@ function mail_shift_assign(User $user, Shift $shift)
|
|||
return;
|
||||
}
|
||||
|
||||
$room = $shift->room;
|
||||
|
||||
$message = __('You have been assigned to a Shift:') . "\n";
|
||||
$message .= $shift->shiftType->name . "\n";
|
||||
$message .= $shift->title . "\n";
|
||||
$message .= $shift->start->format(__('Y-m-d H:i')) . ' - ' . $shift->end->format(__('H:i')) . "\n";
|
||||
$message .= $room->name . "\n\n";
|
||||
$message .= $shift->start->format(__('general.datetime')) . ' - ' . $shift->end->format(__('H:i')) . "\n";
|
||||
$message .= $shift->location->name . "\n\n";
|
||||
$message .= url('/shifts', ['action' => 'view', 'shift_id' => $shift->id]) . "\n";
|
||||
|
||||
engelsystem_email_to_user($user, __('Assigned to Shift'), $message, true);
|
||||
|
@ -107,13 +25,11 @@ function mail_shift_removed(User $user, Shift $shift)
|
|||
return;
|
||||
}
|
||||
|
||||
$room = $shift->room;
|
||||
|
||||
$message = __('You have been removed from a Shift:') . "\n";
|
||||
$message .= $shift->shiftType->name . "\n";
|
||||
$message .= $shift->title . "\n";
|
||||
$message .= $shift->start->format(__('Y-m-d H:i')) . ' - ' . $shift->end->format(__('H:i')) . "\n";
|
||||
$message .= $room->name . "\n";
|
||||
$message .= $shift->start->format(__('general.datetime')) . ' - ' . $shift->end->format(__('H:i')) . "\n";
|
||||
$message .= $shift->location->name . "\n";
|
||||
|
||||
engelsystem_email_to_user($user, __('Removed from Shift'), $message, true);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ function mail_user_delete($user)
|
|||
{
|
||||
return engelsystem_email_to_user(
|
||||
$user,
|
||||
__('Your account has been deleted'),
|
||||
__('Your account has been deleted.'),
|
||||
__(
|
||||
'Your %s account has been deleted. If you have any questions regarding your account deletion, please contact heaven.',
|
||||
[config('app_name')]
|
||||
|
|
|
@ -1,47 +1,70 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Database\Db;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
/**
|
||||
* Returns all needed angeltypes and already taken needs.
|
||||
*
|
||||
* @param int $shiftId id of shift
|
||||
* @param Shift $shift
|
||||
* @return array
|
||||
*/
|
||||
function NeededAngelTypes_by_shift($shiftId)
|
||||
function NeededAngelTypes_by_shift($shift)
|
||||
{
|
||||
$needed_angeltypes_source = Db::select(
|
||||
'
|
||||
$needed_angeltypes_source = [];
|
||||
// Select from shift
|
||||
if (!$shift->schedule) {
|
||||
$needed_angeltypes_source = Db::select(
|
||||
'
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`angel_types`.`id`,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`no_self_signup`
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id` = `needed_angel_types`.`angel_type_id`
|
||||
WHERE `shift_id` = ?
|
||||
ORDER BY `room_id` DESC',
|
||||
[$shiftId]
|
||||
);
|
||||
WHERE `needed_angel_types`.`shift_id` = ?
|
||||
ORDER BY `location_id` DESC
|
||||
',
|
||||
[$shift->id]
|
||||
);
|
||||
}
|
||||
|
||||
// Use settings from room
|
||||
if (count($needed_angeltypes_source) == 0) {
|
||||
// Get needed by shift type
|
||||
if ($shift->schedule && $shift->schedule->needed_from_shift_type) {
|
||||
$needed_angeltypes_source = Db::select('
|
||||
SELECT `needed_angel_types`.*, `angel_types`.`name`, `angel_types`.`restricted`
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id` = `needed_angel_types`.`angel_type_id`
|
||||
JOIN `shifts` ON `shifts`.`room_id` = `needed_angel_types`.`room_id`
|
||||
WHERE `shifts`.`id` = ?
|
||||
ORDER BY `room_id` DESC
|
||||
', [$shiftId]);
|
||||
WHERE `needed_angel_types`.`shift_type_id` = ?
|
||||
ORDER BY `location_id` DESC
|
||||
', [$shift->shift_type_id]);
|
||||
}
|
||||
|
||||
// Load from room
|
||||
if ($shift->schedule && !$shift->schedule->needed_from_shift_type) {
|
||||
$needed_angeltypes_source = Db::select('
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id` = `needed_angel_types`.`angel_type_id`
|
||||
WHERE `needed_angel_types`.`location_id` = ?
|
||||
ORDER BY `location_id` DESC
|
||||
', [$shift->location_id]);
|
||||
}
|
||||
|
||||
/** @var ShiftEntry[]|Collection $shift_entries */
|
||||
$shift_entries = ShiftEntry::with('user', 'angelType')
|
||||
->where('shift_id', $shiftId)
|
||||
->where('shift_id', $shift->id)
|
||||
->get();
|
||||
$needed_angeltypes = [];
|
||||
foreach ($needed_angeltypes_source as $angeltype) {
|
||||
|
|
|
@ -15,7 +15,7 @@ function ShiftEntry_onCreate(ShiftEntry $shiftEntry): void
|
|||
'User ' . User_Nick_render($shiftEntry->user, true)
|
||||
. ' signed up for shift ' . $shiftEntry->shift->title
|
||||
. ' (' . $shift->shiftType->name . ')'
|
||||
. ' at ' . $shift->room->name
|
||||
. ' at ' . $shift->location->name
|
||||
. ' from ' . $shift->start->format('Y-m-d H:i')
|
||||
. ' to ' . $shift->end->format('Y-m-d H:i')
|
||||
. ' as ' . $shiftEntry->angelType->name
|
||||
|
@ -33,14 +33,14 @@ function ShiftEntry_onDelete(ShiftEntry $shiftEntry)
|
|||
$signout_user = $shiftEntry->user;
|
||||
$shift = Shift($shiftEntry->shift);
|
||||
$shifttype = $shift->shiftType;
|
||||
$room = $shift->room;
|
||||
$location = $shift->location;
|
||||
$angeltype = $shiftEntry->angelType;
|
||||
|
||||
engelsystem_log(
|
||||
'Shift signout: ' . User_Nick_render($signout_user, true)
|
||||
. ' from shift ' . $shift->title
|
||||
. ' (' . $shifttype->name . ')'
|
||||
. ' at ' . $room->name
|
||||
. ' at ' . $location->name
|
||||
. ' from ' . $shift->start->format('Y-m-d H:i')
|
||||
. ' to ' . $shift->end->format('Y-m-d H:i')
|
||||
. ' as ' . $angeltype->name
|
||||
|
|
|
@ -44,10 +44,10 @@ class ShiftsFilter
|
|||
* ShiftsFilter constructor.
|
||||
*
|
||||
* @param bool $user_shifts_admin
|
||||
* @param int[] $rooms
|
||||
* @param int[] $locations
|
||||
* @param int[] $angelTypes
|
||||
*/
|
||||
public function __construct($user_shifts_admin = false, private $rooms = [], $angelTypes = [])
|
||||
public function __construct($user_shifts_admin = false, private $locations = [], $angelTypes = [])
|
||||
{
|
||||
$this->types = $angelTypes;
|
||||
|
||||
|
@ -68,7 +68,7 @@ class ShiftsFilter
|
|||
return [
|
||||
'userShiftsAdmin' => $this->userShiftsAdmin,
|
||||
'filled' => $this->filled,
|
||||
'rooms' => $this->rooms,
|
||||
'locations' => $this->locations,
|
||||
'types' => $this->types,
|
||||
'startTime' => $this->startTime,
|
||||
'endTime' => $this->endTime,
|
||||
|
@ -80,12 +80,12 @@ class ShiftsFilter
|
|||
*/
|
||||
public function sessionImport($data)
|
||||
{
|
||||
$this->userShiftsAdmin = $data['userShiftsAdmin'];
|
||||
$this->filled = $data['filled'];
|
||||
$this->rooms = $data['rooms'];
|
||||
$this->types = $data['types'];
|
||||
$this->startTime = $data['startTime'];
|
||||
$this->endTime = $data['endTime'];
|
||||
$this->userShiftsAdmin = $data['userShiftsAdmin'] ?? false;
|
||||
$this->filled = $data['filled'] ?? [];
|
||||
$this->locations = $data['locations'] ?? [];
|
||||
$this->types = $data['types'] ?? [];
|
||||
$this->startTime = $data['startTime'] ?? null;
|
||||
$this->endTime = $data['endTime'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -163,20 +163,20 @@ class ShiftsFilter
|
|||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
public function getRooms()
|
||||
public function getLocations()
|
||||
{
|
||||
if (count($this->rooms) == 0) {
|
||||
if (count($this->locations) == 0) {
|
||||
return [0];
|
||||
}
|
||||
return $this->rooms;
|
||||
return $this->locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $rooms
|
||||
* @param int[] $locations
|
||||
*/
|
||||
public function setRooms($rooms)
|
||||
public function setLocations($locations)
|
||||
{
|
||||
$this->rooms = $rooms;
|
||||
$this->locations = $locations;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,12 +28,26 @@ function Shifts_by_angeltype(AngelType $angeltype)
|
|||
|
||||
UNION
|
||||
|
||||
/* By shift type */
|
||||
SELECT DISTINCT `shifts`.* FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`room_id` = `shifts`.`room_id`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`shift_type_id` = `shifts`.`shift_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `needed_angel_types`.`angel_type_id` = ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
', [$angeltype->id, $angeltype->id]);
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
|
||||
UNION
|
||||
|
||||
/* By location */
|
||||
SELECT DISTINCT `shifts`.* FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`location_id` = `shifts`.`location_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `needed_angel_types`.`angel_type_id` = ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
', [$angeltype->id, $angeltype->id, $angeltype->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,25 +67,42 @@ function Shifts_free($start, $end, ShiftsFilter $filter = null)
|
|||
$shifts = Db::select('
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT id, start
|
||||
SELECT shifts.id, start
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE (`end` > ? AND `start` < ?)
|
||||
AND (SELECT SUM(`count`) FROM `needed_angel_types` WHERE `needed_angel_types`.`shift_id`=`shifts`.`id`' . ($filter ? ' AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
> (SELECT COUNT(*) FROM `shift_entries` WHERE `shift_entries`.`shift_id`=`shifts`.`id` AND shift_entries.`freeloaded`=0' . ($filter ? ' AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
AND s.shift_id IS NULL
|
||||
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION
|
||||
|
||||
SELECT id, start
|
||||
/* By shift type */
|
||||
SELECT shifts.id, start
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE (`end` > ? AND `start` < ?)
|
||||
AND (SELECT SUM(`count`) FROM `needed_angel_types` WHERE `needed_angel_types`.`room_id`=`shifts`.`room_id`' . ($filter ? ' AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
> (SELECT COUNT(*) FROM `shift_entries` WHERE `shift_entries`.`shift_id`=`shifts`.`id` AND `freeloaded`=0' . ($filter ? ' AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
AND (SELECT SUM(`count`) FROM `needed_angel_types` WHERE `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`' . ($filter ? ' AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
> (SELECT COUNT(*) FROM `shift_entries` WHERE `shift_entries`.`shift_id`=`shifts`.`id` AND shift_entries.`freeloaded`=0' . ($filter ? ' AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
AND NOT s.shift_id IS NULL
|
||||
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION
|
||||
|
||||
/* By location */
|
||||
SELECT shifts.id, start
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE (`end` > ? AND `start` < ?)
|
||||
AND (SELECT SUM(`count`) FROM `needed_angel_types` WHERE `needed_angel_types`.`location_id`=`shifts`.`location_id`' . ($filter ? ' AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
> (SELECT COUNT(*) FROM `shift_entries` WHERE `shift_entries`.`shift_id`=`shifts`.`id` AND shift_entries.`freeloaded`=0' . ($filter ? ' AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
) AS `tmp`
|
||||
ORDER BY `tmp`.`start`
|
||||
', [
|
||||
|
@ -79,6 +110,8 @@ function Shifts_free($start, $end, ShiftsFilter $filter = null)
|
|||
$end,
|
||||
$start,
|
||||
$end,
|
||||
$start,
|
||||
$end,
|
||||
]);
|
||||
|
||||
$shifts = collect($shifts);
|
||||
|
@ -97,32 +130,51 @@ function Shifts_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
|||
{
|
||||
$sql = '
|
||||
SELECT * FROM (
|
||||
SELECT DISTINCT `shifts`.*, `shift_types`.`name`, `rooms`.`name` AS `room_name`
|
||||
SELECT DISTINCT `shifts`.*, `shift_types`.`name`, `locations`.`name` AS `location_name`
|
||||
FROM `shifts`
|
||||
JOIN `rooms` ON `shifts`.`room_id` = `rooms`.`id`
|
||||
JOIN `locations` ON `shifts`.`location_id` = `locations`.`id`
|
||||
JOIN `shift_types` ON `shift_types`.`id` = `shifts`.`shift_type_id`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`shift_id` = `shifts`.`id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE `shifts`.`room_id` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
||||
WHERE `shifts`.`location_id` IN (' . implode(',', $shiftsFilter->getLocations()) . ')
|
||||
AND `start` BETWEEN ? AND ?
|
||||
AND `needed_angel_types`.`angel_type_id` IN (' . implode(',', $shiftsFilter->getTypes()) . ')
|
||||
AND s.shift_id IS NULL
|
||||
|
||||
UNION
|
||||
|
||||
SELECT DISTINCT `shifts`.*, `shift_types`.`name`, `rooms`.`name` AS `room_name`
|
||||
/* By shift type */
|
||||
SELECT DISTINCT `shifts`.*, `shift_types`.`name`, `locations`.`name` AS `location_name`
|
||||
FROM `shifts`
|
||||
JOIN `rooms` ON `shifts`.`room_id` = `rooms`.`id`
|
||||
JOIN `locations` ON `shifts`.`location_id` = `locations`.`id`
|
||||
JOIN `shift_types` ON `shift_types`.`id` = `shifts`.`shift_type_id`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`room_id`=`shifts`.`room_id`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE `shifts`.`room_id` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`location_id` IN (' . implode(',', $shiftsFilter->getLocations()) . ')
|
||||
AND `start` BETWEEN ? AND ?
|
||||
AND `needed_angel_types`.`angel_type_id` IN (' . implode(',', $shiftsFilter->getTypes()) . ')
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
|
||||
UNION
|
||||
|
||||
/* By location */
|
||||
SELECT DISTINCT `shifts`.*, `shift_types`.`name`, `locations`.`name` AS `location_name`
|
||||
FROM `shifts`
|
||||
JOIN `locations` ON `shifts`.`location_id` = `locations`.`id`
|
||||
JOIN `shift_types` ON `shift_types`.`id` = `shifts`.`shift_type_id`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`location_id`=`shifts`.`location_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`location_id` IN (' . implode(',', $shiftsFilter->getLocations()) . ')
|
||||
AND `start` BETWEEN ? AND ?
|
||||
AND `needed_angel_types`.`angel_type_id` IN (' . implode(',', $shiftsFilter->getTypes()) . ')
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
) AS tmp_shifts
|
||||
|
||||
ORDER BY `room_name`, `start`
|
||||
ORDER BY `location_name`, `start`
|
||||
';
|
||||
|
||||
$shiftsData = Db::select(
|
||||
|
@ -132,6 +184,8 @@ function Shifts_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
|||
$shiftsFilter->getEnd(),
|
||||
$shiftsFilter->getStart(),
|
||||
$shiftsFilter->getEnd(),
|
||||
$shiftsFilter->getStart(),
|
||||
$shiftsFilter->getEnd(),
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -156,31 +210,54 @@ function NeededAngeltypes_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
|||
`angel_types`.`id`,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`no_self_signup`
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`shift_id`=`shifts`.`id`
|
||||
JOIN `angel_types` ON `angel_types`.`id`= `needed_angel_types`.`angel_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE `shifts`.`room_id` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
||||
WHERE `shifts`.`location_id` IN (' . implode(',', $shiftsFilter->getLocations()) . ')
|
||||
AND shifts.`start` BETWEEN ? AND ?
|
||||
AND s.shift_id IS NULL
|
||||
|
||||
UNION
|
||||
|
||||
/* By shift type */
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`shifts`.`id` AS shift_id,
|
||||
`angel_types`.`id`,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`no_self_signup`
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`room_id`=`shifts`.`room_id`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`
|
||||
JOIN `angel_types` ON `angel_types`.`id`= `needed_angel_types`.`angel_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE `shifts`.`room_id` IN (' . implode(',', $shiftsFilter->getRooms()) . ')
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`location_id` IN (' . implode(',', $shiftsFilter->getLocations()) . ')
|
||||
AND shifts.`start` BETWEEN ? AND ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
|
||||
UNION
|
||||
|
||||
/* By location */
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`shifts`.`id` AS shift_id,
|
||||
`angel_types`.`id`,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`location_id`=`shifts`.`location_id`
|
||||
JOIN `angel_types` ON `angel_types`.`id`= `needed_angel_types`.`angel_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`location_id` IN (' . implode(',', $shiftsFilter->getLocations()) . ')
|
||||
AND shifts.`start` BETWEEN ? AND ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
';
|
||||
|
||||
return Db::select(
|
||||
|
@ -190,6 +267,8 @@ function NeededAngeltypes_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
|||
$shiftsFilter->getEnd(),
|
||||
$shiftsFilter->getStart(),
|
||||
$shiftsFilter->getEnd(),
|
||||
$shiftsFilter->getStart(),
|
||||
$shiftsFilter->getEnd(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -209,7 +288,7 @@ function NeededAngeltype_by_Shift_and_Angeltype(Shift $shift, AngelType $angelty
|
|||
`angel_types`.`id`,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`no_self_signup`
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`shift_id`=`shifts`.`id`
|
||||
JOIN `angel_types` ON `angel_types`.`id`= `needed_angel_types`.`angel_type_id`
|
||||
|
@ -220,26 +299,51 @@ function NeededAngeltype_by_Shift_and_Angeltype(Shift $shift, AngelType $angelty
|
|||
|
||||
UNION
|
||||
|
||||
/* By shift type */
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`shifts`.`id` AS shift_id,
|
||||
`angel_types`.`id`,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`no_self_signup`
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`room_id`=`shifts`.`room_id`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`
|
||||
JOIN `angel_types` ON `angel_types`.`id`= `needed_angel_types`.`angel_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`id`=?
|
||||
AND `angel_types`.`id`=?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
|
||||
UNION
|
||||
|
||||
/* By location */
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`shifts`.`id` AS shift_id,
|
||||
`angel_types`.`id`,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`location_id`=`shifts`.`location_id`
|
||||
JOIN `angel_types` ON `angel_types`.`id`= `needed_angel_types`.`angel_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`id`=?
|
||||
AND `angel_types`.`id`=?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
',
|
||||
[
|
||||
$shift->id,
|
||||
$angeltype->id,
|
||||
$shift->id,
|
||||
$angeltype->id,
|
||||
$shift->id,
|
||||
$angeltype->id,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -252,7 +356,7 @@ function ShiftEntries_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
|||
{
|
||||
return ShiftEntry::with('user')
|
||||
->join('shifts', 'shifts.id', 'shift_entries.shift_id')
|
||||
->whereIn('shifts.room_id', $shiftsFilter->getRooms())
|
||||
->whereIn('shifts.location_id', $shiftsFilter->getLocations())
|
||||
->whereBetween('start', [$shiftsFilter->getStart(), $shiftsFilter->getEnd()])
|
||||
->get();
|
||||
}
|
||||
|
@ -368,12 +472,12 @@ function Shift_signup_allowed_angel(
|
|||
|
||||
if (
|
||||
empty($user_angeltype)
|
||||
|| $angeltype->no_self_signup == 1
|
||||
|| ($angeltype->restricted == 1 && !isset($user_angeltype['confirm_user_id']))
|
||||
|| !$angeltype->shift_self_signup
|
||||
|| ($angeltype->restricted && !isset($user_angeltype['confirm_user_id']))
|
||||
) {
|
||||
// you cannot join if user is not of this angel type
|
||||
// you cannot join if angeltype has shift self signup disabled
|
||||
// you cannot join if you are not confirmed
|
||||
// you cannot join if angeltype has no self signup
|
||||
|
||||
return new ShiftSignupState(ShiftSignupStatus::ANGELTYPE, $free_entries);
|
||||
}
|
||||
|
@ -510,8 +614,8 @@ function Shifts_by_user($userId, $include_freeloaded_comments = false)
|
|||
$shiftsData = Db::select(
|
||||
'
|
||||
SELECT
|
||||
`rooms`.*,
|
||||
`rooms`.name AS Name,
|
||||
`locations`.*,
|
||||
`locations`.name AS Name,
|
||||
`shift_types`.`id` AS `shifttype_id`,
|
||||
`shift_types`.`name`,
|
||||
`shift_entries`.`id` as shift_entry_id,
|
||||
|
@ -525,7 +629,7 @@ function Shifts_by_user($userId, $include_freeloaded_comments = false)
|
|||
FROM `shift_entries`
|
||||
JOIN `shifts` ON (`shift_entries`.`shift_id` = `shifts`.`id`)
|
||||
JOIN `shift_types` ON (`shift_types`.`id` = `shifts`.`shift_type_id`)
|
||||
JOIN `rooms` ON (`shifts`.`room_id` = `rooms`.`id`)
|
||||
JOIN `locations` ON (`shifts`.`location_id` = `locations`.`id`)
|
||||
WHERE shift_entries.`user_id` = ?
|
||||
ORDER BY `start`
|
||||
',
|
||||
|
@ -559,7 +663,7 @@ function Shift($shift)
|
|||
}
|
||||
|
||||
$neededAngels = [];
|
||||
$angelTypes = NeededAngelTypes_by_shift($shift->id);
|
||||
$angelTypes = NeededAngelTypes_by_shift($shift);
|
||||
foreach ($angelTypes as $type) {
|
||||
$neededAngels[] = [
|
||||
'angel_type_id' => $type['angel_type_id'],
|
||||
|
|
|
@ -24,7 +24,7 @@ function stats_currently_working(ShiftsFilter $filter = null)
|
|||
)) AS `count`
|
||||
FROM `shifts`
|
||||
WHERE (`end` >= NOW() AND `start` <= NOW())
|
||||
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '')
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '')
|
||||
);
|
||||
|
||||
return $result['count'] ?: '-';
|
||||
|
@ -47,20 +47,37 @@ function stats_hours_to_work(ShiftsFilter $filter = null)
|
|||
* TIMESTAMPDIFF(MINUTE, `shifts`.`start`, `shifts`.`end`) / 60 AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE `shifts`.`end` >= NOW()
|
||||
WHERE shifts.`end` >= NOW()
|
||||
AND s.shift_id IS NULL
|
||||
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* By shift type */
|
||||
SELECT
|
||||
(SELECT SUM(`count`) FROM `needed_angel_types` WHERE `needed_angel_types`.`room_id`=`shifts`.`room_id`' . ($filter ? ' AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
(SELECT SUM(`count`) FROM `needed_angel_types` WHERE `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`' . ($filter ? ' AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
* TIMESTAMPDIFF(MINUTE, `shifts`.`start`, `shifts`.`end`) / 60 AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE shifts.`end` >= NOW()
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` >= NOW()
|
||||
AND NOT s.shift_id IS NULL
|
||||
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* By location */
|
||||
SELECT
|
||||
(SELECT SUM(`count`) FROM `needed_angel_types` WHERE `needed_angel_types`.`location_id`=`shifts`.`location_id`' . ($filter ? ' AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
* TIMESTAMPDIFF(MINUTE, `shifts`.`start`, `shifts`.`end`) / 60 AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` >= NOW()
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
) AS `tmp`
|
||||
'
|
||||
);
|
||||
|
@ -90,7 +107,8 @@ function stats_angels_needed_three_hours(ShiftsFilter $filter = null)
|
|||
AND `needed_angel_types`.`shift_id`=`shifts`.`id`
|
||||
' . ($filter ? 'AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
SELECT COUNT(*) FROM `shift_entries`
|
||||
SELECT COUNT(*)
|
||||
FROM `shift_entries`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
|
@ -103,10 +121,11 @@ function stats_angels_needed_three_hours(ShiftsFilter $filter = null)
|
|||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE shifts.`end` > NOW() AND shifts.`start` < ?
|
||||
AND s.shift_id IS NULL
|
||||
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* By shift type */
|
||||
SELECT
|
||||
GREATEST(0,
|
||||
(
|
||||
|
@ -114,7 +133,7 @@ function stats_angels_needed_three_hours(ShiftsFilter $filter = null)
|
|||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`needed_angel_types`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `needed_angel_types`.`room_id`=`shifts`.`room_id`
|
||||
AND `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`
|
||||
' . ($filter ? 'AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
SELECT COUNT(*)
|
||||
|
@ -129,12 +148,46 @@ function stats_angels_needed_three_hours(ShiftsFilter $filter = null)
|
|||
AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE `end` > NOW() AND `start` < ?
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` > NOW() AND shifts.`start` < ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* By location */
|
||||
SELECT
|
||||
GREATEST(0,
|
||||
(
|
||||
SELECT SUM(needed_angel_types.`count`)
|
||||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`needed_angel_types`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `needed_angel_types`.`location_id`=`shifts`.`location_id`
|
||||
' . ($filter ? 'AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
SELECT COUNT(*)
|
||||
FROM `shift_entries`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
AND `freeloaded`=0
|
||||
' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
)
|
||||
)
|
||||
AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` > NOW() AND shifts.`start` < ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
) AS `tmp`', [
|
||||
$in3hours,
|
||||
$in3hours,
|
||||
$in3hours,
|
||||
]);
|
||||
|
||||
return $result['count'] ?: '-';
|
||||
|
@ -185,10 +238,11 @@ function stats_angels_needed_for_nightshifts(ShiftsFilter $filter = null)
|
|||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE shifts.`end` > ? AND shifts.`start` < ?
|
||||
AND s.shift_id IS NULL
|
||||
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* By shift type */
|
||||
SELECT
|
||||
GREATEST(0,
|
||||
(
|
||||
|
@ -196,28 +250,62 @@ function stats_angels_needed_for_nightshifts(ShiftsFilter $filter = null)
|
|||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`needed_angel_types`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `needed_angel_types`.`room_id`=`shifts`.`room_id`
|
||||
AND `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`
|
||||
' . ($filter ? 'AND angel_types.id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
SELECT COUNT(*) FROM `shift_entries`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
AND `freeloaded`=0
|
||||
AND shift_entries.`freeloaded`=0
|
||||
' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
)
|
||||
)
|
||||
AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE `end` > ? AND `start` < ?
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` > ? AND shifts.`start` < ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* By location */
|
||||
SELECT
|
||||
GREATEST(0,
|
||||
(
|
||||
SELECT SUM(needed_angel_types.`count`)
|
||||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`needed_angel_types`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `needed_angel_types`.`location_id`=`shifts`.`location_id`
|
||||
' . ($filter ? 'AND angel_types.id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
SELECT COUNT(*) FROM `shift_entries`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
AND shift_entries.`freeloaded`=0
|
||||
' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
)
|
||||
)
|
||||
AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` > ? AND shifts.`start` < ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
) AS `tmp`', [
|
||||
$night_start,
|
||||
$night_end,
|
||||
$night_start,
|
||||
$night_end,
|
||||
$night_start,
|
||||
$night_end,
|
||||
]);
|
||||
|
||||
return $result['count'] ?: '-';
|
||||
|
|
|
@ -137,22 +137,6 @@ function User_validate_planned_departure_date($planned_arrival_date, $planned_de
|
|||
return new ValidationResult(true, $planned_departure_date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new api key for given user.
|
||||
*
|
||||
* @param User $user
|
||||
* @param bool $log
|
||||
*/
|
||||
function User_reset_api_key($user, $log = true)
|
||||
{
|
||||
$user->api_key = bin2hex(random_bytes(32));
|
||||
$user->save();
|
||||
|
||||
if ($log) {
|
||||
engelsystem_log(sprintf('API key resetted (%s).', User_Nick_render($user, true)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @return float
|
||||
|
|
|
@ -47,11 +47,11 @@ function admin_active()
|
|||
__('At least %s angels are forced to be active. The number has to be greater.'),
|
||||
$forced_count
|
||||
));
|
||||
throw_redirect(page_link_to('admin_active'));
|
||||
throw_redirect(url('/admin-active'));
|
||||
}
|
||||
} else {
|
||||
$msg .= error(__('Please enter a number of angels to be marked as active.'));
|
||||
throw_redirect(page_link_to('admin_active'));
|
||||
throw_redirect(url('/admin-active'));
|
||||
}
|
||||
|
||||
if ($request->hasPostData('ack')) {
|
||||
|
@ -97,9 +97,9 @@ function admin_active()
|
|||
$msg = success(__('Marked angels.'), true);
|
||||
} else {
|
||||
$set_active = form([
|
||||
button(page_link_to('admin_active', ['search' => $search]), '« ' . __('back')),
|
||||
form_submit('ack', '» ' . __('apply')),
|
||||
], page_link_to('admin_active', ['search' => $search, 'count' => $count, 'set_active' => 1]));
|
||||
button(url('/admin-active', ['search' => $search]), '« ' . __('general.back')),
|
||||
form_submit('ack', '» ' . __('Apply')),
|
||||
], url('/admin-active', ['search' => $search, 'count' => $count, 'set_active' => 1]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ function admin_active()
|
|||
$user_source->state->got_shirt = true;
|
||||
$user_source->state->save();
|
||||
engelsystem_log('User ' . User_Nick_render($user_source, true) . ' has tshirt now.');
|
||||
$msg = success(($goodie_tshirt ? __('Angel has got a t-shirt.') : __('Angel has got a goodie.')), true);
|
||||
$msg = success(($goodie_tshirt ? __('Angel has got a T-shirt.') : __('Angel has got a goodie.')), true);
|
||||
} else {
|
||||
$msg = error('Angel not found.', true);
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ function admin_active()
|
|||
$user_source->state->got_shirt = false;
|
||||
$user_source->state->save();
|
||||
engelsystem_log('User ' . User_Nick_render($user_source, true) . ' has NO tshirt.');
|
||||
$msg = success(($goodie_tshirt ? __('Angel has got no t-shirt.') : __('Angel has got no goodie.')), true);
|
||||
$msg = success(($goodie_tshirt ? __('Angel has got no T-shirt.') : __('Angel has got no goodie.')), true);
|
||||
} else {
|
||||
$msg = error(__('Angel not found.'), true);
|
||||
}
|
||||
|
@ -236,8 +236,8 @@ function admin_active()
|
|||
$parameters['show_all_shifts'] = 1;
|
||||
}
|
||||
$actions[] = form(
|
||||
[form_submit('submit', __('set active'), 'btn-sm', false, 'secondary')],
|
||||
page_link_to('admin_active', $parameters),
|
||||
[form_submit('submit', icon('plus-lg') . __('set active'), 'btn-sm', false, 'secondary')],
|
||||
url('/admin-active', $parameters),
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
@ -251,8 +251,8 @@ function admin_active()
|
|||
$parametersRemove['show_all_shifts'] = 1;
|
||||
}
|
||||
$actions[] = form(
|
||||
[form_submit('submit', __('remove active'), 'btn-sm', false, 'secondary')],
|
||||
page_link_to('admin_active', $parametersRemove),
|
||||
[form_submit('submit', icon('dash-lg') . __('Remove active'), 'btn-sm', false, 'secondary')],
|
||||
url('/admin-active', $parametersRemove),
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
@ -268,8 +268,8 @@ function admin_active()
|
|||
|
||||
if ($goodie_enabled) {
|
||||
$actions[] = form(
|
||||
[form_submit('submit', ($goodie_tshirt ? __('got t-shirt') : __('got goodie')), 'btn-sm', false, 'secondary')],
|
||||
page_link_to('admin_active', $parametersShirt),
|
||||
[form_submit('submit', icon('person') . ($goodie_tshirt ? __('Got T-shirt') : __('Got goodie')), 'btn-sm', false, 'secondary')],
|
||||
url('/admin-active', $parametersShirt),
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
@ -286,8 +286,8 @@ function admin_active()
|
|||
|
||||
if ($goodie_enabled) {
|
||||
$actions[] = form(
|
||||
[form_submit('submit', ($goodie_tshirt ? __('remove t-shirt') : __('remove goodie')), 'btn-sm', false, 'secondary')],
|
||||
page_link_to('admin_active', $parameters),
|
||||
[form_submit('submit', icon('person') . ($goodie_tshirt ? __('Remove T-shirt') : __('Remove goodie')), 'btn-sm', false, 'secondary')],
|
||||
url('/admin-active', $parameters),
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
@ -295,7 +295,7 @@ function admin_active()
|
|||
}
|
||||
|
||||
if ($goodie_tshirt) {
|
||||
$actions[] = button(url('/admin/user/' . $usr->id . '/goodie'), __('form.edit'), 'btn-secondary btn-sm');
|
||||
$actions[] = button(url('/admin/user/' . $usr->id . '/goodie'), icon('pencil') . __('form.edit'), 'btn-secondary btn-sm');
|
||||
}
|
||||
|
||||
$userData['actions'] = buttons($actions);
|
||||
|
@ -328,18 +328,18 @@ function admin_active()
|
|||
form([
|
||||
form_text('search', __('Search angel:'), $search),
|
||||
form_checkbox('show_all_shifts', __('Show all shifts'), $show_all_shifts),
|
||||
form_submit('submit', __('Search')),
|
||||
], page_link_to('admin_active')),
|
||||
form_submit('submit', icon('search') . __('form.search')),
|
||||
], url('/admin-active')),
|
||||
$set_active == '' ? form([
|
||||
form_text('count', __('How much angels should be active?'), $count ?: $forced_count),
|
||||
form_submit('set_active', __('Preview')),
|
||||
form_submit('set_active', icon('eye') . __('form.preview'), 'btn-info'),
|
||||
]) : $set_active,
|
||||
$msg . msg(),
|
||||
table(
|
||||
array_merge(
|
||||
[
|
||||
'no' => __('No.'),
|
||||
'nick' => __('Name'),
|
||||
'nick' => __('general.name'),
|
||||
],
|
||||
($goodie_tshirt ? ['shirt_size' => __('Size')] : []),
|
||||
[
|
||||
|
@ -350,15 +350,15 @@ function admin_active()
|
|||
],
|
||||
($goodie_enabled ? ['tshirt' => ($goodie_tshirt ? __('T-shirt?') : __('Goodie?'))] : []),
|
||||
[
|
||||
'actions' => '',
|
||||
'actions' => __('general.actions'),
|
||||
]
|
||||
),
|
||||
$matched_users
|
||||
),
|
||||
$goodie_enabled ? '<h2>' . ($goodie_tshirt ? __('Shirt statistic') : __('Goodie statistic')) . '</h2>' : '',
|
||||
$goodie_enabled ? '<h2>' . ($goodie_tshirt ? __('T-shirt statistic') : __('Goodie statistic')) . '</h2>' : '',
|
||||
$goodie_enabled ? table(array_merge(
|
||||
($goodie_tshirt ? ['size' => __('Size')] : []),
|
||||
['given' => $goodie_tshirt ? __('Given shirts') : __('Given goodies') ]
|
||||
['given' => $goodie_tshirt ? __('Given T-shirts') : __('Given goodies') ]
|
||||
), $goodie_statistics) : '',
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -78,7 +78,13 @@ function admin_arrive()
|
|||
foreach ($users as $usr) {
|
||||
if (count($tokens) > 0) {
|
||||
$match = false;
|
||||
$index = join(' ', $usr->attributesToArray());
|
||||
$data = collect($usr->toArray())->flatten()->filter(function ($value) {
|
||||
// Remove empty values
|
||||
return !empty($value) &&
|
||||
// Skip datetime
|
||||
!preg_match('/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{6}Z$/', (string) $value);
|
||||
});
|
||||
$index = join(' ', $data->toArray());
|
||||
foreach ($tokens as $token) {
|
||||
$token = trim($token);
|
||||
if (!empty($token) && stristr($index, $token)) {
|
||||
|
@ -92,50 +98,68 @@ function admin_arrive()
|
|||
}
|
||||
}
|
||||
|
||||
$usr->name = User_Nick_render($usr) . User_Pronoun_render($usr);
|
||||
$usr->name = User_Nick_render($usr)
|
||||
. User_Pronoun_render($usr)
|
||||
. ($usr->state->user_info
|
||||
? ' <small><span class="bi bi-info-circle-fill text-info"></span></small>'
|
||||
: '');
|
||||
$plannedDepartureDate = $usr->personalData->planned_departure_date;
|
||||
$arrivalDate = $usr->state->arrival_date;
|
||||
$plannedArrivalDate = $usr->personalData->planned_arrival_date;
|
||||
$usr['rendered_planned_departure_date'] = $plannedDepartureDate
|
||||
? $plannedDepartureDate->format(__('Y-m-d'))
|
||||
? $plannedDepartureDate->format(__('general.date'))
|
||||
: '-';
|
||||
$usr['rendered_planned_arrival_date'] = $plannedArrivalDate ? $plannedArrivalDate->format(__('Y-m-d')) : '-';
|
||||
$usr['rendered_arrival_date'] = $arrivalDate ? $arrivalDate->format(__('Y-m-d')) : '-';
|
||||
$usr['rendered_planned_arrival_date'] = $plannedArrivalDate ? $plannedArrivalDate->format(__('general.date')) : '-';
|
||||
$usr['rendered_arrival_date'] = $arrivalDate ? $arrivalDate->format(__('general.date')) : '-';
|
||||
$usr['arrived'] = icon_bool($usr->state->arrived);
|
||||
$usr['actions'] = form([
|
||||
form_hidden('action', $usr->state->arrived ? 'reset' : 'arrived'),
|
||||
form_hidden('user', $usr->id),
|
||||
form_submit(
|
||||
'submit',
|
||||
$usr->state->arrived ? __('reset') : __('arrived'),
|
||||
$usr->state->arrived
|
||||
? icon('arrow-counterclockwise')
|
||||
: icon('house'),
|
||||
'btn-sm',
|
||||
true,
|
||||
$usr->state->arrived ? 'secondary' : 'primary'
|
||||
$usr->state->arrived ? 'secondary' : 'primary',
|
||||
$usr->state->arrived
|
||||
? __('Reset')
|
||||
: __('user.arrive')
|
||||
),
|
||||
]);
|
||||
|
||||
if ($usr->state->arrival_date) {
|
||||
$day = $usr->state->arrival_date->format(__('Y-m-d'));
|
||||
$day = $usr->state->arrival_date->format('Y-m-d');
|
||||
if (!isset($arrival_count_at_day[$day])) {
|
||||
$arrival_count_at_day[$day] = 0;
|
||||
$arrival_count_at_day[$day] = [
|
||||
'day' => $usr->state->arrival_date,
|
||||
'count' => 0,
|
||||
];
|
||||
}
|
||||
$arrival_count_at_day[$day]++;
|
||||
$arrival_count_at_day[$day]['count']++;
|
||||
}
|
||||
|
||||
if ($usr->personalData->planned_arrival_date) {
|
||||
$day = $usr->personalData->planned_arrival_date->format(__('Y-m-d'));
|
||||
$day = $usr->personalData->planned_arrival_date->format('Y-m-d');
|
||||
if (!isset($planned_arrival_count_at_day[$day])) {
|
||||
$planned_arrival_count_at_day[$day] = 0;
|
||||
$planned_arrival_count_at_day[$day] = [
|
||||
'day' => $usr->personalData->planned_arrival_date,
|
||||
'count' => 0,
|
||||
];
|
||||
}
|
||||
$planned_arrival_count_at_day[$day]++;
|
||||
$planned_arrival_count_at_day[$day]['count']++;
|
||||
}
|
||||
|
||||
if ($usr->personalData->planned_departure_date && $usr->state->arrived) {
|
||||
$day = $usr->personalData->planned_departure_date->format(__('Y-m-d'));
|
||||
$day = $usr->personalData->planned_departure_date->format('Y-m-d');
|
||||
if (!isset($planned_departure_count_at_day[$day])) {
|
||||
$planned_departure_count_at_day[$day] = 0;
|
||||
$planned_departure_count_at_day[$day] = [
|
||||
'day' => $usr->personalData->planned_departure_date,
|
||||
'count' => 0,
|
||||
];
|
||||
}
|
||||
$planned_departure_count_at_day[$day]++;
|
||||
$planned_departure_count_at_day[$day]['count']++;
|
||||
}
|
||||
|
||||
$users_matched[] = $usr;
|
||||
|
@ -147,33 +171,33 @@ function admin_arrive()
|
|||
|
||||
$arrival_at_day = [];
|
||||
$arrival_sum = 0;
|
||||
foreach ($arrival_count_at_day as $day => $count) {
|
||||
$arrival_sum += $count;
|
||||
foreach ($arrival_count_at_day as $day => $entry) {
|
||||
$arrival_sum += $entry['count'];
|
||||
$arrival_at_day[$day] = [
|
||||
'day' => $day,
|
||||
'count' => $count,
|
||||
'day' => $entry['day']->format(__('general.date')),
|
||||
'count' => $entry['count'],
|
||||
'sum' => $arrival_sum,
|
||||
];
|
||||
}
|
||||
|
||||
$planned_arrival_at_day = [];
|
||||
$planned_arrival_sum = 0;
|
||||
foreach ($planned_arrival_count_at_day as $day => $count) {
|
||||
$planned_arrival_sum += $count;
|
||||
foreach ($planned_arrival_count_at_day as $day => $entry) {
|
||||
$planned_arrival_sum += $entry['count'];
|
||||
$planned_arrival_at_day[$day] = [
|
||||
'day' => $day,
|
||||
'count' => $count,
|
||||
'day' => $entry['day']->format(__('general.date')),
|
||||
'count' => $entry['count'],
|
||||
'sum' => $planned_arrival_sum,
|
||||
];
|
||||
}
|
||||
|
||||
$planned_departure_at_day = [];
|
||||
$planned_departure_sum = 0;
|
||||
foreach ($planned_departure_count_at_day as $day => $count) {
|
||||
$planned_departure_sum += $count;
|
||||
foreach ($planned_departure_count_at_day as $day => $entry) {
|
||||
$planned_departure_sum += $entry['count'];
|
||||
$planned_departure_at_day[$day] = [
|
||||
'day' => $day,
|
||||
'count' => $count,
|
||||
'day' => $entry['day']->format(__('general.date')),
|
||||
'count' => $entry['count'],
|
||||
'sum' => $planned_departure_sum,
|
||||
];
|
||||
}
|
||||
|
@ -181,60 +205,60 @@ function admin_arrive()
|
|||
return page_with_title(admin_arrive_title(), [
|
||||
$msg . msg(),
|
||||
form([
|
||||
form_text('search', __('Search'), $search),
|
||||
form_submit('submit', __('Search')),
|
||||
], page_link_to('admin_arrive')),
|
||||
form_text('search', __('form.search'), $search),
|
||||
form_submit('submit', icon('search') . __('form.search')),
|
||||
], url('/admin-arrive')),
|
||||
table([
|
||||
'name' => __('Name'),
|
||||
'name' => __('general.name'),
|
||||
'rendered_planned_arrival_date' => __('Planned arrival'),
|
||||
'arrived' => __('Arrived?'),
|
||||
'rendered_arrival_date' => __('Arrival date'),
|
||||
'rendered_planned_departure_date' => __('Planned departure'),
|
||||
'actions' => '',
|
||||
'actions' => __('general.actions'),
|
||||
], $users_matched),
|
||||
div('row', [
|
||||
div('col-md-4', [
|
||||
heading(__('Planned arrival statistics'), 3),
|
||||
BarChart::render([
|
||||
'count' => __('arrived'),
|
||||
'count' => __('user.arrived'),
|
||||
'sum' => __('arrived sum'),
|
||||
], [
|
||||
'count' => '#090',
|
||||
'sum' => '#888',
|
||||
], $planned_arrival_at_day),
|
||||
table([
|
||||
'day' => __('Date'),
|
||||
'count' => __('Count'),
|
||||
'day' => __('title.date'),
|
||||
'count' => __('general.count'),
|
||||
'sum' => __('Sum'),
|
||||
], $planned_arrival_at_day),
|
||||
]),
|
||||
div('col-md-4', [
|
||||
heading(__('Arrival statistics'), 3),
|
||||
BarChart::render([
|
||||
'count' => __('arrived'),
|
||||
'count' => __('user.arrived'),
|
||||
'sum' => __('arrived sum'),
|
||||
], [
|
||||
'count' => '#090',
|
||||
'sum' => '#888',
|
||||
], $arrival_at_day),
|
||||
table([
|
||||
'day' => __('Date'),
|
||||
'count' => __('Count'),
|
||||
'day' => __('title.date'),
|
||||
'count' => __('general.count'),
|
||||
'sum' => __('Sum'),
|
||||
], $arrival_at_day),
|
||||
]),
|
||||
div('col-md-4', [
|
||||
heading(__('Planned departure statistics'), 3),
|
||||
BarChart::render([
|
||||
'count' => __('arrived'),
|
||||
'count' => __('user.arrived'),
|
||||
'sum' => __('arrived sum'),
|
||||
], [
|
||||
'count' => '#090',
|
||||
'sum' => '#888',
|
||||
], $planned_departure_at_day),
|
||||
table([
|
||||
'day' => __('Date'),
|
||||
'count' => __('Count'),
|
||||
'day' => __('title.date'),
|
||||
'count' => __('general.count'),
|
||||
'sum' => __('Sum'),
|
||||
], $planned_departure_at_day),
|
||||
]),
|
||||
|
|
|
@ -97,16 +97,20 @@ function admin_free()
|
|||
|
||||
$email = $usr->contact->email ?: $usr->email;
|
||||
$free_users_table[] = [
|
||||
'name' => User_Nick_render($usr) . User_Pronoun_render($usr),
|
||||
'name' => User_Nick_render($usr)
|
||||
. User_Pronoun_render($usr)
|
||||
. ($usr->state->user_info
|
||||
? ' <small><span class="bi bi-info-circle-fill text-info"></span></small>'
|
||||
: ''),
|
||||
'shift_state' => User_shift_state_render($usr),
|
||||
'last_shift' => User_last_shift_render($usr),
|
||||
'dect' => sprintf('<a href="tel:%s">%1$s</a>', $usr->contact->dect),
|
||||
'dect' => sprintf('<a href="tel:%s">%1$s</a>', htmlspecialchars((string) $usr->contact->dect)),
|
||||
'email' => $usr->settings->email_human
|
||||
? sprintf('<a href="mailto:%s">%1$s</a>', $email)
|
||||
? sprintf('<a href="mailto:%s">%1$s</a>', htmlspecialchars((string) $email))
|
||||
: icon('eye-slash'),
|
||||
'actions' =>
|
||||
auth()->can('admin_user')
|
||||
? button(page_link_to('admin_user', ['id' => $usr->id]), icon('pencil') . __('edit'), 'btn-sm')
|
||||
? button(url('/admin-user', ['id' => $usr->id]), icon('pencil'), 'btn-sm', '', __('form.edit'))
|
||||
: '',
|
||||
];
|
||||
}
|
||||
|
@ -115,19 +119,19 @@ function admin_free()
|
|||
div('row', [
|
||||
div('col-md-12 form-inline', [
|
||||
div('row', [
|
||||
form_text('search', __('Search'), $search, null, null, null, 'col'),
|
||||
form_text('search', __('form.search'), $search, null, null, null, 'col'),
|
||||
form_select('angeltype', __('Angeltype'), $angel_types, $angelType, '', 'col'),
|
||||
form_submit('submit', __('Search')),
|
||||
form_submit('submit', icon('search') . __('form.search')),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
table([
|
||||
'name' => __('Name'),
|
||||
'shift_state' => __('Next shift'),
|
||||
'name' => __('general.name'),
|
||||
'shift_state' => __('shift.next'),
|
||||
'last_shift' => __('Last shift'),
|
||||
'dect' => __('DECT'),
|
||||
'email' => __('E-Mail'),
|
||||
'dect' => __('general.dect'),
|
||||
'email' => __('general.email'),
|
||||
'actions' => '',
|
||||
], $free_users_table),
|
||||
]);
|
||||
|
|
|
@ -31,18 +31,21 @@ function admin_groups()
|
|||
$privileges_html = [];
|
||||
|
||||
foreach ($privileges as $privilege) {
|
||||
$privileges_html[] = $privilege['name'];
|
||||
$privileges_html[] = htmlspecialchars($privilege['name']);
|
||||
}
|
||||
|
||||
$groups_table[] = [
|
||||
'name' => $group->name,
|
||||
'name' => htmlspecialchars($group->name),
|
||||
'privileges' => join(', ', $privileges_html),
|
||||
'actions' => button(
|
||||
page_link_to(
|
||||
'admin_groups',
|
||||
url(
|
||||
'/admin-groups',
|
||||
['action' => 'edit', 'id' => $group->id]
|
||||
),
|
||||
icon('pencil') . __('edit'),
|
||||
icon('pencil'),
|
||||
'',
|
||||
'',
|
||||
__('form.edit'),
|
||||
'btn-sm'
|
||||
),
|
||||
];
|
||||
|
@ -50,7 +53,7 @@ function admin_groups()
|
|||
|
||||
return page_with_title(admin_groups_title(), [
|
||||
table([
|
||||
'name' => __('Name'),
|
||||
'name' => __('general.name'),
|
||||
'privileges' => __('Privileges'),
|
||||
'actions' => '',
|
||||
], $groups_table),
|
||||
|
@ -72,18 +75,18 @@ function admin_groups()
|
|||
foreach ($privileges as $privilege) {
|
||||
$privileges_form[] = form_checkbox(
|
||||
'privileges[]',
|
||||
$privilege->description . ' (' . $privilege->name . ')',
|
||||
htmlspecialchars($privilege->description . ' (' . $privilege->name . ')'),
|
||||
$privilege->selected != '',
|
||||
$privilege->id,
|
||||
'privilege-' . $privilege->name
|
||||
'privilege-' . htmlspecialchars($privilege->name)
|
||||
);
|
||||
}
|
||||
|
||||
$privileges_form[] = form_submit('submit', __('Save'));
|
||||
$html .= page_with_title(__('Edit group') . ' ' . $group->name, [
|
||||
$privileges_form[] = form_submit('submit', icon('save') . __('form.save'));
|
||||
$html .= page_with_title(__('Edit group') . ' ' . htmlspecialchars($group->name), [
|
||||
form(
|
||||
$privileges_form,
|
||||
page_link_to('admin_groups', ['action' => 'save', 'id' => $group->id])
|
||||
url('/admin-groups', ['action' => 'save', 'id' => $group->id])
|
||||
),
|
||||
]);
|
||||
} else {
|
||||
|
@ -118,7 +121,7 @@ function admin_groups()
|
|||
'Group privileges of group ' . $group->name
|
||||
. ' edited: ' . join(', ', $privilege_names)
|
||||
);
|
||||
throw_redirect(page_link_to('admin_groups'));
|
||||
throw_redirect(url('/admin-groups'));
|
||||
} else {
|
||||
return error('No Group found.', true);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Database\Db;
|
||||
use Engelsystem\Helpers\Carbon;
|
||||
use Engelsystem\Http\Exceptions\HttpForbidden;
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||
use Engelsystem\Models\Shifts\Schedule;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftType;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
|
@ -44,8 +40,8 @@ function admin_shifts()
|
|||
$shift_over_midnight = true;
|
||||
|
||||
// Locations laden
|
||||
$rooms = Room::orderBy('name')->get();
|
||||
$room_array = $rooms->pluck('name', 'id')->toArray();
|
||||
$locations = Location::orderBy('name')->get();
|
||||
$location_array = $locations->pluck('name', 'id')->toArray();
|
||||
|
||||
// Load angeltypes
|
||||
/** @var AngelType[] $types */
|
||||
|
@ -85,14 +81,14 @@ function admin_shifts()
|
|||
|
||||
// Auswahl der sichtbaren Locations für die Schichten
|
||||
if (
|
||||
$request->has('rid')
|
||||
&& preg_match('/^\d+$/', $request->input('rid'))
|
||||
&& isset($room_array[$request->input('rid')])
|
||||
$request->has('lid')
|
||||
&& preg_match('/^\d+$/', $request->input('lid'))
|
||||
&& isset($location_array[$request->input('lid')])
|
||||
) {
|
||||
$rid = $request->input('rid');
|
||||
$lid = $request->input('lid');
|
||||
} else {
|
||||
$valid = false;
|
||||
$rid = $rooms->first()->id;
|
||||
$lid = $locations->first()?->id ?? 0;
|
||||
error(__('Please select a location.'));
|
||||
}
|
||||
|
||||
|
@ -139,6 +135,29 @@ function admin_shifts()
|
|||
'trim',
|
||||
explode(',', $request->input('change_hours'))
|
||||
);
|
||||
// Fehlende Minutenangaben ergänzen, 24 Uhr -> 00 Uhr
|
||||
array_walk($change_hours, function (&$value) use ($valid) {
|
||||
// Add minutes
|
||||
if (!preg_match('/^(\d{1,2}):\d{2}$/', $value)) {
|
||||
$value .= ':00';
|
||||
}
|
||||
// Add 0 before low hours
|
||||
if (preg_match('/^\d:\d{2}$/', $value)) {
|
||||
$value = '0' . $value;
|
||||
}
|
||||
// Fix 24:00
|
||||
if ($value == '24:00') {
|
||||
$value = '00:00';
|
||||
}
|
||||
});
|
||||
// Ensure valid time in change hours
|
||||
foreach ($change_hours as $change_hour) {
|
||||
if (!preg_match('/^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/', $change_hour)) {
|
||||
$valid = false;
|
||||
error(sprintf(__('Please validate the change hour %s. It should be between 00:00 and 24:00.'), $change_hour));
|
||||
}
|
||||
}
|
||||
$change_hours = array_unique($change_hours);
|
||||
} else {
|
||||
$valid = false;
|
||||
error(__('Please split the shift-change hours by colons.'));
|
||||
|
@ -152,7 +171,9 @@ function admin_shifts()
|
|||
}
|
||||
|
||||
if ($request->has('angelmode')) {
|
||||
if ($request->input('angelmode') == 'location') {
|
||||
if ($request->input('angelmode') == 'shift_type') {
|
||||
$angelmode = 'shift_type';
|
||||
} elseif ($request->input('angelmode') == 'location') {
|
||||
$angelmode = 'location';
|
||||
} elseif ($request->input('angelmode') == 'manually') {
|
||||
foreach ($types as $type) {
|
||||
|
@ -184,8 +205,12 @@ function admin_shifts()
|
|||
|
||||
// Alle Eingaben in Ordnung
|
||||
if ($valid) {
|
||||
if ($angelmode == 'location') {
|
||||
$needed_angel_types = NeededAngelType::whereRoomId($rid)
|
||||
if ($angelmode == 'shift_type') {
|
||||
$needed_angel_types = NeededAngelType::whereShiftTypeId($shifttype_id)
|
||||
->pluck('count', 'angel_type_id')
|
||||
->toArray() + $needed_angel_types;
|
||||
} elseif ($angelmode == 'location') {
|
||||
$needed_angel_types = NeededAngelType::whereLocationId($lid)
|
||||
->pluck('count', 'angel_type_id')
|
||||
->toArray() + $needed_angel_types;
|
||||
}
|
||||
|
@ -195,7 +220,7 @@ function admin_shifts()
|
|||
$shifts[] = [
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'room_id' => $rid,
|
||||
'location_id' => $lid,
|
||||
'title' => $title,
|
||||
'shift_type_id' => $shifttype_id,
|
||||
'description' => $description,
|
||||
|
@ -215,7 +240,7 @@ function admin_shifts()
|
|||
$shifts[] = [
|
||||
'start' => $shift_start,
|
||||
'end' => $shift_end,
|
||||
'room_id' => $rid,
|
||||
'location_id' => $lid,
|
||||
'title' => $title,
|
||||
'shift_type_id' => $shifttype_id,
|
||||
'description' => $description,
|
||||
|
@ -224,13 +249,6 @@ function admin_shifts()
|
|||
$shift_start = $shift_end;
|
||||
} while ($shift_end < $end);
|
||||
} elseif ($mode == 'variable') {
|
||||
// Fehlende Minutenangaben ergänzen
|
||||
array_walk($change_hours, function (&$value) {
|
||||
if (!preg_match('/^\d{1,2}:\d{2}$/', $value)) {
|
||||
$value .= ':00';
|
||||
}
|
||||
});
|
||||
|
||||
// Alle Tage durchgehen
|
||||
$end_day = Carbon::createFromDatetime($end->format('Y-m-d') . ' 00:00');
|
||||
$day = Carbon::createFromDatetime($start->format('Y-m-d') . ' 00:00');
|
||||
|
@ -238,10 +256,10 @@ function admin_shifts()
|
|||
// Alle Schichtwechselstunden durchgehen
|
||||
for ($i = 0; $i < count($change_hours); $i++) {
|
||||
$start_hour = $change_hours[$i];
|
||||
if ($i < count($change_hours) - 1) {
|
||||
if (isset($change_hours[$i + 1])) {
|
||||
// Normales Intervall zwischen zwei Schichtwechselstunden
|
||||
$end_hour = $change_hours[$i + 1];
|
||||
} elseif ($shift_over_midnight) {
|
||||
} elseif ($shift_over_midnight && $day != $end_day) {
|
||||
// Letzte Schichtwechselstunde: Wenn eine 24h Abdeckung gewünscht ist,
|
||||
// hier die erste Schichtwechselstunde als Ende einsetzen
|
||||
$end_hour = $change_hours[0];
|
||||
|
@ -283,7 +301,7 @@ function admin_shifts()
|
|||
$shifts[] = [
|
||||
'start' => $interval_start,
|
||||
'end' => $interval_end,
|
||||
'room_id' => $rid,
|
||||
'location_id' => $lid,
|
||||
'title' => $title,
|
||||
'shift_type_id' => $shifttype_id,
|
||||
'description' => $description,
|
||||
|
@ -300,17 +318,24 @@ function admin_shifts()
|
|||
|
||||
$shifts_table = [];
|
||||
foreach ($shifts as $shift) {
|
||||
/** @var Carbon $start */
|
||||
$start = $shift['start'];
|
||||
/** @var Carbon $end */
|
||||
$end = $shift['end'];
|
||||
$shifts_table_entry = [
|
||||
'timeslot' =>
|
||||
icon('clock-history') . ' '
|
||||
. $shift['start']->format(__('Y-m-d H:i'))
|
||||
. $start->format(__('general.datetime'))
|
||||
. ' - '
|
||||
. $shift['end']->format(__('H:i'))
|
||||
. '<br />'
|
||||
. Room_name_render(Room::find($shift['room_id'])),
|
||||
. '<span title="' . $end->format(__('general.date')) . '">'
|
||||
. $end->format(__('H:i'))
|
||||
. '</span>'
|
||||
. ', ' . round($end->copy()->diffInMinutes($start) / 60, 2) . 'h'
|
||||
. '<br>'
|
||||
. location_name_render(Location::find($shift['location_id'])),
|
||||
'title' =>
|
||||
ShiftType_name_render(ShiftType::find($shifttype_id))
|
||||
. ($shift['title'] ? '<br />' . $shift['title'] : ''),
|
||||
htmlspecialchars(ShiftType::find($shifttype_id)->name)
|
||||
. ($shift['title'] ? '<br />' . htmlspecialchars($shift['title']) : ''),
|
||||
'needed_angels' => '',
|
||||
];
|
||||
foreach ($types as $type) {
|
||||
|
@ -326,9 +351,9 @@ function admin_shifts()
|
|||
$session->set('admin_shifts_shifts', $shifts);
|
||||
$session->set('admin_shifts_types', $needed_angel_types);
|
||||
|
||||
$hidden_types = '';
|
||||
$previousEntries = [];
|
||||
foreach ($needed_angel_types as $type_id => $count) {
|
||||
$hidden_types .= form_hidden('angeltype_count_' . $type_id, $count);
|
||||
$previousEntries['angeltype_count_' . $type_id] = $count;
|
||||
}
|
||||
|
||||
// Number of Shifts that will be created (if over 100 its danger-red)
|
||||
|
@ -338,28 +363,38 @@ function admin_shifts()
|
|||
$shiftsCreationHint = '<span class="text-danger">' . $shiftsCreationHint . '</span>';
|
||||
}
|
||||
|
||||
return page_with_title(__('Preview'), [
|
||||
// Save as previous state to be able to reuse it
|
||||
$previousEntries += [
|
||||
'shifttype_id' => $shifttype_id,
|
||||
'description' => $description,
|
||||
'title' => $title,
|
||||
'lid' => $lid,
|
||||
'start' => $request->input('start'),
|
||||
'end' => $request->input('end'),
|
||||
'mode' => $mode,
|
||||
'length' => $length,
|
||||
'change_hours' => implode(', ', $change_hours),
|
||||
'angelmode' => $angelmode,
|
||||
'shift_over_midnight' => $shift_over_midnight ? 'true' : 'false',
|
||||
];
|
||||
$session->set('admin_shifts_previous', $previousEntries);
|
||||
|
||||
$hidden_types = '';
|
||||
foreach ($previousEntries as $name => $value) {
|
||||
$hidden_types .= form_hidden($name, $value);
|
||||
}
|
||||
|
||||
return page_with_title(__('form.preview'), [
|
||||
form([
|
||||
$hidden_types,
|
||||
form_hidden('shifttype_id', $shifttype_id),
|
||||
form_hidden('description', $description),
|
||||
form_hidden('title', $title),
|
||||
form_hidden('rid', $rid),
|
||||
form_hidden('start', $start->format('Y-m-d H:i')),
|
||||
form_hidden('end', $end->format('Y-m-d H:i')),
|
||||
form_hidden('mode', $mode),
|
||||
form_hidden('length', $length),
|
||||
form_hidden('change_hours', implode(', ', $change_hours)),
|
||||
form_hidden('angelmode', $angelmode),
|
||||
form_hidden('shift_over_midnight', $shift_over_midnight ? 'true' : 'false'),
|
||||
form_submit('back', icon('chevron-left') . __('back')),
|
||||
form_submit('back', icon('chevron-left') . __('general.back')),
|
||||
$shiftsCreationHint,
|
||||
table([
|
||||
'timeslot' => __('Time and location'),
|
||||
'title' => __('Type and title'),
|
||||
'needed_angels' => __('Needed angels'),
|
||||
], $shifts_table),
|
||||
form_submit('submit', icon('save') . __('Save')),
|
||||
form_submit('submit', icon('save') . __('form.save')),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
@ -368,7 +403,7 @@ function admin_shifts()
|
|||
!is_array($session->get('admin_shifts_shifts'))
|
||||
|| !is_array($session->get('admin_shifts_types'))
|
||||
) {
|
||||
throw_redirect(page_link_to('admin_shifts'));
|
||||
throw_redirect(url('/admin-shifts'));
|
||||
}
|
||||
|
||||
$transactionId = Str::uuid();
|
||||
|
@ -405,22 +440,22 @@ function admin_shifts()
|
|||
}
|
||||
|
||||
success('Shifts created.');
|
||||
throw_redirect(page_link_to('admin_shifts'));
|
||||
throw_redirect(url('/admin-shifts'));
|
||||
} else {
|
||||
$session->remove('admin_shifts_shifts');
|
||||
$session->remove('admin_shifts_types');
|
||||
}
|
||||
|
||||
$rid = null;
|
||||
if ($request->has('rid')) {
|
||||
$rid = $request->input('rid');
|
||||
$lid = null;
|
||||
if ($request->has('lid')) {
|
||||
$lid = $request->input('lid');
|
||||
}
|
||||
$angel_types = '';
|
||||
foreach ($types as $type) {
|
||||
$angel_types .= '<div class="col-sm-6 col-md-8 col-lg-6 col-xl-4 col-xxl-3">'
|
||||
. form_spinner(
|
||||
'angeltype_count_' . $type->id,
|
||||
$type->name,
|
||||
htmlspecialchars($type->name),
|
||||
$needed_angel_types[$type->id],
|
||||
[
|
||||
'radio-name' => 'angelmode',
|
||||
|
@ -430,20 +465,36 @@ function admin_shifts()
|
|||
. '</div>';
|
||||
}
|
||||
|
||||
$link = button(url('/user-shifts'), icon('chevron-left'), 'btn-sm', '', __('general.back'));
|
||||
$reset = '';
|
||||
if ($session->has('admin_shifts_previous')) {
|
||||
$reset = form_submit(
|
||||
'back',
|
||||
icon('arrow-counterclockwise'),
|
||||
'',
|
||||
false,
|
||||
'link',
|
||||
__('Reset to previous state')
|
||||
);
|
||||
foreach ($session->get('admin_shifts_previous', []) as $name => $value) {
|
||||
$reset .= form_hidden($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return page_with_title(
|
||||
admin_shifts_title() . ' ' . sprintf(
|
||||
$link . ' ' . admin_shifts_title() . ' ' . sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
page_link_to('admin_shifts_history'),
|
||||
url('/admin/shifts/history'),
|
||||
icon('clock-history')
|
||||
),
|
||||
) . form([$reset], '', 'display:inline'),
|
||||
[
|
||||
msg(),
|
||||
form([
|
||||
div('row', [
|
||||
div('col-md-6 col-xl-5', [
|
||||
form_select('shifttype_id', __('Shifttype'), $shifttypes, $shifttype_id),
|
||||
form_text('title', __('Title'), $title),
|
||||
form_select('rid', __('Room'), $room_array, $rid),
|
||||
form_text('title', __('title.title'), $title),
|
||||
form_select('lid', __('Location'), $location_array, $lid),
|
||||
]),
|
||||
div('col-md-6 col-xl-7', [
|
||||
form_textarea('description', __('Additional description'), $description),
|
||||
|
@ -454,10 +505,22 @@ function admin_shifts()
|
|||
div('col-md-6 col-xl-5', [
|
||||
div('row', [
|
||||
div('col-lg-6', [
|
||||
form_datetime('start', __('Start'), $start),
|
||||
form_datetime(
|
||||
'start',
|
||||
__('shifts.start'),
|
||||
$request->has('start')
|
||||
? Carbon::createFromDatetime($request->input('start'))
|
||||
: $start
|
||||
),
|
||||
]),
|
||||
div('col-lg-6', [
|
||||
form_datetime('end', __('End'), $end),
|
||||
form_datetime(
|
||||
'end',
|
||||
__('shifts.end'),
|
||||
$request->has('end')
|
||||
? Carbon::createFromDatetime($request->input('end'))
|
||||
: $end
|
||||
),
|
||||
]),
|
||||
]),
|
||||
form_info(__('Mode')),
|
||||
|
@ -488,7 +551,7 @@ function admin_shifts()
|
|||
'change_hours',
|
||||
__('Shift change hours'),
|
||||
$request->has('change_hours')
|
||||
? $request->input('change_hours')
|
||||
? ($change_hours ? implode(', ', $change_hours) : $request->input('change_hours'))
|
||||
: '00, 04, 08, 10, 12, 14, 16, 18, 20, 22',
|
||||
false,
|
||||
null,
|
||||
|
@ -509,7 +572,13 @@ function admin_shifts()
|
|||
form_info(__('Needed angels')),
|
||||
form_radio(
|
||||
'angelmode',
|
||||
__('Take needed angels from room settings'),
|
||||
__('Copy needed angels from shift type settings'),
|
||||
$angelmode == 'shift_type',
|
||||
'shift_type'
|
||||
),
|
||||
form_radio(
|
||||
'angelmode',
|
||||
__('Copy needed angels from location settings'),
|
||||
$angelmode == 'location',
|
||||
'location'
|
||||
),
|
||||
|
@ -524,104 +593,8 @@ function admin_shifts()
|
|||
]),
|
||||
]),
|
||||
]),
|
||||
form_submit('preview', icon('search') . __('Preview')),
|
||||
form_submit('preview', icon('eye') . __('form.preview'), 'btn-info'),
|
||||
]),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function admin_shifts_history_title(): string
|
||||
{
|
||||
return __('Shifts history');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display shifts transaction history
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function admin_shifts_history(): string
|
||||
{
|
||||
if (!auth()->can('admin_shifts')) {
|
||||
throw new HttpForbidden();
|
||||
}
|
||||
|
||||
$request = request();
|
||||
$transactionId = $request->postData('transaction_id');
|
||||
if ($request->hasPostData('delete') && $transactionId) {
|
||||
$shifts = Shift::whereTransactionId($transactionId)->get();
|
||||
|
||||
engelsystem_log('Deleting ' . count($shifts) . ' shifts (transaction id ' . $transactionId . ')');
|
||||
|
||||
foreach ($shifts as $shift) {
|
||||
$shift = Shift($shift);
|
||||
foreach ($shift->shiftEntries as $entry) {
|
||||
event('shift.entry.deleting', [
|
||||
'user' => $entry->user,
|
||||
'start' => $shift->start,
|
||||
'end' => $shift->end,
|
||||
'name' => $shift->shiftType->name,
|
||||
'title' => $shift->title,
|
||||
'type' => $entry->angelType->name,
|
||||
'room' => $shift->room,
|
||||
'freeloaded' => $entry->freeloaded,
|
||||
]);
|
||||
}
|
||||
|
||||
$shift->delete();
|
||||
|
||||
engelsystem_log(
|
||||
'Deleted shift ' . $shift->title . ' / ' . $shift->shiftType->name
|
||||
. ' from ' . $shift->start->format('Y-m-d H:i')
|
||||
. ' to ' . $shift->end->format('Y-m-d H:i')
|
||||
);
|
||||
}
|
||||
|
||||
success(sprintf(__('%s shifts deleted.'), count($shifts)));
|
||||
throw_redirect(page_link_to('admin_shifts_history'));
|
||||
}
|
||||
|
||||
$schedules = Schedule::all()->pluck('name', 'id')->toArray();
|
||||
$shiftsData = Db::select('
|
||||
SELECT
|
||||
s.transaction_id,
|
||||
s.title,
|
||||
schedule_shift.schedule_id,
|
||||
COUNT(s.id) AS count,
|
||||
MIN(s.start) AS start,
|
||||
MAX(s.end) AS end,
|
||||
s.created_by AS user_id,
|
||||
MAX(s.created_at) AS created_at
|
||||
FROM shifts AS s
|
||||
LEFT JOIN schedule_shift on schedule_shift.shift_id = s.id
|
||||
WHERE s.transaction_id IS NOT NULL
|
||||
GROUP BY s.transaction_id
|
||||
ORDER BY created_at DESC
|
||||
');
|
||||
|
||||
foreach ($shiftsData as &$shiftData) {
|
||||
$shiftData['title'] = $shiftData['schedule_id'] ? __('shifts_history.schedule', [$schedules[$shiftData['schedule_id']]]) : $shiftData['title'];
|
||||
$shiftData['user'] = User_Nick_render(User::find($shiftData['user_id']));
|
||||
$shiftData['start'] = Carbon::make($shiftData['start'])->format(__('Y-m-d H:i'));
|
||||
$shiftData['end'] = Carbon::make($shiftData['end'])->format(__('Y-m-d H:i'));
|
||||
$shiftData['created_at'] = Carbon::make($shiftData['created_at'])->format(__('Y-m-d H:i'));
|
||||
$shiftData['actions'] = form([
|
||||
form_hidden('transaction_id', $shiftData['transaction_id']),
|
||||
form_submit('delete', icon('trash') . __('delete all'), 'btn-sm', true, 'danger'),
|
||||
]);
|
||||
}
|
||||
|
||||
return page_with_title(admin_shifts_history_title(), [
|
||||
msg(),
|
||||
table([
|
||||
'transaction_id' => __('ID'),
|
||||
'title' => __('Title'),
|
||||
'count' => __('Count'),
|
||||
'start' => __('Start'),
|
||||
'end' => __('End'),
|
||||
'user' => __('User'),
|
||||
'created_at' => __('Created'),
|
||||
'actions' => '',
|
||||
], $shiftsData),
|
||||
], true);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,9 @@ function admin_user()
|
|||
$goodie = GoodieType::from(config('goodie_type'));
|
||||
$goodie_enabled = $goodie !== GoodieType::None;
|
||||
$goodie_tshirt = $goodie === GoodieType::Tshirt;
|
||||
$user_info_edit = auth()->can('user.info.edit');
|
||||
$user_edit_shirt = auth()->can('user.edit.shirt');
|
||||
$user_edit = auth()->can('user.edit');
|
||||
|
||||
if (!$request->has('id')) {
|
||||
throw_redirect(users_link());
|
||||
|
@ -41,38 +44,51 @@ function admin_user()
|
|||
}
|
||||
|
||||
$html .= __('Here you can change the user entry. Under the item \'Arrived\' the angel is marked as present, a yes at Active means that the angel was active.');
|
||||
if ($goodie_enabled) {
|
||||
if ($goodie_enabled && $user_edit_shirt) {
|
||||
if ($goodie_tshirt) {
|
||||
$html .= ' ' . __('If the angel is active, it can claim a T-shirt. If T-shirt is set to \'Yes\', the angel already got their T-shirt.');
|
||||
} else {
|
||||
$html .= ' ' . __('If the angel is active, it can claim a goodie. If goodie is set to \'Yes\', the angel already got their goodie.');
|
||||
}
|
||||
}
|
||||
$html .= '<br /><br />';
|
||||
$html .= '<br><br>';
|
||||
$html .= '<form action="'
|
||||
. page_link_to('admin_user', ['action' => 'save', 'id' => $user_id])
|
||||
. url('/admin-user', ['action' => 'save', 'id' => $user_id])
|
||||
. '" method="post">' . "\n";
|
||||
$html .= form_csrf();
|
||||
$html .= '<table>' . "\n";
|
||||
$html .= '<input type="hidden" name="Type" value="Normal">' . "\n";
|
||||
$html .= '<tr><td>' . "\n";
|
||||
$html .= '<table>' . "\n";
|
||||
$html .= ' <tr><td>' . __('Nickname') . '</td><td>' . '<input size="40" name="eNick" value="' . $user_source->name . '" class="form-control" maxlength="24"></td></tr>' . "\n";
|
||||
$html .= ' <tr><td>' . __('general.nick') . '</td><td>'
|
||||
. '<input size="40" name="eNick" value="' . htmlspecialchars($user_source->name)
|
||||
. '" class="form-control" maxlength="24" ' . ($user_edit ? '' : 'disabled') . '>'
|
||||
. '</td></tr>' . "\n";
|
||||
$html .= ' <tr><td>' . __('Last login') . '</td><td><p class="help-block">'
|
||||
. ($user_source->last_login_at ? $user_source->last_login_at->format(__('Y-m-d H:i')) : '-')
|
||||
. ($user_source->last_login_at ? $user_source->last_login_at->format(__('general.datetime')) : '-')
|
||||
. '</p></td></tr>' . "\n";
|
||||
if (config('enable_user_name')) {
|
||||
$html .= ' <tr><td>' . __('Prename') . '</td><td>' . '<input size="40" name="eName" value="' . $user_source->personalData->last_name . '" class="form-control" maxlength="64"></td></tr>' . "\n";
|
||||
$html .= ' <tr><td>' . __('Last name') . '</td><td>' . '<input size="40" name="eVorname" value="' . $user_source->personalData->first_name . '" class="form-control" maxlength="64"></td></tr>' . "\n";
|
||||
$html .= ' <tr><td>' . __('settings.profile.firstname') . '</td><td>'
|
||||
. '<input size="40" name="eName" value="' . htmlspecialchars((string) $user_source->personalData->last_name) . '" class="form-control" maxlength="64">'
|
||||
. '</td></tr>' . "\n";
|
||||
$html .= ' <tr><td>' . __('settings.profile.lastname') . '</td><td>'
|
||||
. '<input size="40" name="eVorname" value="' . htmlspecialchars((string) $user_source->personalData->first_name) . '" class="form-control" maxlength="64">'
|
||||
. '</td></tr>' . "\n";
|
||||
}
|
||||
$html .= ' <tr><td>' . __('Mobile') . '</td><td>' . '<input type= "tel" size="40" name="eHandy" value="' . $user_source->contact->mobile . '" class="form-control" maxlength="40"></td></tr>' . "\n";
|
||||
$html .= ' <tr><td>' . __('settings.profile.mobile') . '</td><td>'
|
||||
. '<input type= "tel" size="40" name="eHandy" value="' . htmlspecialchars((string) $user_source->contact->mobile) . '" class="form-control" maxlength="40">'
|
||||
. '</td></tr>' . "\n";
|
||||
if (config('enable_dect')) {
|
||||
$html .= ' <tr><td>' . __('DECT') . '</td><td>' . '<input size="40" name="eDECT" value="' . $user_source->contact->dect . '" class="form-control" maxlength="40"></td></tr>' . "\n";
|
||||
$html .= ' <tr><td>' . __('general.dect') . '</td><td>'
|
||||
. '<input size="40" name="eDECT" value="' . htmlspecialchars((string) $user_source->contact->dect) . '" class="form-control" maxlength="40">'
|
||||
. '</td></tr>' . "\n";
|
||||
}
|
||||
if ($user_source->settings->email_human) {
|
||||
$html .= ' <tr><td>' . __('settings.profile.email') . '</td><td>' . '<input type="email" size="40" name="eemail" value="' . $user_source->email . '" class="form-control" maxlength="254"></td></tr>' . "\n";
|
||||
$html .= ' <tr><td>' . __('general.email') . '</td><td>'
|
||||
. '<input type="email" size="40" name="eemail" value="' . htmlspecialchars($user_source->email) . '" class="form-control" maxlength="254">'
|
||||
. '</td></tr>' . "\n";
|
||||
}
|
||||
if ($goodie_tshirt) {
|
||||
if ($goodie_tshirt && $user_edit_shirt) {
|
||||
$html .= ' <tr><td>' . __('user.shirt_size') . '</td><td>'
|
||||
. html_select_key(
|
||||
'size',
|
||||
|
@ -84,34 +100,50 @@ function admin_user()
|
|||
. '</td></tr>' . "\n";
|
||||
}
|
||||
|
||||
// User info
|
||||
if ($user_info_edit) {
|
||||
$html .= ' <tr><td>'
|
||||
. __('user.info')
|
||||
. ' <span class="bi bi-info-circle-fill text-info" data-bs-toggle="tooltip" title="'
|
||||
. __('user.info.hint')
|
||||
. '"></span>'
|
||||
. '</td><td>'
|
||||
. '<textarea cols="40" rows="" name="userInfo" class="form-control">'
|
||||
. htmlspecialchars((string) $user_source->state->user_info)
|
||||
. '</textarea>'
|
||||
. '</td></tr>' . "\n";
|
||||
}
|
||||
|
||||
$options = [
|
||||
'1' => __('Yes'),
|
||||
'0' => __('No'),
|
||||
];
|
||||
|
||||
// Gekommen?
|
||||
$html .= ' <tr><td>' . __('Arrived') . '</td><td>' . "\n";
|
||||
if ($user_source->state->arrived) {
|
||||
$html .= __('Yes');
|
||||
} else {
|
||||
$html .= __('No');
|
||||
}
|
||||
// Arrived?
|
||||
$html .= ' <tr><td>' . __('user.arrived') . '</td><td>' . "\n";
|
||||
$html .= ($user_source->state->arrived ? __('Yes') : __('No'));
|
||||
$html .= '</td></tr>' . "\n";
|
||||
|
||||
// Aktiv?
|
||||
$html .= ' <tr><td>' . __('user.active') . '</td><td>' . "\n";
|
||||
$html .= html_options('eAktiv', $options, $user_source->state->active) . '</td></tr>' . "\n";
|
||||
// Active?
|
||||
if ($user_edit_shirt) {
|
||||
$html .= ' <tr><td>' . __('user.active') . '</td><td>' . "\n";
|
||||
$html .= html_options('eAktiv', $options, $user_source->state->active) . '</td></tr>' . "\n";
|
||||
} else {
|
||||
$html .= ' <tr><td>' . __('user.active') . '</td><td>' . "\n";
|
||||
$html .= ($user_source->state->active ? __('Yes') : __('No'));
|
||||
$html .= '</td></tr>' . "\n";
|
||||
}
|
||||
|
||||
// Aktiv erzwingen
|
||||
// Forced active?
|
||||
if (auth()->can('admin_active')) {
|
||||
$html .= ' <tr><td>' . __('Force active') . '</td><td>' . "\n";
|
||||
$html .= html_options('force_active', $options, $user_source->state->force_active) . '</td></tr>' . "\n";
|
||||
}
|
||||
|
||||
if ($goodie_enabled) {
|
||||
if ($goodie_enabled && $user_edit_shirt) {
|
||||
// T-Shirt bekommen?
|
||||
if ($goodie_tshirt) {
|
||||
$html .= ' <tr><td>' . __('T-Shirt') . '</td><td>' . "\n";
|
||||
$html .= ' <tr><td>' . __('T-shirt') . '</td><td>' . "\n";
|
||||
} else {
|
||||
$html .= ' <tr><td>' . __('Goodie') . '</td><td>' . "\n";
|
||||
}
|
||||
|
@ -120,27 +152,36 @@ function admin_user()
|
|||
$html .= '</table>' . "\n" . '</td><td></td></tr>';
|
||||
|
||||
$html .= '</td></tr>' . "\n";
|
||||
$html .= '</table>' . "\n" . '<br />' . "\n";
|
||||
$html .= '<button type="submit" class="btn btn-primary">' . __('form.save') . '</button>' . "\n";
|
||||
$html .= '</table>' . "\n" . '<br>' . "\n";
|
||||
$html .= '<button type="submit" class="btn btn-primary">'
|
||||
. icon('save') . __('form.save') . '</button>' . "\n";
|
||||
$html .= '</form>';
|
||||
|
||||
$html .= '<hr />';
|
||||
$html .= '<hr>';
|
||||
|
||||
$html .= form_info('', __('Please visit the angeltypes page or the users profile to manage the users angeltypes.'));
|
||||
$html .= __('Here you can reset the password of this angel:');
|
||||
|
||||
$html .= ' ' . __('Here you can reset the password of this angel:') . '<form action="'
|
||||
. page_link_to('admin_user', ['action' => 'change_pw', 'id' => $user_id])
|
||||
$html .= '<form action="'
|
||||
. url('/admin-user', ['action' => 'change_pw', 'id' => $user_id])
|
||||
. '" method="post">' . "\n";
|
||||
$html .= form_csrf();
|
||||
$html .= '<table>' . "\n";
|
||||
$html .= ' <tr><td>' . __('Password') . '</td><td>' . '<input type="password" size="40" name="new_pw" value="" class="form-control" autocomplete="new-password"></td></tr>' . "\n";
|
||||
$html .= ' <tr><td>' . __('Confirm password') . '</td><td>' . '<input type="password" size="40" name="new_pw2" value="" class="form-control" autocomplete="new-password"></td></tr>' . "\n";
|
||||
$html .= ' <tr><td>' . __('settings.password')
|
||||
. ' <span class="bi bi-info-circle-fill text-info" data-bs-toggle="tooltip" title="'
|
||||
. __('password.minimal_length', [config('min_password_length')]) . '"></span>'
|
||||
. '</td><td>'
|
||||
. '<input type="password" size="40" name="new_pw" value="" class="form-control" autocomplete="new-password">'
|
||||
. '</td></tr>' . "\n";
|
||||
$html .= ' <tr><td>' . __('password.reset.confirm') . '</td><td>'
|
||||
. '<input type="password" size="40" name="new_pw2" value="" class="form-control" autocomplete="new-password">'
|
||||
. '</td></tr>' . "\n";
|
||||
|
||||
$html .= '</table>' . "\n" . '<br />' . "\n";
|
||||
$html .= '<button type="submit" class="btn btn-primary">' . __('form.save') . '</button>' . "\n";
|
||||
$html .= '</table>' . "\n" . '<br>' . "\n";
|
||||
$html .= '<button type="submit" class="btn btn-primary">'
|
||||
. icon('save') . __('form.save') . '</button>' . "\n";
|
||||
$html .= '</form>';
|
||||
|
||||
$html .= '<hr />';
|
||||
$html .= '<hr>';
|
||||
|
||||
/** @var Group $my_highest_group */
|
||||
$my_highest_group = $user->groups()->orderByDesc('id')->first();
|
||||
|
@ -158,7 +199,7 @@ function admin_user()
|
|||
&& ($my_highest_group >= $angel_highest_group || is_null($angel_highest_group))
|
||||
) {
|
||||
$html .= __('Here you can define the user groups of the angel:') . '<form action="'
|
||||
. page_link_to('admin_user', ['action' => 'save_groups', 'id' => $user_id])
|
||||
. url('/admin-user', ['action' => 'save_groups', 'id' => $user_id])
|
||||
. '" method="post">' . "\n";
|
||||
$html .= form_csrf();
|
||||
$html .= '<div>';
|
||||
|
@ -168,19 +209,22 @@ function admin_user()
|
|||
$html .= '<div class="form-check">'
|
||||
. '<input class="form-check-input" type="checkbox" id="' . $group->id . '" name="groups[]" value="' . $group->id . '" '
|
||||
. ($group->selected ? ' checked="checked"' : '')
|
||||
. ' /><label class="form-check-label" for="' . $group->id . '">' . $group->name . '</label></div>';
|
||||
. ' /><label class="form-check-label" for="' . $group->id . '">'
|
||||
. htmlspecialchars($group->name)
|
||||
. '</label></div>';
|
||||
}
|
||||
|
||||
$html .= '</div><br>';
|
||||
|
||||
$html .= '<button type="submit" class="btn btn-primary">' . __('form.save') . '</button>' . "\n";
|
||||
$html .= '<button type="submit" class="btn btn-primary">'
|
||||
. icon('save') . __('form.save') . '</button>' . "\n";
|
||||
$html .= '</form>';
|
||||
|
||||
$html .= '<hr />';
|
||||
$html .= '<hr>';
|
||||
}
|
||||
|
||||
$html .= buttons([
|
||||
button(user_delete_link($user_source->id), icon('trash') . __('delete'), 'btn-danger'),
|
||||
button(user_delete_link($user_source->id), icon('trash') . __('form.delete'), 'btn-danger'),
|
||||
]);
|
||||
|
||||
$html .= '<hr>';
|
||||
|
@ -237,19 +281,21 @@ function admin_user()
|
|||
break;
|
||||
|
||||
case 'save':
|
||||
$force_active = $user->state->force_active;
|
||||
$user_source = User::find($user_id);
|
||||
if (auth()->can('admin_active')) {
|
||||
$force_active = $request->input('force_active');
|
||||
}
|
||||
|
||||
$changed_email = false;
|
||||
if ($user_source->settings->email_human) {
|
||||
$changed_email = $user_source->email !== $request->postData('eemail');
|
||||
$user_source->email = $request->postData('eemail');
|
||||
}
|
||||
|
||||
$nick = trim($request->get('eNick'));
|
||||
$nickValid = (new Username())->validate($nick);
|
||||
|
||||
if ($nickValid) {
|
||||
$changed_nick = false;
|
||||
$old_nick = $user_source->name;
|
||||
if ($nickValid && $user_edit) {
|
||||
$changed_nick = $user_source->name !== $nick;
|
||||
$user_source->name = $nick;
|
||||
}
|
||||
$user_source->save();
|
||||
|
@ -258,30 +304,45 @@ function admin_user()
|
|||
$user_source->personalData->first_name = $request->postData('eVorname');
|
||||
$user_source->personalData->last_name = $request->postData('eName');
|
||||
}
|
||||
if ($goodie_tshirt) {
|
||||
if ($goodie_tshirt && $user_edit_shirt) {
|
||||
$user_source->personalData->shirt_size = $request->postData('eSize');
|
||||
}
|
||||
$user_source->personalData->save();
|
||||
|
||||
$user_source->contact->mobile = $request->postData('eHandy');
|
||||
$user_source->contact->dect = $request->postData('eDECT');
|
||||
if (config('enable_dect')) {
|
||||
$user_source->contact->dect = $request->postData('eDECT');
|
||||
}
|
||||
$user_source->contact->save();
|
||||
|
||||
if ($goodie_enabled) {
|
||||
if ($goodie_enabled && $user_edit_shirt) {
|
||||
$user_source->state->got_shirt = $request->postData('eTshirt');
|
||||
}
|
||||
$user_source->state->active = $request->postData('eAktiv');
|
||||
$user_source->state->force_active = $force_active;
|
||||
if ($user_info_edit) {
|
||||
$user_source->state->user_info = $request->postData('userInfo');
|
||||
}
|
||||
|
||||
if ($user_edit_shirt) {
|
||||
$user_source->state->active = $request->postData('eAktiv');
|
||||
}
|
||||
if (auth()->can('admin_active')) {
|
||||
$user_source->state->force_active = $request->input('force_active');
|
||||
}
|
||||
$user_source->state->save();
|
||||
|
||||
engelsystem_log(
|
||||
'Updated user: ' . $user_source->name . ' (' . $user_source->id . ')'
|
||||
. ($goodie_tshirt ? ', t-shirt: ' : '' . $user_source->personalData->shirt_size)
|
||||
'Updated user: ' . ($changed_nick
|
||||
? ('nick modified form ' . $old_nick . ' to ' . $user_source->name)
|
||||
: $user_source->name)
|
||||
. ' (' . $user_source->id . ')'
|
||||
. ($changed_email ? ', email modified' : '')
|
||||
. ($goodie_tshirt ? ', t-shirt-size: ' . $user_source->personalData->shirt_size : '')
|
||||
. ', active: ' . $user_source->state->active
|
||||
. ', force-active: ' . $user_source->state->force_active
|
||||
. ($goodie_tshirt ? ', tshirt: ' : ', goodie: ' . $user_source->state->got_shirt)
|
||||
. ($goodie_tshirt ? ', t-shirt: ' : ', goodie: ' . $user_source->state->got_shirt)
|
||||
. ($user_info_edit ? ', user-info: ' . $user_source->state->user_info : '')
|
||||
);
|
||||
$html .= success(__('Changes where saved.') . "\n", true);
|
||||
$html .= success(__('Changes were saved.') . "\n", true);
|
||||
break;
|
||||
|
||||
case 'change_pw':
|
||||
|
@ -303,9 +364,13 @@ function admin_user()
|
|||
}
|
||||
}
|
||||
|
||||
return page_with_title(__('Edit user'), [
|
||||
$link = button(url('/users', ['action' => 'view', 'user_id' => $user_id]), icon('chevron-left'), 'btn-sm', '', __('general.back'));
|
||||
return page_with_title(
|
||||
$link . ' ' . __('Edit user'),
|
||||
[
|
||||
$html,
|
||||
]);
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,543 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Engelsystem\Database\Database;
|
||||
use Engelsystem\Events\Listener\OAuth2;
|
||||
use Engelsystem\Config\GoodieType;
|
||||
use Engelsystem\Http\Validation\Rules\Username;
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Group;
|
||||
use Engelsystem\Models\OAuth;
|
||||
use Engelsystem\Models\User\Contact;
|
||||
use Engelsystem\Models\User\PersonalData;
|
||||
use Engelsystem\Models\User\Settings;
|
||||
use Engelsystem\Models\User\State;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function register_title()
|
||||
{
|
||||
return __('Register');
|
||||
}
|
||||
|
||||
/**
|
||||
* Engel registrieren
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function guest_register()
|
||||
{
|
||||
$authUser = auth()->user();
|
||||
$tshirt_sizes = config('tshirt_sizes');
|
||||
$goodie = GoodieType::from(config('goodie_type'));
|
||||
$goodie_enabled = $goodie !== GoodieType::None;
|
||||
$goodie_tshirt = $goodie === GoodieType::Tshirt;
|
||||
$enable_user_name = config('enable_user_name');
|
||||
$enable_dect = config('enable_dect');
|
||||
$enable_planned_arrival = config('enable_planned_arrival');
|
||||
$min_password_length = config('min_password_length');
|
||||
$enable_password = config('enable_password');
|
||||
$enable_pronoun = config('enable_pronoun');
|
||||
$enable_mobile_show = config('enable_mobile_show');
|
||||
$config = config();
|
||||
$request = request();
|
||||
$session = session();
|
||||
/** @var Connection $db */
|
||||
$db = app(Database::class)->getConnection();
|
||||
$is_oauth = $session->has('oauth2_connect_provider');
|
||||
|
||||
$msg = '';
|
||||
$nick = '';
|
||||
$lastName = '';
|
||||
$preName = '';
|
||||
$dect = '';
|
||||
$mobile = '';
|
||||
$mobile_show = false;
|
||||
$email = '';
|
||||
$pronoun = '';
|
||||
$email_shiftinfo = false;
|
||||
$email_by_human_allowed = false;
|
||||
$email_messages = false;
|
||||
$email_news = false;
|
||||
$email_goody = false;
|
||||
$tshirt_size = '';
|
||||
$password_hash = '';
|
||||
$selected_angel_types = [];
|
||||
$planned_arrival_date = null;
|
||||
|
||||
/** @var AngelType[]|Collection $angel_types_source */
|
||||
$angel_types_source = AngelType::all();
|
||||
$angel_types = [];
|
||||
if (!empty($session->get('oauth2_groups'))) {
|
||||
/** @var OAuth2 $oauth */
|
||||
$oauth = app()->get(OAuth2::class);
|
||||
$ssoTeams = $oauth->getSsoTeams($session->get('oauth2_connect_provider'));
|
||||
foreach ($ssoTeams as $name => $team) {
|
||||
if (in_array($name, $session->get('oauth2_groups'))) {
|
||||
$selected_angel_types[] = $team['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($angel_types_source as $angel_type) {
|
||||
if ($angel_type->hide_register) {
|
||||
continue;
|
||||
}
|
||||
$angel_types[$angel_type->id] = $angel_type->name
|
||||
. ($angel_type->restricted ? ' (' . __('Requires introduction') . ')' : '');
|
||||
if (!$angel_type->restricted) {
|
||||
$selected_angel_types[] = $angel_type->id;
|
||||
}
|
||||
}
|
||||
|
||||
$oauth_enable_password = $session->get('oauth2_enable_password');
|
||||
if (!is_null($oauth_enable_password)) {
|
||||
$enable_password = $oauth_enable_password;
|
||||
}
|
||||
|
||||
if (
|
||||
!auth()->can('register') // No registration permission
|
||||
// Not authenticated and
|
||||
|| (!$authUser && !config('registration_enabled') && !$session->get('oauth2_allow_registration')) // Registration disabled
|
||||
|| (!$authUser && !$enable_password && !$is_oauth) // Password disabled and not oauth
|
||||
) {
|
||||
error(__('Registration is disabled.'));
|
||||
|
||||
return page_with_title(register_title(), [
|
||||
msg(),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($request->hasPostData('submit')) {
|
||||
$valid = true;
|
||||
|
||||
if ($request->has('username')) {
|
||||
$nick = trim($request->get('username'));
|
||||
$nickValid = (new Username())->validate($nick);
|
||||
|
||||
if (!$nickValid) {
|
||||
$valid = false;
|
||||
$msg .= error(sprintf(
|
||||
__('Please enter a valid nick.') . ' ' . __('Use up to 24 letters, numbers or connecting punctuations for your nickname.'),
|
||||
$nick
|
||||
), true);
|
||||
}
|
||||
if (User::whereName($nick)->count() > 0) {
|
||||
$valid = false;
|
||||
$msg .= error(sprintf(__('Your nick "%s" already exists.'), htmlspecialchars($nick)), true);
|
||||
}
|
||||
} else {
|
||||
$valid = false;
|
||||
$msg .= error(__('Please enter a nickname.'), true);
|
||||
}
|
||||
|
||||
if ($request->has('mobile_show') && $enable_mobile_show) {
|
||||
$mobile_show = true;
|
||||
}
|
||||
|
||||
if ($request->has('email') && strlen(strip_request_item('email')) > 0) {
|
||||
$email = strip_request_item('email');
|
||||
if (!check_email($email)) {
|
||||
$valid = false;
|
||||
$msg .= error(__('E-mail address is not correct.'), true);
|
||||
}
|
||||
if (User::whereEmail($email)->first()) {
|
||||
$valid = false;
|
||||
$msg .= error(__('E-mail address is already used by another user.'), true);
|
||||
}
|
||||
} else {
|
||||
$valid = false;
|
||||
$msg .= error(__('Please enter your e-mail.'), true);
|
||||
}
|
||||
|
||||
if ($request->has('email_shiftinfo')) {
|
||||
$email_shiftinfo = true;
|
||||
}
|
||||
|
||||
if ($request->has('email_by_human_allowed')) {
|
||||
$email_by_human_allowed = true;
|
||||
}
|
||||
|
||||
if ($request->has('email_messages')) {
|
||||
$email_messages = true;
|
||||
}
|
||||
|
||||
if ($request->has('email_news')) {
|
||||
$email_news = true;
|
||||
}
|
||||
|
||||
if ($request->has('email_goody')) {
|
||||
$email_goody = true;
|
||||
}
|
||||
|
||||
if ($goodie_tshirt) {
|
||||
if ($request->has('tshirt_size') && isset($tshirt_sizes[$request->input('tshirt_size')])) {
|
||||
$tshirt_size = $request->input('tshirt_size');
|
||||
} else {
|
||||
$valid = false;
|
||||
$msg .= error(__('Please select your shirt size.'), true);
|
||||
}
|
||||
}
|
||||
|
||||
if ($enable_password && $request->has('password') && strlen($request->postData('password')) >= $min_password_length) {
|
||||
if ($request->postData('password') != $request->postData('password2')) {
|
||||
$valid = false;
|
||||
$msg .= error(__('Your passwords don\'t match.'), true);
|
||||
}
|
||||
} elseif ($enable_password) {
|
||||
$valid = false;
|
||||
$msg .= error(sprintf(
|
||||
__('Your password is too short (please use at least %s characters).'),
|
||||
$min_password_length
|
||||
), true);
|
||||
}
|
||||
|
||||
if ($request->has('planned_arrival_date') && $enable_planned_arrival) {
|
||||
$tmp = parse_date('Y-m-d H:i', $request->input('planned_arrival_date') . ' 00:00');
|
||||
$result = User_validate_planned_arrival_date($tmp);
|
||||
$planned_arrival_date = $result->getValue();
|
||||
if (!$result->isValid()) {
|
||||
$valid = false;
|
||||
error(__('Please enter your planned date of arrival. It should be after the buildup start date and before teardown end date.'));
|
||||
}
|
||||
} elseif ($enable_planned_arrival) {
|
||||
$valid = false;
|
||||
error(__('Please enter your planned date of arrival. It should be after the buildup start date and before teardown end date.'));
|
||||
}
|
||||
|
||||
$selected_angel_types = [];
|
||||
foreach (array_keys($angel_types) as $angel_type_id) {
|
||||
if ($request->has('angel_types_' . $angel_type_id)) {
|
||||
$selected_angel_types[] = $angel_type_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Trivia
|
||||
if ($enable_user_name && $request->has('lastname')) {
|
||||
$lastName = strip_request_item('lastname');
|
||||
}
|
||||
if ($enable_user_name && $request->has('prename')) {
|
||||
$preName = strip_request_item('prename');
|
||||
}
|
||||
if ($enable_pronoun && $request->has('pronoun')) {
|
||||
$pronoun = strip_request_item('pronoun');
|
||||
}
|
||||
if ($enable_dect && $request->has('dect')) {
|
||||
if (strlen(strip_request_item('dect')) <= 40) {
|
||||
$dect = strip_request_item('dect');
|
||||
} else {
|
||||
$valid = false;
|
||||
error(__('For dect numbers are only 40 digits allowed.'));
|
||||
}
|
||||
}
|
||||
if ($request->has('mobile')) {
|
||||
$mobile = strip_request_item('mobile');
|
||||
}
|
||||
|
||||
if ($valid) {
|
||||
// Safeguard against partially created user data
|
||||
$db->beginTransaction();
|
||||
|
||||
$user = new User([
|
||||
'name' => $nick,
|
||||
'password' => $password_hash,
|
||||
'email' => $email,
|
||||
'api_key' => '',
|
||||
'last_login_at' => null,
|
||||
]);
|
||||
$user->save();
|
||||
|
||||
$contact = new Contact([
|
||||
'dect' => $dect,
|
||||
'mobile' => $mobile,
|
||||
]);
|
||||
$contact->user()
|
||||
->associate($user)
|
||||
->save();
|
||||
|
||||
$personalData = new PersonalData([
|
||||
'first_name' => $preName,
|
||||
'last_name' => $lastName,
|
||||
'pronoun' => $pronoun,
|
||||
'shirt_size' => $tshirt_size,
|
||||
'planned_arrival_date' => $enable_planned_arrival ? Carbon::createFromTimestamp($planned_arrival_date) : null,
|
||||
]);
|
||||
$personalData->user()
|
||||
->associate($user)
|
||||
->save();
|
||||
|
||||
$settings = new Settings([
|
||||
'language' => $session->get('locale'),
|
||||
'theme' => config('theme'),
|
||||
'email_human' => $email_by_human_allowed,
|
||||
'email_messages' => $email_messages,
|
||||
'email_goody' => $email_goody,
|
||||
'email_shiftinfo' => $email_shiftinfo,
|
||||
'email_news' => $email_news,
|
||||
'mobile_show' => $mobile_show,
|
||||
]);
|
||||
$settings->user()
|
||||
->associate($user)
|
||||
->save();
|
||||
|
||||
$state = new State([]);
|
||||
if (config('autoarrive')) {
|
||||
$state->arrived = true;
|
||||
$state->arrival_date = new Carbon();
|
||||
}
|
||||
$state->user()
|
||||
->associate($user)
|
||||
->save();
|
||||
|
||||
if ($session->has('oauth2_connect_provider') && $session->has('oauth2_user_id')) {
|
||||
$oauth = new OAuth([
|
||||
'provider' => $session->get('oauth2_connect_provider'),
|
||||
'identifier' => $session->get('oauth2_user_id'),
|
||||
'access_token' => $session->get('oauth2_access_token'),
|
||||
'refresh_token' => $session->get('oauth2_refresh_token'),
|
||||
'expires_at' => $session->get('oauth2_expires_at'),
|
||||
]);
|
||||
$oauth->user()
|
||||
->associate($user)
|
||||
->save();
|
||||
|
||||
$session->remove('oauth2_connect_provider');
|
||||
$session->remove('oauth2_user_id');
|
||||
$session->remove('oauth2_access_token');
|
||||
$session->remove('oauth2_refresh_token');
|
||||
$session->remove('oauth2_expires_at');
|
||||
}
|
||||
|
||||
// Assign user-group and set password
|
||||
$defaultGroup = Group::find(auth()->getDefaultRole());
|
||||
$user->groups()->attach($defaultGroup);
|
||||
if ($enable_password) {
|
||||
auth()->setPassword($user, $request->postData('password'));
|
||||
}
|
||||
|
||||
// Assign angel-types
|
||||
$user_angel_types_info = [];
|
||||
foreach ($selected_angel_types as $selected_angel_type_id) {
|
||||
$angelType = AngelType::findOrFail($selected_angel_type_id);
|
||||
$user->userAngelTypes()->attach($angelType);
|
||||
$user_angel_types_info[] = $angelType->name;
|
||||
}
|
||||
|
||||
// Commit complete user data
|
||||
$db->commit();
|
||||
|
||||
engelsystem_log(
|
||||
'User ' . User_Nick_render($user, true)
|
||||
. ' signed up as: ' . join(', ', $user_angel_types_info)
|
||||
);
|
||||
success(__('Angel registration successful!'));
|
||||
|
||||
// User is already logged in - that means a supporter has registered an angel. Return to register page.
|
||||
if ($authUser) {
|
||||
throw_redirect(page_link_to('register'));
|
||||
}
|
||||
|
||||
// If a welcome message is present, display it on the next page
|
||||
if ($config->get('welcome_msg')) {
|
||||
$session->set('show_welcome', true);
|
||||
}
|
||||
|
||||
// Login the user
|
||||
if ($user->oauth->count()) {
|
||||
/** @var OAuth $provider */
|
||||
$provider = $user->oauth->first();
|
||||
throw_redirect(url('/oauth/' . $provider->provider));
|
||||
}
|
||||
|
||||
throw_redirect(page_link_to('/'));
|
||||
}
|
||||
}
|
||||
|
||||
$buildup_start_date = time();
|
||||
$teardown_end_date = null;
|
||||
if ($buildup = $config->get('buildup_start')) {
|
||||
/** @var Carbon $buildup */
|
||||
$buildup_start_date = $buildup->getTimestamp();
|
||||
}
|
||||
|
||||
if ($teardown = $config->get('teardown_end')) {
|
||||
/** @var Carbon $teardown */
|
||||
$teardown_end_date = $teardown->getTimestamp();
|
||||
}
|
||||
|
||||
$form_data = $session->get('form_data');
|
||||
$session->remove('form_data');
|
||||
if (!$nick && !empty($form_data['name'])) {
|
||||
$nick = $form_data['name'];
|
||||
}
|
||||
|
||||
if (!$email && !empty($form_data['email'])) {
|
||||
$email = $form_data['email'];
|
||||
}
|
||||
|
||||
if (!$preName && !empty($form_data['first_name'])) {
|
||||
$preName = $form_data['first_name'];
|
||||
}
|
||||
|
||||
if (!$lastName && !empty($form_data['last_name'])) {
|
||||
$lastName = $form_data['last_name'];
|
||||
}
|
||||
|
||||
return page_with_title(register_title(), [
|
||||
__('By completing this form you\'re registering as a Chaos-Angel. This script will create you an account in the angel task scheduler.'),
|
||||
form_info(entry_required() . ' = ' . __('Entry required!')),
|
||||
$msg,
|
||||
msg(),
|
||||
form([
|
||||
div('row', [
|
||||
div('col', [
|
||||
form_text(
|
||||
'username',
|
||||
__('Nick') . ' ' . entry_required(),
|
||||
$nick,
|
||||
false,
|
||||
24,
|
||||
'nickname'
|
||||
),
|
||||
form_info(
|
||||
'',
|
||||
__('Use up to 24 letters, numbers or connecting punctuations for your nickname.')
|
||||
),
|
||||
]),
|
||||
|
||||
$enable_pronoun ? div('col', [
|
||||
form_text('pronoun', __('Pronoun'), $pronoun, false, 15),
|
||||
]) : '',
|
||||
]),
|
||||
|
||||
$enable_user_name ? div('row', [
|
||||
div('col', [
|
||||
form_text('prename', __('First name'), $preName, false, 64, 'given-name'),
|
||||
]),
|
||||
div('col', [
|
||||
form_text('lastname', __('Last name'), $lastName, false, 64, 'family-name'),
|
||||
]),
|
||||
]) : '',
|
||||
|
||||
div('row', [
|
||||
div('col', [
|
||||
form_email(
|
||||
'email',
|
||||
__('E-Mail') . ' ' . entry_required(),
|
||||
$email,
|
||||
false,
|
||||
'email',
|
||||
254
|
||||
),
|
||||
form_checkbox(
|
||||
'email_shiftinfo',
|
||||
__(
|
||||
'settings.profile.email_shiftinfo',
|
||||
[config('app_name')]
|
||||
),
|
||||
$email_shiftinfo
|
||||
),
|
||||
form_checkbox(
|
||||
'email_news',
|
||||
__('Notify me of new news'),
|
||||
$email_news
|
||||
),
|
||||
form_checkbox(
|
||||
'email_messages',
|
||||
__('settings.profile.email_messages'),
|
||||
$email_messages
|
||||
),
|
||||
form_checkbox(
|
||||
'email_by_human_allowed',
|
||||
__('Allow heaven angels to contact you by e-mail.'),
|
||||
$email_by_human_allowed
|
||||
),
|
||||
$goodie_enabled ?
|
||||
form_checkbox(
|
||||
'email_goody',
|
||||
__('To receive vouchers, give consent that nick, email address, worked hours and shirt size will be stored until the next similar event.')
|
||||
. (config('privacy_email') ? ' ' . __('To withdraw your approval, send an email to <a href="mailto:%s">%1$s</a>.', [config('privacy_email')]) : ''),
|
||||
$email_goody
|
||||
) : '',
|
||||
]),
|
||||
|
||||
$enable_dect ? div('col', [
|
||||
form_text('dect', __('DECT'), $dect, false, 40, 'tel-local'),
|
||||
]) : '',
|
||||
|
||||
div('col', [
|
||||
form_text('mobile', __('Mobile'), $mobile, false, 40, 'tel-national'),
|
||||
$enable_mobile_show ? form_checkbox(
|
||||
'mobile_show',
|
||||
__('Show mobile number to other users to contact me'),
|
||||
$mobile_show
|
||||
) : '',
|
||||
]),
|
||||
]),
|
||||
|
||||
div('row', [
|
||||
$enable_password ? div('col', [
|
||||
form_password('password', __('Password') . ' ' . entry_required(), 'new-password'),
|
||||
]) : '',
|
||||
|
||||
$enable_planned_arrival ? div('col', [
|
||||
form_date(
|
||||
'planned_arrival_date',
|
||||
__('Planned date of arrival') . ' ' . entry_required(),
|
||||
$planned_arrival_date,
|
||||
$buildup_start_date,
|
||||
$teardown_end_date
|
||||
),
|
||||
]) : '',
|
||||
]),
|
||||
|
||||
div('row', [
|
||||
$enable_password ? div('col', [
|
||||
form_password('password2', __('Confirm password') . ' ' . entry_required(), 'new-password'),
|
||||
]) : '',
|
||||
|
||||
div('col', [
|
||||
$goodie_tshirt ? form_select(
|
||||
'tshirt_size',
|
||||
__('Shirt size') . ' ' . entry_required(),
|
||||
$tshirt_sizes,
|
||||
$tshirt_size,
|
||||
__('form.select_placeholder')
|
||||
) : '',
|
||||
]),
|
||||
]),
|
||||
|
||||
div('row', [
|
||||
div('col', [
|
||||
form_checkboxes(
|
||||
'angel_types',
|
||||
__('What do you want to do?') . sprintf(
|
||||
' (<a href="%s">%s</a>)',
|
||||
url('/angeltypes/about'),
|
||||
__('Description of job types')
|
||||
),
|
||||
$angel_types,
|
||||
$selected_angel_types
|
||||
),
|
||||
form_info(
|
||||
'',
|
||||
__('Some angel types have to be confirmed later by a supporter at an introduction meeting. You can change your selection in the options section.')
|
||||
),
|
||||
]),
|
||||
]),
|
||||
|
||||
form_submit('submit', __('Register')),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function entry_required()
|
||||
{
|
||||
return icon('exclamation-triangle', 'text-info');
|
||||
}
|
|
@ -16,7 +16,7 @@ use Engelsystem\Helpers\Schedule\XmlParser;
|
|||
use Engelsystem\Helpers\Uuid;
|
||||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Models\Room as RoomModel;
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\Models\Shifts\Schedule as ScheduleUrl;
|
||||
use Engelsystem\Models\Shifts\ScheduleShift;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
|
@ -110,10 +110,15 @@ class ImportSchedule extends BaseController
|
|||
/** @var ScheduleUrl $schedule */
|
||||
$schedule = ScheduleUrl::findOrNew($scheduleId);
|
||||
|
||||
if ($request->request->has('delete')) {
|
||||
return $this->delete($schedule);
|
||||
}
|
||||
|
||||
$data = $this->validate($request, [
|
||||
'name' => 'required',
|
||||
'url' => 'required',
|
||||
'shift_type' => 'required|int',
|
||||
'needed_from_shift_type' => 'optional|checked',
|
||||
'minutes_before' => 'int',
|
||||
'minutes_after' => 'int',
|
||||
]);
|
||||
|
@ -125,17 +130,19 @@ class ImportSchedule extends BaseController
|
|||
$schedule->name = $data['name'];
|
||||
$schedule->url = $data['url'];
|
||||
$schedule->shift_type = $data['shift_type'];
|
||||
$schedule->needed_from_shift_type = (bool) $data['needed_from_shift_type'];
|
||||
$schedule->minutes_before = $data['minutes_before'];
|
||||
$schedule->minutes_after = $data['minutes_after'];
|
||||
|
||||
$schedule->save();
|
||||
|
||||
$this->log->info(
|
||||
'Schedule {name}: Url {url}, Shift Type {shift_type}, minutes before/after {before}/{after}',
|
||||
'Schedule {name}: Url {url}, Shift Type {shift_type}, ({need}), minutes before/after {before}/{after}',
|
||||
[
|
||||
'name' => $schedule->name,
|
||||
'url' => $schedule->name,
|
||||
'shift_type' => $schedule->shift_type,
|
||||
'need' => $schedule->needed_from_shift_type ? 'from shift type' : 'from room',
|
||||
'before' => $schedule->minutes_before,
|
||||
'after' => $schedule->minutes_after,
|
||||
]
|
||||
|
@ -146,6 +153,33 @@ class ImportSchedule extends BaseController
|
|||
return redirect('/admin/schedule/load/' . $schedule->id);
|
||||
}
|
||||
|
||||
protected function delete(ScheduleUrl $schedule): Response
|
||||
{
|
||||
foreach ($schedule->scheduleShifts as $scheduleShift) {
|
||||
// Only guid is needed here
|
||||
$event = new Event(
|
||||
$scheduleShift->guid,
|
||||
0,
|
||||
new Room(''),
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
Carbon::now(),
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
''
|
||||
);
|
||||
|
||||
$this->deleteEvent($event, $schedule);
|
||||
}
|
||||
$schedule->delete();
|
||||
|
||||
$this->addNotification('schedule.delete.success');
|
||||
return redirect('/admin/schedule');
|
||||
}
|
||||
|
||||
public function loadSchedule(Request $request): Response
|
||||
{
|
||||
try {
|
||||
|
@ -179,7 +213,7 @@ class ImportSchedule extends BaseController
|
|||
[
|
||||
'schedule_id' => $scheduleUrl->id,
|
||||
'schedule' => $schedule,
|
||||
'rooms' => [
|
||||
'locations' => [
|
||||
'add' => $newRooms,
|
||||
],
|
||||
'shifts' => [
|
||||
|
@ -218,15 +252,15 @@ class ImportSchedule extends BaseController
|
|||
$this->log('Started schedule "{name}" import', ['name' => $scheduleUrl->name]);
|
||||
|
||||
foreach ($newRooms as $room) {
|
||||
$this->createRoom($room);
|
||||
$this->createLocation($room);
|
||||
}
|
||||
|
||||
$rooms = $this->getAllRooms();
|
||||
$locations = $this->getAllLocations();
|
||||
foreach ($newEvents as $event) {
|
||||
$this->createEvent(
|
||||
$event,
|
||||
$shiftType,
|
||||
$rooms
|
||||
$locations
|
||||
->where('name', $event->getRoom()->getName())
|
||||
->first(),
|
||||
$scheduleUrl
|
||||
|
@ -237,15 +271,15 @@ class ImportSchedule extends BaseController
|
|||
$this->updateEvent(
|
||||
$event,
|
||||
$shiftType,
|
||||
$rooms
|
||||
$locations
|
||||
->where('name', $event->getRoom()->getName())
|
||||
->first()
|
||||
->first(),
|
||||
$scheduleUrl
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($deleteEvents as $event) {
|
||||
$this->fireDeleteShiftEntryEvents($event);
|
||||
$this->deleteEvent($event);
|
||||
$this->deleteEvent($event, $scheduleUrl);
|
||||
}
|
||||
|
||||
$scheduleUrl->touch();
|
||||
|
@ -255,29 +289,30 @@ class ImportSchedule extends BaseController
|
|||
return redirect($this->url, 303);
|
||||
}
|
||||
|
||||
protected function createRoom(Room $room): void
|
||||
protected function createLocation(Room $room): void
|
||||
{
|
||||
$roomModel = new RoomModel();
|
||||
$roomModel->name = $room->getName();
|
||||
$roomModel->save();
|
||||
$location = new Location();
|
||||
$location->name = $room->getName();
|
||||
$location->save();
|
||||
|
||||
$this->log('Created schedule room "{room}"', ['room' => $room->getName()]);
|
||||
$this->log('Created schedule location "{location}"', ['location' => $room->getName()]);
|
||||
}
|
||||
|
||||
protected function fireDeleteShiftEntryEvents(Event $event): void
|
||||
protected function fireDeleteShiftEntryEvents(Event $event, ScheduleUrl $schedule): void
|
||||
{
|
||||
$shiftEntries = $this->db
|
||||
->table('shift_entries')
|
||||
->select([
|
||||
'shift_types.name', 'shifts.title', 'angel_types.name AS type', 'rooms.id AS room_id',
|
||||
'shift_types.name', 'shifts.title', 'angel_types.name AS type', 'locations.id AS location_id',
|
||||
'shifts.start', 'shifts.end', 'shift_entries.user_id', 'shift_entries.freeloaded',
|
||||
])
|
||||
->join('shifts', 'shifts.id', 'shift_entries.shift_id')
|
||||
->join('schedule_shift', 'shifts.id', 'schedule_shift.shift_id')
|
||||
->join('rooms', 'rooms.id', 'shifts.room_id')
|
||||
->join('locations', 'locations.id', 'shifts.location_id')
|
||||
->join('angel_types', 'angel_types.id', 'shift_entries.angel_type_id')
|
||||
->join('shift_types', 'shift_types.id', 'shifts.shift_type_id')
|
||||
->where('schedule_shift.guid', $event->getGuid())
|
||||
->where('schedule_shift.schedule_id', $schedule->id)
|
||||
->get();
|
||||
|
||||
foreach ($shiftEntries as $shiftEntry) {
|
||||
|
@ -288,13 +323,13 @@ class ImportSchedule extends BaseController
|
|||
'name' => $shiftEntry->name,
|
||||
'title' => $shiftEntry->title,
|
||||
'type' => $shiftEntry->type,
|
||||
'room' => RoomModel::find($shiftEntry->room_id),
|
||||
'location' => Location::find($shiftEntry->location_id),
|
||||
'freeloaded' => $shiftEntry->freeloaded,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function createEvent(Event $event, int $shiftTypeId, RoomModel $room, ScheduleUrl $scheduleUrl): void
|
||||
protected function createEvent(Event $event, int $shiftTypeId, Location $location, ScheduleUrl $scheduleUrl): void
|
||||
{
|
||||
$user = auth()->user();
|
||||
$eventTimeZone = Carbon::now()->timezone;
|
||||
|
@ -304,7 +339,7 @@ class ImportSchedule extends BaseController
|
|||
$shift->shift_type_id = $shiftTypeId;
|
||||
$shift->start = $event->getDate()->copy()->timezone($eventTimeZone);
|
||||
$shift->end = $event->getEndDate()->copy()->timezone($eventTimeZone);
|
||||
$shift->room()->associate($room);
|
||||
$shift->location()->associate($location);
|
||||
$shift->url = $event->getUrl() ?? '';
|
||||
$shift->transaction_id = Uuid::uuidBy($scheduleUrl->id, '5c4ed01e');
|
||||
$shift->createdBy()->associate($user);
|
||||
|
@ -316,68 +351,81 @@ class ImportSchedule extends BaseController
|
|||
$scheduleShift->save();
|
||||
|
||||
$this->log(
|
||||
'Created schedule shift "{shift}" in "{room}" ({from} {to}, {guid})',
|
||||
'Created schedule shift "{shift}" in "{location}" ({from} {to}, {guid})',
|
||||
[
|
||||
'shift' => $shift->title,
|
||||
'room' => $shift->room->name,
|
||||
'from' => $shift->start->format(DateTimeInterface::RFC3339),
|
||||
'to' => $shift->end->format(DateTimeInterface::RFC3339),
|
||||
'guid' => $scheduleShift->guid,
|
||||
'shift' => $shift->title,
|
||||
'location' => $shift->location->name,
|
||||
'from' => $shift->start->format(DateTimeInterface::RFC3339),
|
||||
'to' => $shift->end->format(DateTimeInterface::RFC3339),
|
||||
'guid' => $scheduleShift->guid,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function updateEvent(Event $event, int $shiftTypeId, RoomModel $room): void
|
||||
protected function updateEvent(Event $event, int $shiftTypeId, Location $location, ScheduleUrl $schedule): void
|
||||
{
|
||||
$user = auth()->user();
|
||||
$eventTimeZone = Carbon::now()->timezone;
|
||||
|
||||
/** @var ScheduleShift $scheduleShift */
|
||||
$scheduleShift = ScheduleShift::whereGuid($event->getGuid())->first();
|
||||
$scheduleShift = ScheduleShift::whereGuid($event->getGuid())->where('schedule_id', $schedule->id)->first();
|
||||
$shift = $scheduleShift->shift;
|
||||
$oldShift = Shift::find($shift->id);
|
||||
$shift->title = $event->getTitle();
|
||||
$shift->shift_type_id = $shiftTypeId;
|
||||
$shift->start = $event->getDate()->copy()->timezone($eventTimeZone);
|
||||
$shift->end = $event->getEndDate()->copy()->timezone($eventTimeZone);
|
||||
$shift->room()->associate($room);
|
||||
$shift->location()->associate($location);
|
||||
$shift->url = $event->getUrl() ?? '';
|
||||
$shift->updatedBy()->associate($user);
|
||||
$shift->save();
|
||||
|
||||
$this->fireUpdateShiftUpdateEvent($oldShift, $shift);
|
||||
|
||||
$this->log(
|
||||
'Updated schedule shift "{shift}" in "{room}" ({from} {to}, {guid})',
|
||||
'Updated schedule shift "{shift}" in "{location}" ({from} {to}, {guid})',
|
||||
[
|
||||
'shift' => $shift->title,
|
||||
'room' => $shift->room->name,
|
||||
'from' => $shift->start->format(DateTimeInterface::RFC3339),
|
||||
'to' => $shift->end->format(DateTimeInterface::RFC3339),
|
||||
'guid' => $scheduleShift->guid,
|
||||
'shift' => $shift->title,
|
||||
'location' => $shift->location->name,
|
||||
'from' => $shift->start->format(DateTimeInterface::RFC3339),
|
||||
'to' => $shift->end->format(DateTimeInterface::RFC3339),
|
||||
'guid' => $scheduleShift->guid,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function deleteEvent(Event $event): void
|
||||
protected function deleteEvent(Event $event, ScheduleUrl $schedule): void
|
||||
{
|
||||
/** @var ScheduleShift $scheduleShift */
|
||||
$scheduleShift = ScheduleShift::whereGuid($event->getGuid())->first();
|
||||
$scheduleShift = ScheduleShift::whereGuid($event->getGuid())->where('schedule_id', $schedule->id)->first();
|
||||
$shift = $scheduleShift->shift;
|
||||
$shift->delete();
|
||||
|
||||
$this->fireDeleteShiftEntryEvents($event, $schedule);
|
||||
|
||||
$this->log(
|
||||
'Deleted schedule shift "{shift}" in {room} ({from} {to}, {guid})',
|
||||
'Deleted schedule shift "{shift}" in {location} ({from} {to}, {guid})',
|
||||
[
|
||||
'shift' => $shift->title,
|
||||
'room' => $shift->room->name,
|
||||
'from' => $shift->start->format(DateTimeInterface::RFC3339),
|
||||
'to' => $shift->end->format(DateTimeInterface::RFC3339),
|
||||
'guid' => $scheduleShift->guid,
|
||||
'shift' => $shift->title,
|
||||
'location' => $shift->location->name,
|
||||
'from' => $shift->start->format(DateTimeInterface::RFC3339),
|
||||
'to' => $shift->end->format(DateTimeInterface::RFC3339),
|
||||
'guid' => $scheduleShift->guid,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
protected function fireUpdateShiftUpdateEvent(Shift $oldShift, Shift $newShift): void
|
||||
{
|
||||
event('shift.updating', [
|
||||
'shift' => $newShift,
|
||||
'oldShift' => $oldShift,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return Event[]|Room[]|RoomModel[]
|
||||
* @return Event[]|Room[]|Location[]
|
||||
* @throws ErrorException
|
||||
*/
|
||||
protected function getScheduleData(Request $request)
|
||||
|
@ -420,10 +468,10 @@ class ImportSchedule extends BaseController
|
|||
protected function newRooms(array $scheduleRooms): array
|
||||
{
|
||||
$newRooms = [];
|
||||
$allRooms = $this->getAllRooms();
|
||||
$allLocations = $this->getAllLocations();
|
||||
|
||||
foreach ($scheduleRooms as $room) {
|
||||
if ($allRooms->where('name', $room->getName())->count()) {
|
||||
if ($allLocations->where('name', $room->getName())->count()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -456,7 +504,7 @@ class ImportSchedule extends BaseController
|
|||
$scheduleEvents = [];
|
||||
/** @var Event[] $deleteEvents */
|
||||
$deleteEvents = [];
|
||||
$rooms = $this->getAllRooms();
|
||||
$locations = $this->getAllLocations();
|
||||
$eventTimeZone = Carbon::now()->timezone;
|
||||
|
||||
foreach ($schedule->getDay() as $day) {
|
||||
|
@ -477,19 +525,19 @@ class ImportSchedule extends BaseController
|
|||
|
||||
$scheduleEventsGuidList = array_keys($scheduleEvents);
|
||||
$existingShifts = $this->getScheduleShiftsByGuid($scheduleUrl, $scheduleEventsGuidList);
|
||||
foreach ($existingShifts as $shift) {
|
||||
$guid = $shift->guid;
|
||||
foreach ($existingShifts as $scheduleShift) {
|
||||
$guid = $scheduleShift->guid;
|
||||
/** @var Shift $shift */
|
||||
$shift = Shift::with('room')->find($shift->shift_id);
|
||||
$shift = Shift::with('location')->find($scheduleShift->shift_id);
|
||||
$event = $scheduleEvents[$guid];
|
||||
$room = $rooms->where('name', $event->getRoom()->getName())->first();
|
||||
$location = $locations->where('name', $event->getRoom()->getName())->first();
|
||||
|
||||
if (
|
||||
$shift->title != $event->getTitle()
|
||||
|| $shift->shift_type_id != $shiftType
|
||||
|| $shift->start != $event->getDate()
|
||||
|| $shift->end != $event->getEndDate()
|
||||
|| $shift->room_id != ($room->id ?? '')
|
||||
|| $shift->location_id != ($location->id ?? '')
|
||||
|| $shift->url != ($event->getUrl() ?? '')
|
||||
) {
|
||||
$changeEvents[$guid] = $event;
|
||||
|
@ -503,8 +551,8 @@ class ImportSchedule extends BaseController
|
|||
}
|
||||
|
||||
$scheduleShifts = $this->getScheduleShiftsWhereNotGuid($scheduleUrl, $scheduleEventsGuidList);
|
||||
foreach ($scheduleShifts as $shift) {
|
||||
$event = $this->eventFromScheduleShift($shift);
|
||||
foreach ($scheduleShifts as $scheduleShift) {
|
||||
$event = $this->eventFromScheduleShift($scheduleShift);
|
||||
$deleteEvents[$event->getGuid()] = $event;
|
||||
}
|
||||
|
||||
|
@ -513,14 +561,13 @@ class ImportSchedule extends BaseController
|
|||
|
||||
protected function eventFromScheduleShift(ScheduleShift $scheduleShift): Event
|
||||
{
|
||||
/** @var Shift $shift */
|
||||
$shift = Shift::with('room')->find($scheduleShift->shift_id);
|
||||
$shift = $scheduleShift->shift;
|
||||
$duration = $shift->start->diff($shift->end);
|
||||
|
||||
return new Event(
|
||||
$scheduleShift->guid,
|
||||
0,
|
||||
new Room($shift->room->name),
|
||||
new Room($shift->location->name),
|
||||
$shift->title,
|
||||
'',
|
||||
'n/a',
|
||||
|
@ -534,11 +581,11 @@ class ImportSchedule extends BaseController
|
|||
}
|
||||
|
||||
/**
|
||||
* @return RoomModel[]|Collection
|
||||
* @return Location[]|Collection
|
||||
*/
|
||||
protected function getAllRooms(): Collection
|
||||
protected function getAllLocations(): Collection
|
||||
{
|
||||
return RoomModel::all();
|
||||
return Location::all();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,7 +8,7 @@ use Engelsystem\Models\User\User;
|
|||
*/
|
||||
function myshifts_title()
|
||||
{
|
||||
return __('My shifts');
|
||||
return __('profile.my-shifts');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,23 +35,24 @@ function user_myshifts()
|
|||
$shifts_user = User::find($shift_entry_id);
|
||||
if ($request->has('reset')) {
|
||||
if ($request->input('reset') == 'ack') {
|
||||
User_reset_api_key($user);
|
||||
auth()->resetApiKey($user);
|
||||
engelsystem_log(sprintf('API key resetted (%s).', User_Nick_render($user, true)));
|
||||
success(__('Key changed.'));
|
||||
throw_redirect(page_link_to('users', ['action' => 'view', 'user_id' => $shifts_user->id]));
|
||||
throw_redirect(url('/users', ['action' => 'view', 'user_id' => $shifts_user->id]));
|
||||
}
|
||||
return page_with_title(__('Reset API key'), [
|
||||
error(
|
||||
__('If you reset the key, the url to your iCal- and JSON-export and your atom/rss feed changes! You have to update it in every application using one of these exports.'),
|
||||
true
|
||||
),
|
||||
button(page_link_to('user_myshifts', ['reset' => 'ack']), __('Continue'), 'btn-danger'),
|
||||
button(url('/user-myshifts', ['reset' => 'ack']), __('Continue'), 'btn-danger'),
|
||||
]);
|
||||
} elseif ($request->has('edit') && preg_match('/^\d+$/', $request->input('edit'))) {
|
||||
$shift_entry_id = $request->input('edit');
|
||||
/** @var ShiftEntry $shiftEntry */
|
||||
$shiftEntry = ShiftEntry::where('id', $shift_entry_id)
|
||||
->where('user_id', $shifts_user->id)
|
||||
->with(['shift', 'shift.shiftType', 'shift.room', 'user'])
|
||||
->with(['shift', 'shift.shiftType', 'shift.location', 'user'])
|
||||
->first();
|
||||
if (!empty($shiftEntry)) {
|
||||
$shift = $shiftEntry->shift;
|
||||
|
@ -90,14 +91,14 @@ function user_myshifts()
|
|||
. '. Freeloaded: ' . ($freeloaded ? 'YES Comment: ' . $freeloaded_comment : 'NO')
|
||||
);
|
||||
success(__('Shift saved.'));
|
||||
throw_redirect(page_link_to('users', ['action' => 'view', 'user_id' => $shifts_user->id]));
|
||||
throw_redirect(url('/users', ['action' => 'view', 'user_id' => $shifts_user->id]));
|
||||
}
|
||||
}
|
||||
|
||||
return ShiftEntry_edit_view(
|
||||
$shifts_user,
|
||||
$shift->start->format(__('Y-m-d H:i')) . ', ' . shift_length($shift),
|
||||
$shift->room->name,
|
||||
$shift->start->format(__('general.datetime')) . ', ' . shift_length($shift),
|
||||
$shift->location->name,
|
||||
$shift->shiftType->name,
|
||||
$shiftEntry->angelType->name,
|
||||
$shiftEntry->user_comment,
|
||||
|
@ -106,10 +107,10 @@ function user_myshifts()
|
|||
auth()->can('user_shifts_admin')
|
||||
);
|
||||
} else {
|
||||
throw_redirect(page_link_to('user_myshifts'));
|
||||
throw_redirect(url('/user-myshifts'));
|
||||
}
|
||||
}
|
||||
|
||||
throw_redirect(page_link_to('users', ['action' => 'view', 'user_id' => $shifts_user->id]));
|
||||
throw_redirect(url('/users', ['action' => 'view', 'user_id' => $shifts_user->id]));
|
||||
return '';
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use Engelsystem\Database\Db;
|
||||
use Engelsystem\Helpers\Carbon;
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\UserAngelType;
|
||||
|
@ -34,7 +34,7 @@ function user_shifts()
|
|||
$request = request();
|
||||
|
||||
if (auth()->user()->isFreeloader()) {
|
||||
throw_redirect(page_link_to('user_myshifts'));
|
||||
throw_redirect(url('/user-myshifts'));
|
||||
}
|
||||
|
||||
if ($request->has('edit_shift')) {
|
||||
|
@ -107,40 +107,42 @@ function update_ShiftsFilter(ShiftsFilter $shiftsFilter, $user_shifts_admin, $da
|
|||
{
|
||||
$shiftsFilter->setUserShiftsAdmin($user_shifts_admin);
|
||||
$shiftsFilter->setFilled(check_request_int_array('filled', $shiftsFilter->getFilled()));
|
||||
$shiftsFilter->setRooms(check_request_int_array('rooms', $shiftsFilter->getRooms()));
|
||||
$shiftsFilter->setLocations(check_request_int_array('locations', $shiftsFilter->getLocations()));
|
||||
$shiftsFilter->setTypes(check_request_int_array('types', $shiftsFilter->getTypes()));
|
||||
update_ShiftsFilter_timerange($shiftsFilter, $days);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Room[]|Collection
|
||||
* @return Location[]|Collection
|
||||
*/
|
||||
function load_rooms(bool $onlyWithActiveShifts = false)
|
||||
function load_locations(bool $onlyWithActiveShifts = false)
|
||||
{
|
||||
$rooms = Room::orderBy('name');
|
||||
$locations = Location::orderBy('name');
|
||||
|
||||
if ($onlyWithActiveShifts) {
|
||||
$roomIdsFromAngelType = NeededAngelType::query()
|
||||
->whereNotNull('room_id')
|
||||
->select('room_id');
|
||||
$locationIdsFromAngelType = NeededAngelType::query()
|
||||
->whereNotNull('location_id')
|
||||
->select('location_id');
|
||||
|
||||
$roomIdsFromShift = Shift::query()
|
||||
$locationIdsFromShift = Shift::query()
|
||||
->leftJoin('needed_angel_types', 'shifts.id', 'needed_angel_types.shift_id')
|
||||
->whereNotNull('needed_angel_types.shift_id')
|
||||
->select('shifts.room_id');
|
||||
->leftJoin('needed_angel_types AS nast', 'shifts.shift_type_id', 'nast.shift_type_id')
|
||||
->whereNotNull('needed_angel_types.id')
|
||||
->orWhereNotNull('nast.id')
|
||||
->select('shifts.location_id');
|
||||
|
||||
$rooms->whereIn('id', $roomIdsFromAngelType)
|
||||
->orWhereIn('id', $roomIdsFromShift);
|
||||
$locations->whereIn('id', $locationIdsFromAngelType)
|
||||
->orWhereIn('id', $locationIdsFromShift);
|
||||
}
|
||||
|
||||
$rooms = $rooms->get();
|
||||
$locations = $locations->get();
|
||||
|
||||
if ($rooms->isEmpty()) {
|
||||
error(__('The administration has not configured any rooms yet.'));
|
||||
throw_redirect(page_link_to('/'));
|
||||
if ($locations->isEmpty()) {
|
||||
error(__('The administration has not configured any locations yet.'));
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
return $rooms;
|
||||
return $locations;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,7 +164,7 @@ function load_days()
|
|||
error(__('The administration has not configured any shifts yet.'));
|
||||
// Do not try to redirect to the current page
|
||||
if (config('home_site') != 'user_shifts') {
|
||||
throw_redirect(page_link_to('/'));
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
}
|
||||
return $days;
|
||||
|
@ -174,10 +176,11 @@ function load_days()
|
|||
function load_types()
|
||||
{
|
||||
$user = auth()->user();
|
||||
$isShico = auth()->can('admin_shifts');
|
||||
|
||||
if (!AngelType::count()) {
|
||||
error(__('The administration has not configured any angeltypes yet - or you are not subscribed to any angeltype.'));
|
||||
throw_redirect(page_link_to('/'));
|
||||
throw_redirect(url('/'));
|
||||
}
|
||||
|
||||
$types = Db::select(
|
||||
|
@ -197,8 +200,11 @@ function load_types()
|
|||
ON (
|
||||
`user_angel_type`.`angel_type_id`=`angel_types`.`id`
|
||||
AND `user_angel_type`.`user_id`=?
|
||||
)
|
||||
ORDER BY `angel_types`.`name`
|
||||
)'
|
||||
. ($isShico ? '' :
|
||||
'WHERE angel_types.hide_on_shift_view = 0
|
||||
OR user_angel_type.user_id IS NOT NULL ') .
|
||||
'ORDER BY `angel_types`.`name`
|
||||
',
|
||||
[
|
||||
$user->id,
|
||||
|
@ -229,7 +235,7 @@ function view_user_shifts()
|
|||
|
||||
$session = session();
|
||||
$days = load_days();
|
||||
$rooms = load_rooms(true);
|
||||
$locations = load_locations(true);
|
||||
$types = load_types();
|
||||
$ownAngelTypes = [];
|
||||
|
||||
|
@ -246,8 +252,8 @@ function view_user_shifts()
|
|||
}
|
||||
|
||||
if (!$session->has('shifts-filter')) {
|
||||
$room_ids = $rooms->pluck('id')->toArray();
|
||||
$shiftsFilter = new ShiftsFilter(auth()->can('user_shifts_admin'), $room_ids, $ownAngelTypes);
|
||||
$location_ids = $locations->pluck('id')->toArray();
|
||||
$shiftsFilter = new ShiftsFilter(auth()->can('user_shifts_admin'), $location_ids, $ownAngelTypes);
|
||||
$session->set('shifts-filter', $shiftsFilter->sessionExport());
|
||||
}
|
||||
|
||||
|
@ -259,7 +265,7 @@ function view_user_shifts()
|
|||
$shiftCalendarRenderer = shiftCalendarRendererByShiftFilter($shiftsFilter);
|
||||
|
||||
if (empty($user->api_key)) {
|
||||
User_reset_api_key($user, false);
|
||||
auth()->resetApiKey($user);
|
||||
}
|
||||
|
||||
$filled = [
|
||||
|
@ -277,24 +283,29 @@ function view_user_shifts()
|
|||
$end_day = $shiftsFilter->getEnd()->format('Y-m-d');
|
||||
$end_time = $shiftsFilter->getEnd()->format('H:i');
|
||||
|
||||
$canSignUpForShifts = true;
|
||||
if (config('signup_requires_arrival') && !$user->state->arrived) {
|
||||
$canSignUpForShifts = false;
|
||||
info(render_user_arrived_hint());
|
||||
}
|
||||
|
||||
$formattedDays = collect($days)->map(function ($value) {
|
||||
return Carbon::make($value)->format(__('Y-m-d'));
|
||||
return dateWithEventDay(Carbon::make($value)->format('Y-m-d'));
|
||||
})->toArray();
|
||||
|
||||
$link = button(url('/admin-shifts'), icon('plus-lg'), 'add');
|
||||
|
||||
return page([
|
||||
div('col-md-12', [
|
||||
msg(),
|
||||
view(__DIR__ . '/../../resources/views/pages/user-shifts.html', [
|
||||
'title' => shifts_title(),
|
||||
'room_select' => make_select(
|
||||
$rooms,
|
||||
$shiftsFilter->getRooms(),
|
||||
'rooms',
|
||||
icon('pin-map-fill') . __('Rooms')
|
||||
'add_link' => auth()->can('admin_shifts') ? $link : '',
|
||||
'location_select' => make_select(
|
||||
$locations,
|
||||
$shiftsFilter->getLocations(),
|
||||
'locations',
|
||||
icon('pin-map-fill') . __('Locations')
|
||||
),
|
||||
'start_select' => html_select_key(
|
||||
'start_day',
|
||||
|
@ -314,7 +325,10 @@ function view_user_shifts()
|
|||
$types,
|
||||
$shiftsFilter->getTypes(),
|
||||
'types',
|
||||
icon('person-lines-fill') . __('Angeltypes') . '<sup>1</sup>',
|
||||
icon('person-lines-fill') . __('angeltypes.angeltypes')
|
||||
. ' <small><span class="bi bi-info-circle-fill text-info" data-bs-toggle="tooltip" title="'
|
||||
. __('The tasks shown here are influenced by the angeltypes you joined already!')
|
||||
. '"></span></small>',
|
||||
$ownAngelTypes
|
||||
),
|
||||
'filled_select' => make_select(
|
||||
|
@ -323,12 +337,6 @@ function view_user_shifts()
|
|||
'filled',
|
||||
icon('person-fill-slash') . __('Occupancy')
|
||||
),
|
||||
'task_notice' =>
|
||||
'<sup>1</sup>'
|
||||
. __('The tasks shown here are influenced by the angeltypes you joined already!')
|
||||
. ' <a href="' . url('/angeltypes/about') . '">'
|
||||
. __('Description of the jobs.')
|
||||
. '</a>',
|
||||
'shifts_table' => msg() . $shiftCalendarRenderer->render(),
|
||||
'ical_text' => div('mt-3', ical_hint()),
|
||||
'filter' => __('Filter'),
|
||||
|
@ -340,7 +348,11 @@ function view_user_shifts()
|
|||
'set_last_4h' => __('last 4h'),
|
||||
'set_next_4h' => __('next 4h'),
|
||||
'set_next_8h' => __('next 8h'),
|
||||
'buttons' => button(
|
||||
'random' => auth()->can('user_shifts') && $canSignUpForShifts ? button(
|
||||
url('/shifts/random'),
|
||||
icon('dice-4-fill') . __('shifts.random')
|
||||
) : '',
|
||||
'dashboard' => button(
|
||||
public_dashboard_link(),
|
||||
icon('speedometer2') . __('Public Dashboard')
|
||||
),
|
||||
|
@ -364,9 +376,9 @@ function ical_hint()
|
|||
return heading(__('iCal export and API') . ' ' . button_help('user/ical'), 2)
|
||||
. '<p>' . sprintf(
|
||||
__('Export your own shifts. <a href="%s">iCal format</a> or <a href="%s">JSON format</a> available (please keep secret, otherwise <a href="%s">reset the api key</a>).'),
|
||||
page_link_to('ical', ['key' => $user->api_key]),
|
||||
page_link_to('shifts_json_export', ['key' => $user->api_key]),
|
||||
page_link_to('user_myshifts', ['reset' => 1])
|
||||
url('/ical', ['key' => $user->api_key]),
|
||||
url('/shifts-json-export', ['key' => $user->api_key]),
|
||||
url('/user-myshifts', ['reset' => 1])
|
||||
)
|
||||
. ' <button class="btn btn-sm btn-danger" type="button"
|
||||
data-bs-toggle="collapse" data-bs-target="#collapseApiKey"
|
||||
|
@ -377,15 +389,6 @@ function ical_hint()
|
|||
. '<p id="collapseApiKey" class="collapse"><code>' . $user->api_key . '</code></p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
* @return array
|
||||
*/
|
||||
function get_ids_from_array($array)
|
||||
{
|
||||
return $array['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $items
|
||||
* @param array $selected
|
||||
|
@ -418,7 +421,7 @@ function make_select($items, $selected, $name, $title = null, $ownSelect = [])
|
|||
$htmlItems[] = '<div class="form-check">'
|
||||
. '<input class="form-check-input" type="checkbox" id="' . $id . '" name="' . $name . '[]" value="' . $i['id'] . '" '
|
||||
. (in_array($i['id'], $selected) ? ' checked="checked"' : '')
|
||||
. '><label class="form-check-label" for="' . $id . '">' . $i['name'] . '</label>'
|
||||
. '><label class="form-check-label" for="' . $id . '">' . htmlspecialchars($i['name']) . '</label>'
|
||||
. (!isset($i['enabled']) || $i['enabled'] ? '' : icon('mortarboard-fill'))
|
||||
. '</div>';
|
||||
}
|
||||
|
|
|
@ -24,52 +24,28 @@ function form_hidden($name, $value)
|
|||
* @param array $data_attributes
|
||||
* @return string
|
||||
*/
|
||||
function form_spinner(string $name, string $label, int $value, array $data_attributes = [])
|
||||
function form_spinner(string $name, string $label, int $value, array $data_attributes = [], bool $isDisabled = false)
|
||||
{
|
||||
$id = 'spinner-' . $name;
|
||||
$attr = '';
|
||||
foreach ($data_attributes as $attr_key => $attr_value) {
|
||||
$attr .= ' data-' . $attr_key . '="' . $attr_value . '"';
|
||||
}
|
||||
$disabled = $isDisabled ? ' disabled' : '';
|
||||
|
||||
return form_element($label, '
|
||||
<div class="input-group">
|
||||
<input id="' . $id . '" class="form-control" type="number" min="0" step="1" name="' . $name . '" value="' . $value . '"' . $attr . ' />
|
||||
<button class="btn btn-secondary spinner-down" type="button" data-input-id="' . $id . '"' . $attr . '>
|
||||
<input id="' . $id . '" class="form-control" type="number" min="0" step="1" name="' . $name . '" value="' . $value . '"' . $attr . $disabled . '/>
|
||||
<button class="btn btn-secondary spinner-down' . $disabled . '" type="button" data-input-id="' . $id . '"' . $attr . '>
|
||||
' . icon('dash-lg') . '
|
||||
</button>
|
||||
<button class="btn btn-secondary spinner-up" type="button" data-input-id="' . $id . '"' . $attr . '>
|
||||
<button class="btn btn-secondary spinner-up' . $disabled . '" type="button" data-input-id="' . $id . '"' . $attr . '>
|
||||
' . icon('plus-lg') . '
|
||||
</button>
|
||||
</div>
|
||||
', $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a bootstrap datepicker
|
||||
*
|
||||
* @param string $name Name of the parameter
|
||||
* @param string $label Label
|
||||
* @param int|Carbon $value Unix Timestamp
|
||||
* @param string $start_date Earliest possible date
|
||||
* @param string $end_date
|
||||
* @return string HTML
|
||||
*/
|
||||
function form_date($name, $label, $value, $start_date = '', $end_date = '')
|
||||
{
|
||||
$dom_id = $name . '-date';
|
||||
$value = ($value instanceof Carbon) ? $value->getTimestamp() : $value;
|
||||
$value = is_numeric($value) ? date('Y-m-d', $value) : '';
|
||||
$start_date = is_numeric($start_date) ? date('Y-m-d', $start_date) : '';
|
||||
$end_date = is_numeric($end_date) ? date('Y-m-d', $end_date) : '';
|
||||
|
||||
return form_element(
|
||||
$label,
|
||||
'<input class="form-control" id="' . $dom_id . '" type="date" placeholder="YYYY-MM-DD" pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}" min="' . $start_date . '" max="' . $end_date . '" name="' . $name . '" value="' . htmlspecialchars((string) $value) . '" autocomplete="off">',
|
||||
$dom_id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a bootstrap datepicker
|
||||
*
|
||||
|
@ -93,24 +69,6 @@ function form_datetime(string $name, string $label, $value)
|
|||
', $dom_id, $name, htmlspecialchars($value ? $value->format('Y-m-d H:i') : '')), $dom_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendert eine Liste von Checkboxen für ein Formular
|
||||
*
|
||||
* @param string $name Die Namen der Checkboxen werden aus name_key gebildet
|
||||
* @param string $label Die Beschriftung der Liste
|
||||
* @param array $items Array mit den einzelnen Checkboxen
|
||||
* @param array $selected Array mit den Keys, die ausgewählt sind
|
||||
* @return string
|
||||
*/
|
||||
function form_checkboxes($name, $label, $items, $selected)
|
||||
{
|
||||
$html = form_element($label, '');
|
||||
foreach ($items as $key => $item) {
|
||||
$html .= form_checkbox($name . '_' . $key, $item, in_array($key, $selected));
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendert eine Checkbox
|
||||
*
|
||||
|
@ -128,14 +86,15 @@ function form_checkbox($name, $label, $selected, $value = 'checked', $html_id =
|
|||
}
|
||||
|
||||
return '<div class="form-check">'
|
||||
. '<input class="form-check-input" type="checkbox" id="' . $html_id . '" name="' . $name . '" value="' . htmlspecialchars((string) $value) . '" '
|
||||
. '<input class="form-check-input" type="checkbox" id="' . $html_id . '" '
|
||||
. 'name="' . htmlspecialchars($name) . '" value="' . $value . '" '
|
||||
. ($selected ? ' checked="checked"' : '') . ' /><label class="form-check-label" for="' . $html_id . '">'
|
||||
. $label
|
||||
. '</label></div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendert einen Radio
|
||||
* Renders a radio button
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $label
|
||||
|
@ -184,9 +143,9 @@ function form_info($label, $text = '')
|
|||
* @param string $buttonType
|
||||
* @return string
|
||||
*/
|
||||
function form_submit($name, $label, $class = '', $wrapForm = true, $buttonType = 'primary')
|
||||
function form_submit($name, $label, $class = '', $wrapForm = true, $buttonType = 'primary', $title = '')
|
||||
{
|
||||
$button = '<button class="btn btn-' . $buttonType . ($class ? ' ' . $class : '') . '" type="submit" name="' . $name . '">'
|
||||
$button = '<button class="btn btn-' . $buttonType . ($class ? ' ' . $class : '') . '" type="submit" name="' . $name . '" title="' . $title . '">'
|
||||
. $label
|
||||
. '</button>';
|
||||
|
||||
|
@ -232,67 +191,6 @@ function form_text($name, $label, $value, $disabled = false, $maxlength = null,
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a text input with placeholder instead of label.
|
||||
*
|
||||
* @param string $name Input name
|
||||
* @param string $placeholder Placeholder
|
||||
* @param string $value The value
|
||||
* @param boolean $disabled Is the field enabled?
|
||||
* @return string
|
||||
*/
|
||||
function form_text_placeholder($name, $placeholder, $value, $disabled = false)
|
||||
{
|
||||
$disabled = $disabled ? ' disabled="disabled"' : '';
|
||||
return form_element(
|
||||
'',
|
||||
'<input class="form-control" id="form_' . $name . '" type="text" name="' . $name
|
||||
. '" value="' . htmlspecialchars((string) $value) . '" placeholder="' . $placeholder
|
||||
. '" ' . $disabled . '/>'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendert ein Formular-Emailfeld
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $label
|
||||
* @param string $value
|
||||
* @param bool $disabled
|
||||
* @param string|null $autocomplete
|
||||
* @param int|null $maxlength
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function form_email($name, $label, $value, $disabled = false, $autocomplete = null, $maxlength = null)
|
||||
{
|
||||
$disabled = $disabled ? ' disabled="disabled"' : '';
|
||||
$autocomplete = $autocomplete ? ' autocomplete="' . $autocomplete . '"' : '';
|
||||
$maxlength = $maxlength ? ' maxlength=' . (int) $maxlength : '';
|
||||
return form_element(
|
||||
$label,
|
||||
'<input class="form-control" id="form_' . $name . '" type="email" name="' . $name . '" value="'
|
||||
. htmlspecialchars((string) $value) . '" ' . $disabled . $autocomplete . $maxlength . '/>',
|
||||
'form_' . $name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendert ein Formular-Dateifeld
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $label
|
||||
* @return string
|
||||
*/
|
||||
function form_file($name, $label)
|
||||
{
|
||||
return form_element(
|
||||
$label,
|
||||
sprintf('<input id="form_%1$s" type="file" name="%1$s" />', $name),
|
||||
'form_' . $name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendert ein Formular-Passwortfeld
|
||||
*
|
||||
|
@ -308,7 +206,7 @@ function form_password($name, $label, $autocomplete, $disabled = false)
|
|||
return form_element(
|
||||
$label,
|
||||
sprintf(
|
||||
'<input class="form-control" id="form_%1$s" type="password" name="%1$s" minlength="%2$s" value="" autocomplete="%3$s"%4$s/>',
|
||||
'<input class="form-control" id="form_%1$s" type="password" name="%1$s" minlength="%2$s" value="" autocomplete="%3$s" %4$s>',
|
||||
$name,
|
||||
config('min_password_length'),
|
||||
$autocomplete,
|
||||
|
@ -318,25 +216,6 @@ function form_password($name, $label, $autocomplete, $disabled = false)
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a password input with placeholder instead of label.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $placeholder
|
||||
* @param bool $disabled
|
||||
* @return string
|
||||
*/
|
||||
function form_password_placeholder($name, $placeholder, $disabled = false)
|
||||
{
|
||||
$disabled = $disabled ? ' disabled="disabled"' : '';
|
||||
return form_element(
|
||||
'',
|
||||
'<input class="form-control" id="form_' . $name . '" type="password" name="'
|
||||
. $name . '" value="" placeholder="' . $placeholder . '" ' . $disabled . '/>',
|
||||
'form_' . $name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendert ein Formular-Textfeld
|
||||
*
|
||||
|
@ -406,14 +285,14 @@ function form_element($label, $input, $for = '', $class = '')
|
|||
*
|
||||
* @param string[] $elements
|
||||
* @param string $action
|
||||
* @param bool $inline
|
||||
* @param string $style
|
||||
* @return string
|
||||
*/
|
||||
function form($elements, $action = '', $inline = false, $btnGroup = false)
|
||||
function form($elements, $action = '', $style = '', $btnGroup = false)
|
||||
{
|
||||
return '<form action="' . $action . '" enctype="multipart/form-data" method="post"'
|
||||
. ($btnGroup ? ' class="btn-group"' : '')
|
||||
. ($inline ? ' style="float:left"' : '') . '>'
|
||||
. ($style ? ' style="' . $style . '"' : '') . '>'
|
||||
. join($elements)
|
||||
. form_csrf()
|
||||
. '</form>';
|
||||
|
@ -463,9 +342,13 @@ function html_select_key($dom_id, $name, $rows, $selected, $selectText = '')
|
|||
}
|
||||
foreach ($rows as $key => $row) {
|
||||
if (($key == $selected) || ($row === $selected)) {
|
||||
$html .= '<option value="' . $key . '" selected="selected">' . $row . '</option>';
|
||||
$html .= '<option value="' . htmlspecialchars($key) . '" selected="selected">'
|
||||
. htmlspecialchars($row)
|
||||
. '</option>';
|
||||
} else {
|
||||
$html .= '<option value="' . $key . '">' . $row . '</option>';
|
||||
$html .= '<option value="' . htmlspecialchars($key) . '">'
|
||||
. htmlspecialchars($row)
|
||||
. '</option>';
|
||||
}
|
||||
}
|
||||
$html .= '</select>';
|
||||
|
|
|
@ -1,20 +1,9 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\Models\Question;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\UserHintsRenderer;
|
||||
|
||||
/**
|
||||
* @param string $page
|
||||
* @param array $parameters get parameters
|
||||
* @return string
|
||||
*/
|
||||
function page_link_to($page = '', $parameters = [])
|
||||
{
|
||||
$page = str_replace('_', '-', $page);
|
||||
return url($page, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the user hints
|
||||
*
|
||||
|
@ -31,12 +20,17 @@ function header_render_hints()
|
|||
$hints_renderer->addHint(user_angeltypes_unconfirmed_hint());
|
||||
$hints_renderer->addHint(render_user_departure_date_hint());
|
||||
$hints_renderer->addHint(user_driver_license_required_hint());
|
||||
$hints_renderer->addHint(user_ifsg_certificate_required_hint());
|
||||
|
||||
// Important hints:
|
||||
$hints_renderer->addHint(render_user_freeloader_hint(), true);
|
||||
$hints_renderer->addHint(render_user_arrived_hint(), true);
|
||||
$hints_renderer->addHint(render_user_arrived_hint(true), true);
|
||||
$hints_renderer->addHint(render_user_pronoun_hint(), true);
|
||||
$hints_renderer->addHint(render_user_firstname_hint(), true);
|
||||
$hints_renderer->addHint(render_user_lastname_hint(), true);
|
||||
$hints_renderer->addHint(render_user_tshirt_hint(), true);
|
||||
$hints_renderer->addHint(render_user_dect_hint(), true);
|
||||
$hints_renderer->addHint(render_user_mobile_hint(), true);
|
||||
|
||||
return $hints_renderer->render();
|
||||
}
|
||||
|
@ -62,10 +56,10 @@ function make_navigation()
|
|||
$page = current_page();
|
||||
$menu = [];
|
||||
$pages = [
|
||||
'news' => __('News'),
|
||||
'meetings' => [__('Meetings'), 'user_meetings'],
|
||||
'news' => __('news.title'),
|
||||
'meetings' => [__('news.title.meetings'), 'user_meetings'],
|
||||
'user_shifts' => __('Shifts'),
|
||||
'angeltypes' => __('Angeltypes'),
|
||||
'angeltypes' => __('angeltypes.angeltypes'),
|
||||
'questions' => [__('Ask the Heaven'), 'question.add'],
|
||||
];
|
||||
|
||||
|
@ -75,23 +69,30 @@ function make_navigation()
|
|||
}
|
||||
|
||||
$title = ((array) $options)[0];
|
||||
$menu[] = toolbar_item_link(page_link_to($menu_page), '', $title, $menu_page == $page);
|
||||
$menu[] = toolbar_item_link(
|
||||
url(str_replace('_', '-', $menu_page)),
|
||||
'',
|
||||
$title,
|
||||
$menu_page == $page
|
||||
);
|
||||
}
|
||||
|
||||
$menu = make_room_navigation($menu);
|
||||
$menu = make_location_navigation($menu);
|
||||
|
||||
$admin_menu = [];
|
||||
$admin_pages = [
|
||||
// path => name
|
||||
// path => [name, permission]
|
||||
// Examples:
|
||||
// path => name,
|
||||
// path => [name, permission],
|
||||
|
||||
'admin_arrive' => 'Arrive angels',
|
||||
'admin_active' => 'Active angels',
|
||||
'users' => ['All Angels', 'admin_user'],
|
||||
'admin_free' => 'Free angels',
|
||||
'admin/questions' => ['Answer questions', 'question.edit'],
|
||||
'shifttypes' => 'Shifttypes',
|
||||
'admin/shifttypes' => ['shifttype.shifttypes', 'shifttypes'],
|
||||
'admin_shifts' => 'Create shifts',
|
||||
'admin/rooms' => ['room.rooms', 'admin_rooms'],
|
||||
'admin/locations' => ['location.locations', 'admin_locations'],
|
||||
'admin_groups' => 'Grouprights',
|
||||
'admin/schedule' => ['schedule.import', 'schedule.import'],
|
||||
'admin/logs' => ['log.log', 'admin_log'],
|
||||
|
@ -109,8 +110,8 @@ function make_navigation()
|
|||
|
||||
$title = ((array) $options)[0];
|
||||
$admin_menu[] = toolbar_dropdown_item(
|
||||
page_link_to($menu_page),
|
||||
__($title),
|
||||
url(str_replace('_', '-', $menu_page)),
|
||||
htmlspecialchars(__($title)),
|
||||
$menu_page == $page
|
||||
);
|
||||
}
|
||||
|
@ -141,31 +142,36 @@ function menu_is_allowed(string $page, $options)
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds room navigation to the given menu.
|
||||
* Adds location navigation to the given menu.
|
||||
*
|
||||
* @param string[] $menu Rendered menu
|
||||
* @return string[]
|
||||
*/
|
||||
function make_room_navigation($menu)
|
||||
function make_location_navigation($menu)
|
||||
{
|
||||
if (!auth()->can('view_rooms')) {
|
||||
if (!auth()->can('view_locations')) {
|
||||
return $menu;
|
||||
}
|
||||
|
||||
// Get a list of all rooms
|
||||
$rooms = Room::orderBy('name')->get();
|
||||
$room_menu = [];
|
||||
if (auth()->can('admin_rooms')) {
|
||||
$room_menu[] = toolbar_dropdown_item(page_link_to('admin/rooms'), __('Manage rooms'), false, 'list');
|
||||
// Get a list of all locations
|
||||
$locations = Location::orderBy('name')->get();
|
||||
$location_menu = [];
|
||||
if (auth()->can('admin_locations')) {
|
||||
$location_menu[] = toolbar_dropdown_item(
|
||||
url('/admin/locations'),
|
||||
__('Manage locations'),
|
||||
false,
|
||||
'list'
|
||||
);
|
||||
}
|
||||
if (count($room_menu) > 0) {
|
||||
$room_menu[] = toolbar_dropdown_item_divider();
|
||||
if (count($location_menu) > 0) {
|
||||
$location_menu[] = toolbar_dropdown_item_divider();
|
||||
}
|
||||
foreach ($rooms as $room) {
|
||||
$room_menu[] = toolbar_dropdown_item(room_link($room), $room->name, false, 'pin-map-fill');
|
||||
foreach ($locations as $location) {
|
||||
$location_menu[] = toolbar_dropdown_item(location_link($location), $location->name, false, 'pin-map-fill');
|
||||
}
|
||||
if (count($room_menu) > 0) {
|
||||
$menu[] = toolbar_dropdown(__('Rooms'), $room_menu);
|
||||
if (count($location_menu) > 0) {
|
||||
$menu[] = toolbar_dropdown(__('Locations'), $location_menu);
|
||||
}
|
||||
return $menu;
|
||||
}
|
||||
|
@ -209,7 +215,7 @@ function admin_new_questions()
|
|||
return null;
|
||||
}
|
||||
|
||||
return '<a href="' . page_link_to('/admin/questions') . '">'
|
||||
return '<a href="' . url('/admin/questions') . '">'
|
||||
. __('There are unanswered questions!')
|
||||
. '</a>';
|
||||
}
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
use Engelsystem\Helpers\Carbon;
|
||||
use Engelsystem\Http\Exceptions\HttpTemporaryRedirect;
|
||||
use Engelsystem\Models\BaseModel;
|
||||
use Engelsystem\ValidationResult;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Provide page/request helper functions
|
||||
|
@ -63,41 +61,6 @@ function throw_redirect($url)
|
|||
throw new HttpTemporaryRedirect($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Echoes given output and dies.
|
||||
*
|
||||
* @param string $output String to display
|
||||
*/
|
||||
function raw_output($output = '')
|
||||
{
|
||||
echo $output;
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for transforming list of entities into array for select boxes.
|
||||
*
|
||||
* @param array|Collection $data The data array
|
||||
* @param string $key_name name of the column to use as id/key
|
||||
* @param string $value_name name of the column to use as displayed value
|
||||
*
|
||||
* @return array|Collection
|
||||
*/
|
||||
function select_array($data, $key_name, $value_name)
|
||||
{
|
||||
if ($data instanceof Collection) {
|
||||
return $data->mapWithKeys(function (BaseModel $model) use ($key_name, $value_name) {
|
||||
return [$model->{$key_name} => $model->{$value_name}];
|
||||
});
|
||||
}
|
||||
|
||||
$return = [];
|
||||
foreach ($data as $value) {
|
||||
$return[$value[$key_name]] = $value[$value_name];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an int[] from given request param name.
|
||||
*
|
||||
|
@ -185,23 +148,6 @@ function strip_request_item($name, $default_value = null)
|
|||
return $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns REQUEST value or default value (null) if not set.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|null $default_value
|
||||
* @return mixed|null
|
||||
*/
|
||||
function strip_request_tags($name, $default_value = null)
|
||||
{
|
||||
$request = request();
|
||||
if ($request->has($name)) {
|
||||
return strip_tags($request->input($name));
|
||||
}
|
||||
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Testet, ob der angegebene REQUEST Wert ein Integer ist, bzw.
|
||||
* eine ID sein könnte.
|
||||
|
|
|
@ -72,17 +72,6 @@ function tabs($tabs, $selected = 0)
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display muted (grey) text.
|
||||
*
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
function mute($text)
|
||||
{
|
||||
return '<span class="text-muted">' . $text . '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a bootstrap label with given content and class.
|
||||
*
|
||||
|
@ -188,7 +177,7 @@ function toolbar_item_link($href, $icon, $label, $active = false)
|
|||
return '<li class="nav-item">'
|
||||
. '<a class="nav-link ' . ($active ? 'active" aria-current="page"' : '"') . ' href="' . $href . '">'
|
||||
. ($icon != '' ? '<span class="bi bi-' . $icon . '"></span> ' : '')
|
||||
. $label
|
||||
. htmlspecialchars($label)
|
||||
. '</a>'
|
||||
. '</li>';
|
||||
}
|
||||
|
@ -196,11 +185,11 @@ function toolbar_item_link($href, $icon, $label, $active = false)
|
|||
function toolbar_dropdown_item(string $href, string $label, bool $active, string $icon = null): string
|
||||
{
|
||||
return strtr(
|
||||
'<li><a class="dropdown-item{active}"{aria} href="{href}">{icon} {label}</a></li>',
|
||||
'<li><a class="dropdown-item{active}" {aria} href="{href}">{icon} {label}</a></li>',
|
||||
[
|
||||
'{href}' => $href,
|
||||
'{icon}' => $icon === null ? '' : '<i class="bi bi-' . $icon . '"></i>',
|
||||
'{label}' => $label,
|
||||
'{label}' => htmlspecialchars($label),
|
||||
'{active}' => $active ? ' active' : '',
|
||||
'{aria}' => $active ? ' aria-current="page"' : '',
|
||||
]
|
||||
|
@ -235,7 +224,7 @@ EOT;
|
|||
$template,
|
||||
[
|
||||
'{class}' => $active ? ' active' : '',
|
||||
'{label}' => $label,
|
||||
'{label}' => htmlspecialchars($label),
|
||||
'{submenu}' => join("\n", $submenu),
|
||||
]
|
||||
);
|
||||
|
@ -338,7 +327,7 @@ function render_table($columns, $rows, $data = true)
|
|||
$html .= '</tr></thead>';
|
||||
$html .= '<tbody>';
|
||||
foreach ($rows as $row) {
|
||||
$html .= '<tr>';
|
||||
$html .= '<tr' . (isset($row['row-class']) ? ' class="' . $row['row-class'] . '"' : '') . '>';
|
||||
foreach ($columns as $key => $column) {
|
||||
$value = ' ';
|
||||
if (isset($row[$key])) {
|
||||
|
@ -362,7 +351,7 @@ function render_table($columns, $rows, $data = true)
|
|||
* @param string $id
|
||||
* @return string
|
||||
*/
|
||||
function button($href, $label, $class = '', $id = '')
|
||||
function button($href, $label, $class = '', $id = '', $title = '')
|
||||
{
|
||||
if (!Str::contains(str_replace(['btn-sm', 'btn-xl'], '', $class), 'btn-')) {
|
||||
$class = 'btn-secondary' . ($class ? ' ' . $class : '');
|
||||
|
@ -370,7 +359,8 @@ function button($href, $label, $class = '', $id = '')
|
|||
|
||||
$idAttribute = $id ? 'id="' . $id . '"' : '';
|
||||
|
||||
return '<a ' . $idAttribute . ' href="' . $href . '" class="btn ' . $class . '">' . $label . '</a>';
|
||||
return '<a ' . $idAttribute . ' href="' . $href
|
||||
. '" class="btn ' . $class . '" title="' . $title . '">' . $label . '</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -396,9 +386,9 @@ function button_checkbox_selection($name, $label, $value)
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
function button_icon($href, $icon, $class = '')
|
||||
function button_icon($href, $icon, $class = '', $title = '')
|
||||
{
|
||||
return button($href, icon($icon), $class);
|
||||
return button($href, icon($icon), $class, '', $title);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,7 +26,7 @@ function AngelType_name_render(AngelType $angeltype, $plain = false)
|
|||
}
|
||||
|
||||
return '<a href="' . angeltype_link($angeltype->id) . '">'
|
||||
. ($angeltype->restricted ? icon('mortarboard-fill') : '') . $angeltype->name
|
||||
. ($angeltype->restricted ? icon('mortarboard-fill') : '') . htmlspecialchars($angeltype->name)
|
||||
. '</a>';
|
||||
}
|
||||
|
||||
|
@ -60,12 +60,15 @@ function AngelType_render_membership(AngelType $user_angeltype)
|
|||
*/
|
||||
function AngelType_delete_view(AngelType $angeltype)
|
||||
{
|
||||
return page_with_title(sprintf(__('Delete angeltype %s'), $angeltype->name), [
|
||||
$link = button($angeltype->id
|
||||
? url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id])
|
||||
: url('/angeltypes'), icon('chevron-left'), 'btn-sm', '', __('general.back'));
|
||||
return page_with_title($link . ' ' . sprintf(__('Delete angeltype %s'), htmlspecialchars($angeltype->name)), [
|
||||
info(sprintf(__('Do you want to delete angeltype %s?'), $angeltype->name), true),
|
||||
form([
|
||||
buttons([
|
||||
button(page_link_to('angeltypes'), icon('x-lg') . __('cancel')),
|
||||
form_submit('delete', icon('trash') . __('delete'), 'btn-danger', false),
|
||||
button(url('/angeltypes'), icon('x-lg') . __('form.cancel')),
|
||||
form_submit('delete', icon('trash'), 'btn-danger', false, 'primary', __('form.delete')),
|
||||
]),
|
||||
]),
|
||||
], true);
|
||||
|
@ -80,56 +83,96 @@ function AngelType_delete_view(AngelType $angeltype)
|
|||
*/
|
||||
function AngelType_edit_view(AngelType $angeltype, bool $supporter_mode)
|
||||
{
|
||||
return page_with_title(sprintf(__('Edit %s'), $angeltype->name), [
|
||||
buttons([
|
||||
button(page_link_to('angeltypes'), icon('person-lines-fill') . __('Angeltypes'), 'back'),
|
||||
]),
|
||||
msg(),
|
||||
form([
|
||||
$supporter_mode
|
||||
? form_info(__('Name'), $angeltype->name)
|
||||
: form_text('name', __('Name'), $angeltype->name),
|
||||
$supporter_mode
|
||||
? form_info(__('Requires introduction'), $angeltype->restricted ? __('Yes') : __('No'))
|
||||
: form_checkbox('restricted', __('Requires introduction'), $angeltype->restricted),
|
||||
form_info(
|
||||
'',
|
||||
__('Angel types which require introduction can only be used by an angel if enabled by a supporter (double opt-in).')
|
||||
),
|
||||
$supporter_mode
|
||||
? form_info(__('No Self Sign Up allowed'), $angeltype->no_self_signup ? __('Yes') : __('No'))
|
||||
: form_checkbox('no_self_signup', __('No Self Sign Up allowed'), $angeltype->no_self_signup),
|
||||
$supporter_mode ?
|
||||
$link = button($angeltype->id
|
||||
? url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id])
|
||||
: url('/angeltypes'), icon('chevron-left'), 'btn-sm', '', __('general.back'));
|
||||
return page_with_title(
|
||||
$link . ' ' . (
|
||||
$angeltype->id ?
|
||||
sprintf(__('Edit %s'), htmlspecialchars((string) $angeltype->name)) :
|
||||
__('Create angeltype')
|
||||
),
|
||||
[
|
||||
$angeltype->id ?
|
||||
buttons([
|
||||
button(url('/angeltypes'), icon('person-lines-fill') . __('angeltypes.angeltypes'), 'back'),
|
||||
]) : '',
|
||||
msg(),
|
||||
form([
|
||||
$supporter_mode
|
||||
? form_info(__('general.name'), htmlspecialchars($angeltype->name))
|
||||
: form_text('name', __('general.name'), $angeltype->name),
|
||||
$supporter_mode
|
||||
? form_info(__('angeltypes.restricted'), $angeltype->restricted ? __('Yes') : __('No'))
|
||||
: form_checkbox(
|
||||
'restricted',
|
||||
__('angeltypes.restricted') .
|
||||
' <span class="bi bi-info-circle-fill text-info" data-bs-toggle="tooltip" title="' .
|
||||
__('angeltypes.restricted.info') . '"></span>',
|
||||
$angeltype->restricted
|
||||
),
|
||||
$supporter_mode
|
||||
? form_info(__('shift.self_signup'), $angeltype->shift_self_signup ? __('Yes') : __('No'))
|
||||
: form_checkbox(
|
||||
'shift_self_signup',
|
||||
__('shift.self_signup') .
|
||||
' <span class="bi bi-info-circle-fill text-info" data-bs-toggle="tooltip" title="' .
|
||||
__('angeltypes.shift.self_signup.info') . '"></span>',
|
||||
$angeltype->shift_self_signup
|
||||
),
|
||||
$supporter_mode ?
|
||||
form_info(
|
||||
__('Requires driver license'),
|
||||
$angeltype->requires_driver_license
|
||||
? __('Yes')
|
||||
: __('No')
|
||||
) :
|
||||
form_checkbox(
|
||||
'requires_driver_license',
|
||||
__('Requires driver license'),
|
||||
$angeltype->requires_driver_license
|
||||
),
|
||||
$supporter_mode && config('ifsg_enabled') ?
|
||||
form_info(
|
||||
__('angeltype.ifsg.required'),
|
||||
$angeltype->requires_ifsg_certificate
|
||||
? __('Yes')
|
||||
: __('No')
|
||||
) :
|
||||
form_checkbox(
|
||||
'requires_ifsg_certificate',
|
||||
__('angeltype.ifsg.required'),
|
||||
$angeltype->requires_ifsg_certificate
|
||||
),
|
||||
$supporter_mode
|
||||
? form_info(__('Show on dashboard'), $angeltype->show_on_dashboard ? __('Yes') : __('No'))
|
||||
: form_checkbox('show_on_dashboard', __('Show on dashboard'), $angeltype->show_on_dashboard),
|
||||
$supporter_mode
|
||||
? form_info(__('Hide at Registration'), $angeltype->hide_register ? __('Yes') : __('No'))
|
||||
: form_checkbox('hide_register', __('Hide at Registration'), $angeltype->hide_register),
|
||||
$supporter_mode
|
||||
? form_info(__('angeltypes.hide_on_shift_view'), $angeltype->hide_on_shift_view ? __('Yes') : __('No'))
|
||||
: form_checkbox(
|
||||
'hide_on_shift_view',
|
||||
__('angeltypes.hide_on_shift_view') .
|
||||
' <span class="bi bi-info-circle-fill text-info" data-bs-toggle="tooltip" title="' .
|
||||
__('angeltypes.hide_on_shift_view.info') . '"></span>',
|
||||
$angeltype->hide_on_shift_view
|
||||
),
|
||||
form_textarea('description', __('general.description'), $angeltype->description),
|
||||
form_info('', __('Please use markdown for the description.')),
|
||||
heading(__('Contact'), 3),
|
||||
form_info(
|
||||
__('Requires driver license'),
|
||||
$angeltype->requires_driver_license
|
||||
? __('Yes')
|
||||
: __('No')
|
||||
) :
|
||||
form_checkbox(
|
||||
'requires_driver_license',
|
||||
__('Requires driver license'),
|
||||
$angeltype->requires_driver_license
|
||||
'',
|
||||
__('Primary contact person/desk for user questions.')
|
||||
),
|
||||
$supporter_mode
|
||||
? form_info(__('Show on dashboard'), $angeltype->show_on_dashboard ? __('Yes') : __('No'))
|
||||
: form_checkbox('show_on_dashboard', __('Show on dashboard'), $angeltype->show_on_dashboard),
|
||||
$supporter_mode
|
||||
? form_info(__('Hide at Registration'), $angeltype->hide_register ? __('Yes') : __('No'))
|
||||
: form_checkbox('hide_register', __('Hide at Registration'), $angeltype->hide_register),
|
||||
form_textarea('description', __('Description'), $angeltype->description),
|
||||
form_info('', __('Please use markdown for the description.')),
|
||||
heading(__('Contact'), 3),
|
||||
form_info(
|
||||
'',
|
||||
__('Primary contact person/desk for user questions.')
|
||||
),
|
||||
form_text('contact_name', __('Name'), $angeltype->contact_name),
|
||||
config('enable_dect') ? form_text('contact_dect', __('DECT'), $angeltype->contact_dect) : '',
|
||||
form_text('contact_email', __('E-Mail'), $angeltype->contact_email),
|
||||
form_submit('submit', __('Save')),
|
||||
]),
|
||||
]);
|
||||
form_text('contact_name', __('general.name'), $angeltype->contact_name),
|
||||
config('enable_dect') ? form_text('contact_dect', __('general.dect'), $angeltype->contact_dect) : '',
|
||||
form_text('contact_email', __('general.email'), $angeltype->contact_email),
|
||||
form_submit('submit', icon('save') . __('form.save')),
|
||||
]),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,28 +194,40 @@ function AngelType_view_buttons(
|
|||
$user_driver_license,
|
||||
$user
|
||||
) {
|
||||
$buttons = [
|
||||
button(page_link_to('angeltypes'), icon('person-lines-fill') . __('Angeltypes'), 'back'),
|
||||
];
|
||||
|
||||
if ($angeltype->requires_driver_license) {
|
||||
$buttons[] = button(
|
||||
user_driver_license_edit_link($user),
|
||||
url('/settings/certificates'),
|
||||
icon('person-vcard') . __('my driving license')
|
||||
);
|
||||
}
|
||||
if (config('isfg_enabled') && $angeltype->requires_ifsg_certificate) {
|
||||
$buttons[] = button(
|
||||
url('/settings/certificates'),
|
||||
icon('card-checklist') . __('angeltype.ifsg.own')
|
||||
);
|
||||
}
|
||||
|
||||
if (is_null($user_angeltype)) {
|
||||
$buttons[] = button(
|
||||
page_link_to('user_angeltypes', ['action' => 'add', 'angeltype_id' => $angeltype->id]),
|
||||
icon('box-arrow-in-right') . __('join'),
|
||||
'add'
|
||||
url('/user-angeltypes', ['action' => 'add', 'angeltype_id' => $angeltype->id]),
|
||||
icon('box-arrow-in-right') . ($admin_angeltypes ? '' : __('Join')),
|
||||
'add',
|
||||
'',
|
||||
($admin_angeltypes ? 'Join' : ''),
|
||||
);
|
||||
} else {
|
||||
if ($angeltype->requires_driver_license && !$user_driver_license->wantsToDrive()) {
|
||||
error(__('This angeltype requires a driver license. Please enter your driver license information!'));
|
||||
}
|
||||
|
||||
if (
|
||||
config('ifsg_enabled') && $angeltype->requires_ifsg_certificate && !(
|
||||
$user->license->ifsg_certificate_light || $user->license->ifsg_certificate
|
||||
)
|
||||
) {
|
||||
error(__('angeltype.ifsg.required.info'));
|
||||
}
|
||||
|
||||
if ($angeltype->restricted && !$user_angeltype->confirm_user_id) {
|
||||
error(sprintf(
|
||||
__('You are unconfirmed for this angeltype. Please go to the introduction for %s to get confirmed.'),
|
||||
|
@ -180,21 +235,30 @@ function AngelType_view_buttons(
|
|||
));
|
||||
}
|
||||
$buttons[] = button(
|
||||
page_link_to('user_angeltypes', ['action' => 'delete', 'user_angeltype_id' => $user_angeltype->id]),
|
||||
icon('box-arrow-right') . __('leave')
|
||||
url('/user-angeltypes', ['action' => 'delete', 'user_angeltype_id' => $user_angeltype->id]),
|
||||
icon('box-arrow-right') . ($admin_angeltypes ? '' : __('Leave')),
|
||||
'',
|
||||
'',
|
||||
($admin_angeltypes ? __('Leave') : ''),
|
||||
);
|
||||
}
|
||||
|
||||
if ($admin_angeltypes || $supporter) {
|
||||
$buttons[] = button(
|
||||
page_link_to('angeltypes', ['action' => 'edit', 'angeltype_id' => $angeltype->id]),
|
||||
icon('pencil') . __('edit')
|
||||
url('/angeltypes', ['action' => 'edit', 'angeltype_id' => $angeltype->id]),
|
||||
icon('pencil'),
|
||||
'',
|
||||
'',
|
||||
__('form.edit')
|
||||
);
|
||||
}
|
||||
if ($admin_angeltypes) {
|
||||
$buttons[] = button(
|
||||
page_link_to('angeltypes', ['action' => 'delete', 'angeltype_id' => $angeltype->id]),
|
||||
icon('trash') . __('delete')
|
||||
url('/angeltypes', ['action' => 'delete', 'angeltype_id' => $angeltype->id]),
|
||||
icon('trash'),
|
||||
'btn-danger',
|
||||
'',
|
||||
__('form.delete')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -218,7 +282,7 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
|
|||
foreach ($members as $member) {
|
||||
$member->name = User_Nick_render($member) . User_Pronoun_render($member);
|
||||
if (config('enable_dect')) {
|
||||
$member['dect'] = $member->contact->dect;
|
||||
$member['dect'] = htmlspecialchars((string) $member->contact->dect);
|
||||
}
|
||||
if ($angeltype->requires_driver_license) {
|
||||
$member['wants_to_drive'] = icon_bool($member->license->wantsToDrive());
|
||||
|
@ -229,23 +293,29 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
|
|||
$member['has_license_12t_truck'] = icon_bool($member->license->drive_12t);
|
||||
$member['has_license_forklift'] = icon_bool($member->license->drive_forklift);
|
||||
}
|
||||
if ($angeltype->requires_ifsg_certificate && config('ifsg_enabled')) {
|
||||
$member['ifsg_certificate'] = icon_bool($member->license->ifsg_certificate);
|
||||
if (config('ifsg_light_enabled')) {
|
||||
$member['ifsg_certificate_light'] = icon_bool($member->license->ifsg_certificate_light);
|
||||
}
|
||||
}
|
||||
|
||||
if ($angeltype->restricted && empty($member->pivot->confirm_user_id)) {
|
||||
$member['actions'] = table_buttons([
|
||||
button(
|
||||
page_link_to(
|
||||
'user_angeltypes',
|
||||
url(
|
||||
'/user-angeltypes',
|
||||
['action' => 'confirm', 'user_angeltype_id' => $member->pivot->id]
|
||||
),
|
||||
__('confirm'),
|
||||
__('Confirm'),
|
||||
'btn-sm'
|
||||
),
|
||||
button(
|
||||
page_link_to(
|
||||
'user_angeltypes',
|
||||
url(
|
||||
'/user-angeltypes',
|
||||
['action' => 'delete', 'user_angeltype_id' => $member->pivot->id]
|
||||
),
|
||||
__('deny'),
|
||||
__('Deny'),
|
||||
'btn-sm'
|
||||
),
|
||||
]);
|
||||
|
@ -254,13 +324,15 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
|
|||
if ($admin_angeltypes) {
|
||||
$member['actions'] = table_buttons([
|
||||
button(
|
||||
page_link_to('user_angeltypes', [
|
||||
url('/user-angeltypes', [
|
||||
'action' => 'update',
|
||||
'user_angeltype_id' => $member->pivot->id,
|
||||
'supporter' => 0,
|
||||
]),
|
||||
icon('person-fill-down') . __('Remove supporter rights'),
|
||||
'btn-sm'
|
||||
icon('person-fill-down'),
|
||||
'btn-sm',
|
||||
'',
|
||||
__('Remove supporter rights'),
|
||||
),
|
||||
]);
|
||||
} else {
|
||||
|
@ -272,22 +344,26 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
|
|||
$member['actions'] = table_buttons([
|
||||
$admin_angeltypes ?
|
||||
button(
|
||||
page_link_to('user_angeltypes', [
|
||||
url('/user-angeltypes', [
|
||||
'action' => 'update',
|
||||
'user_angeltype_id' => $member->pivot->id,
|
||||
'supporter' => 1,
|
||||
]),
|
||||
icon('person-fill-up') . __('Add supporter rights'),
|
||||
'btn-sm'
|
||||
icon('person-fill-up'),
|
||||
'btn-sm',
|
||||
'',
|
||||
__('Add supporter rights'),
|
||||
) :
|
||||
'',
|
||||
button(
|
||||
page_link_to('user_angeltypes', [
|
||||
url('/user-angeltypes', [
|
||||
'action' => 'delete',
|
||||
'user_angeltype_id' => $member->pivot->id,
|
||||
]),
|
||||
icon('trash') . __('remove'),
|
||||
'btn-sm'
|
||||
icon('trash'),
|
||||
'btn-sm btn-danger',
|
||||
'',
|
||||
__('Remove'),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
@ -313,27 +389,34 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
|
|||
function AngelType_view_table_headers(AngelType $angeltype, $supporter, $admin_angeltypes)
|
||||
{
|
||||
$headers = [
|
||||
'name' => __('Nick'),
|
||||
'dect' => __('DECT'),
|
||||
'actions' => '',
|
||||
'name' => __('general.nick'),
|
||||
];
|
||||
|
||||
if (config('enable_dect')) {
|
||||
$headers['dect'] = __('general.dect');
|
||||
}
|
||||
|
||||
if ($angeltype->requires_driver_license && ($supporter || $admin_angeltypes)) {
|
||||
$headers = [
|
||||
'name' => __('Nick'),
|
||||
'dect' => __('DECT'),
|
||||
$headers = array_merge($headers, [
|
||||
'wants_to_drive' => __('Driver'),
|
||||
'has_car' => __('Has car'),
|
||||
'has_license_car' => __('Car'),
|
||||
'has_license_3_5t_transporter' => __('3,5t Transporter'),
|
||||
'has_license_7_5t_truck' => __('7,5t Truck'),
|
||||
'has_license_12t_truck' => __('12t Truck'),
|
||||
'has_license_forklift' => __('Forklift'),
|
||||
'actions' => '',
|
||||
];
|
||||
'has_license_car' => __('settings.certificates.drive_car'),
|
||||
'has_license_3_5t_transporter' => __('settings.certificates.drive_3_5t'),
|
||||
'has_license_7_5t_truck' => __('settings.certificates.drive_7_5t'),
|
||||
'has_license_12t_truck' => __('settings.certificates.drive_12t'),
|
||||
'has_license_forklift' => __('settings.certificates.drive_forklift'),
|
||||
]);
|
||||
}
|
||||
if (!config('enable_dect')) {
|
||||
unset($headers['dect']);
|
||||
|
||||
if (config('ifsg_enabled') && $angeltype->requires_ifsg_certificate && ($supporter || $admin_angeltypes)) {
|
||||
if (config('ifsg_light_enabled')) {
|
||||
$headers['ifsg_certificate_light'] = __('ifsg.certificate_light');
|
||||
}
|
||||
$headers['ifsg_certificate'] = __('ifsg.certificate');
|
||||
}
|
||||
|
||||
$headers['actions'] = '';
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
|
@ -366,24 +449,29 @@ function AngelType_view(
|
|||
ShiftCalendarRenderer $shiftCalendarRenderer,
|
||||
$tab
|
||||
) {
|
||||
return page_with_title(sprintf(__('Team %s'), $angeltype->name), [
|
||||
AngelType_view_buttons($angeltype, $user_angeltype, $admin_angeltypes, $supporter, $user_driver_license, $user),
|
||||
msg(),
|
||||
tabs([
|
||||
__('Info') => AngelType_view_info(
|
||||
$angeltype,
|
||||
$members,
|
||||
$admin_user_angeltypes,
|
||||
$admin_angeltypes,
|
||||
$supporter
|
||||
),
|
||||
__('Shifts') => AngelType_view_shifts(
|
||||
$angeltype,
|
||||
$shiftsFilterRenderer,
|
||||
$shiftCalendarRenderer
|
||||
),
|
||||
], $tab),
|
||||
], true);
|
||||
$link = button(url('/angeltypes'), icon('chevron-left'), 'btn-sm', '', __('general.back'));
|
||||
return page_with_title(
|
||||
$link . ' ' . sprintf(__('Team %s'), htmlspecialchars($angeltype->name)),
|
||||
[
|
||||
AngelType_view_buttons($angeltype, $user_angeltype, $admin_angeltypes, $supporter, $user_driver_license, $user),
|
||||
msg(),
|
||||
tabs([
|
||||
__('Info') => AngelType_view_info(
|
||||
$angeltype,
|
||||
$members,
|
||||
$admin_user_angeltypes,
|
||||
$admin_angeltypes,
|
||||
$supporter
|
||||
),
|
||||
__('Shifts') => AngelType_view_shifts(
|
||||
$angeltype,
|
||||
$shiftsFilterRenderer,
|
||||
$shiftCalendarRenderer
|
||||
),
|
||||
], $tab),
|
||||
],
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,7 +482,7 @@ function AngelType_view(
|
|||
*/
|
||||
function AngelType_view_shifts(AngelType $angeltype, $shiftsFilterRenderer, $shiftCalendarRenderer)
|
||||
{
|
||||
$shifts = $shiftsFilterRenderer->render(page_link_to('angeltypes', [
|
||||
$shifts = $shiftsFilterRenderer->render(url('/angeltypes', [
|
||||
'action' => 'view',
|
||||
'angeltype_id' => $angeltype->id,
|
||||
]), ['type' => $angeltype->id]);
|
||||
|
@ -423,10 +511,10 @@ function AngelType_view_info(
|
|||
$info[] = AngelTypes_render_contact_info($angeltype);
|
||||
}
|
||||
|
||||
$info[] = '<h3>' . __('Description') . '</h3>';
|
||||
$info[] = '<h3>' . __('general.description') . '</h3>';
|
||||
$parsedown = new Parsedown();
|
||||
if ($angeltype->description != '') {
|
||||
$info[] = $parsedown->parse($angeltype->description);
|
||||
$info[] = $parsedown->parse(htmlspecialchars($angeltype->description));
|
||||
}
|
||||
|
||||
list($supporters, $members_confirmed, $members_unconfirmed) = AngelType_view_members(
|
||||
|
@ -462,11 +550,11 @@ function AngelType_view_info(
|
|||
if ($admin_user_angeltypes) {
|
||||
$info[] = buttons([
|
||||
button(
|
||||
page_link_to(
|
||||
'user_angeltypes',
|
||||
url(
|
||||
'/user-angeltypes',
|
||||
['action' => 'add', 'angeltype_id' => $angeltype->id]
|
||||
),
|
||||
__('Add'),
|
||||
icon('plus-lg') . __('Add'),
|
||||
'add'
|
||||
),
|
||||
]);
|
||||
|
@ -477,12 +565,12 @@ function AngelType_view_info(
|
|||
$info[] = '<h3>' . __('Unconfirmed') . '</h3>';
|
||||
$info[] = buttons([
|
||||
button(
|
||||
page_link_to('user_angeltypes', ['action' => 'confirm_all', 'angeltype_id' => $angeltype->id]),
|
||||
icon('check-lg') . __('confirm all')
|
||||
url('/user-angeltypes', ['action' => 'confirm_all', 'angeltype_id' => $angeltype->id]),
|
||||
icon('check-lg') . __('Confirm all')
|
||||
),
|
||||
button(
|
||||
page_link_to('user_angeltypes', ['action' => 'delete_all', 'angeltype_id' => $angeltype->id]),
|
||||
icon('trash') . __('deny all')
|
||||
url('/user-angeltypes', ['action' => 'delete_all', 'angeltype_id' => $angeltype->id]),
|
||||
icon('trash') . __('Deny all')
|
||||
),
|
||||
]);
|
||||
$info[] = table($table_headers, $members_unconfirmed);
|
||||
|
@ -500,9 +588,20 @@ function AngelType_view_info(
|
|||
function AngelTypes_render_contact_info(AngelType $angeltype)
|
||||
{
|
||||
$info = [
|
||||
__('Name') => [$angeltype->contact_name, $angeltype->contact_name],
|
||||
__('DECT') => config('enable_dect') ? [sprintf('<a href="tel:%s">%1$s</a>', $angeltype->contact_dect), $angeltype->contact_dect] : null,
|
||||
__('E-Mail') => [sprintf('<a href="mailto:%s">%1$s</a>', $angeltype->contact_email), $angeltype->contact_email],
|
||||
__('general.name') => [
|
||||
htmlspecialchars($angeltype->contact_name),
|
||||
htmlspecialchars($angeltype->contact_name),
|
||||
],
|
||||
__('general.dect') => config('enable_dect')
|
||||
? [
|
||||
sprintf('<a href="tel:%s">%1$s</a>', htmlspecialchars($angeltype->contact_dect)),
|
||||
htmlspecialchars($angeltype->contact_dect),
|
||||
]
|
||||
: null,
|
||||
__('general.email') => [
|
||||
sprintf('<a href="mailto:%s">%1$s</a>', htmlspecialchars($angeltype->contact_email)),
|
||||
htmlspecialchars($angeltype->contact_email),
|
||||
],
|
||||
];
|
||||
$contactInfo = [];
|
||||
foreach ($info as $name => $data) {
|
||||
|
@ -523,20 +622,22 @@ function AngelTypes_render_contact_info(AngelType $angeltype)
|
|||
*/
|
||||
function AngelTypes_list_view($angeltypes, bool $admin_angeltypes)
|
||||
{
|
||||
return page_with_title(angeltypes_title(), [
|
||||
msg(),
|
||||
buttons([
|
||||
$admin_angeltypes
|
||||
? button(page_link_to('angeltypes', ['action' => 'edit']), __('New angeltype'), 'add')
|
||||
: '',
|
||||
button(url('/angeltypes/about'), __('angeltypes.about')),
|
||||
]),
|
||||
table([
|
||||
'name' => __('Name'),
|
||||
'is_restricted' => icon('mortarboard-fill') . __('Requires introduction'),
|
||||
'no_self_signup_allowed' => icon('pencil-square') . __('Self Sign Up Allowed'),
|
||||
'membership' => __('Membership'),
|
||||
'actions' => '',
|
||||
], $angeltypes),
|
||||
], true);
|
||||
$link = button(url('/angeltypes', ['action' => 'edit']), icon('plus-lg'), 'add');
|
||||
return page_with_title(
|
||||
angeltypes_title() . ' ' . ($admin_angeltypes ? $link : ''),
|
||||
[
|
||||
msg(),
|
||||
buttons([
|
||||
button(url('/angeltypes/about'), __('angeltypes.about')),
|
||||
]),
|
||||
table([
|
||||
'name' => __('general.name'),
|
||||
'is_restricted' => icon('mortarboard-fill') . __('angeltypes.restricted'),
|
||||
'shift_self_signup_allowed' => icon('pencil-square') . __('shift.self_signup.allowed'),
|
||||
'membership' => __('Membership'),
|
||||
'actions' => '',
|
||||
], $angeltypes),
|
||||
],
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ function EventConfig_edit_view(
|
|||
]),
|
||||
div('row', [
|
||||
div('col-md-6', [
|
||||
form_submit('submit', __('Save')),
|
||||
form_submit('submit', icon('save') . __('form.save')),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\ShiftCalendarRenderer;
|
||||
use Engelsystem\ShiftsFilterRenderer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Location $location
|
||||
* @param ShiftsFilterRenderer $shiftsFilterRenderer
|
||||
* @param ShiftCalendarRenderer $shiftCalendarRenderer
|
||||
* @return string
|
||||
*/
|
||||
function location_view(Location $location, ShiftsFilterRenderer $shiftsFilterRenderer, ShiftCalendarRenderer $shiftCalendarRenderer)
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
$assignNotice = '';
|
||||
if (config('signup_requires_arrival') && !$user->state->arrived) {
|
||||
$assignNotice = info(render_user_arrived_hint(), true);
|
||||
}
|
||||
|
||||
$description = '';
|
||||
if ($location->description) {
|
||||
$description = '<h3>' . __('general.description') . '</h3>';
|
||||
$parsedown = new Parsedown();
|
||||
$description .= $parsedown->parse(htmlspecialchars($location->description));
|
||||
}
|
||||
|
||||
$dect = '';
|
||||
if (config('enable_dect') && $location->dect) {
|
||||
$dect = heading(__('Contact'), 3)
|
||||
. description([__('general.dect') => sprintf(
|
||||
'<a href="tel:%s">%1$s</a>',
|
||||
htmlspecialchars($location->dect)
|
||||
)]);
|
||||
}
|
||||
|
||||
$tabs = [];
|
||||
if ($location->map_url) {
|
||||
$tabs[__('location.map_url')] = sprintf(
|
||||
'<div class="map">'
|
||||
. '<iframe style="width: 100%%; min-height: 400px; border: 0 none;" src="%s"></iframe>'
|
||||
. '</div>',
|
||||
htmlspecialchars($location->map_url)
|
||||
);
|
||||
}
|
||||
|
||||
$tabs[__('Shifts')] = div('first', [
|
||||
$shiftsFilterRenderer->render(url('/locations', [
|
||||
'action' => 'view',
|
||||
'location_id' => $location->id,
|
||||
]), ['locations' => [$location->id]]),
|
||||
$shiftCalendarRenderer->render(),
|
||||
]);
|
||||
|
||||
$selected_tab = 0;
|
||||
$request = request();
|
||||
if ($request->has('shifts_filter_day')) {
|
||||
$selected_tab = count($tabs) - 1;
|
||||
}
|
||||
|
||||
$link = button(url('/admin/locations'), icon('chevron-left'), 'btn-sm', '', __('general.back'));
|
||||
return page_with_title(
|
||||
(auth()->can('admin_locations') ? $link . ' ' : '') .
|
||||
icon('pin-map-fill') . htmlspecialchars($location->name),
|
||||
[
|
||||
$assignNotice,
|
||||
auth()->can('admin_locations') ? buttons([
|
||||
button(
|
||||
url('/admin/locations/edit/' . $location->id),
|
||||
icon('pencil'),
|
||||
'',
|
||||
'',
|
||||
__('form.edit')
|
||||
),
|
||||
]) : '',
|
||||
$dect,
|
||||
$description,
|
||||
tabs($tabs, $selected_tab),
|
||||
],
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Location $location
|
||||
* @return string
|
||||
*/
|
||||
function location_name_render(Location $location)
|
||||
{
|
||||
if (auth()->can('view_locations')) {
|
||||
return '<a href="' . location_link($location) . '">'
|
||||
. icon('pin-map-fill') . htmlspecialchars($location->name)
|
||||
. '</a>';
|
||||
}
|
||||
|
||||
return icon('pin-map-fill') . htmlspecialchars($location->name);
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Helpers\DayOfEvent;
|
||||
use Engelsystem\Models\News;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
|
@ -8,17 +9,19 @@ use Illuminate\Support\Collection;
|
|||
*
|
||||
* @param array $stats
|
||||
* @param array[] $free_shifts
|
||||
* @param News[]|Collection $important_news
|
||||
* @param News[]|Collection $highlighted_news
|
||||
* @return string
|
||||
*/
|
||||
function public_dashboard_view($stats, $free_shifts, $important_news)
|
||||
function public_dashboard_view($stats, $free_shifts, $highlighted_news)
|
||||
{
|
||||
$needed_angels = '';
|
||||
$news = '';
|
||||
if ($important_news->isNotEmpty()) {
|
||||
$first_news = $important_news->first();
|
||||
if ($highlighted_news->isNotEmpty()) {
|
||||
$first_news = $highlighted_news->first();
|
||||
$news = div('alert alert-warning text-center', [
|
||||
'<a href="' . url('/news/' . $first_news->id) . '"><strong>' . $first_news->title . '</strong></a>',
|
||||
'<a href="' . url('/news/' . $first_news->id) . '">'
|
||||
. '<strong>' . htmlspecialchars($first_news->title) . '</strong>'
|
||||
. '</a>',
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -43,17 +46,25 @@ function public_dashboard_view($stats, $free_shifts, $important_news)
|
|||
]);
|
||||
}
|
||||
|
||||
$stats = [
|
||||
stats(__('Angels needed in the next 3 hrs'), $stats['needed-3-hours']),
|
||||
stats(__('Angels needed for nightshifts'), $stats['needed-night']),
|
||||
stats(__('Angels currently working'), $stats['angels-working'], 'default'),
|
||||
stats(__('Hours to be worked'), $stats['hours-to-work'], 'default'),
|
||||
];
|
||||
|
||||
$dayOfEvent = DayOfEvent::get();
|
||||
|
||||
if (config('enable_show_day_of_event') && $dayOfEvent !== null) {
|
||||
$stats[] = stats(__('dashboard.day'), $dayOfEvent, 'default');
|
||||
}
|
||||
|
||||
$isFiltered = request()->get('filtered');
|
||||
$filter = collect(session()->get('shifts-filter'))->only(['rooms', 'types'])->toArray();
|
||||
$filter = collect(session()->get('shifts-filter'))->only(['locations', 'types'])->toArray();
|
||||
return page([
|
||||
div('wrapper', [
|
||||
div('public-dashboard', [
|
||||
div('first row', [
|
||||
stats(__('Angels needed in the next 3 hrs'), $stats['needed-3-hours']),
|
||||
stats(__('Angels needed for nightshifts'), $stats['needed-night']),
|
||||
stats(__('Angels currently working'), $stats['angels-working'], 'default'),
|
||||
stats(__('Hours to be worked'), $stats['hours-to-work'], 'default'),
|
||||
], 'statistics'),
|
||||
div('first row', $stats, 'statistics'),
|
||||
$news,
|
||||
$needed_angels,
|
||||
], 'public-dashboard'),
|
||||
|
@ -84,17 +95,17 @@ function public_dashboard_shift_render($shift)
|
|||
$panel_body = icon('clock-history') . $shift['start'] . ' - ' . $shift['end'];
|
||||
$panel_body .= ' (' . $shift['duration'] . ' h)';
|
||||
|
||||
$panel_body .= '<br>' . icon('list-task') . $shift['shifttype_name'];
|
||||
$panel_body .= '<br>' . icon('list-task') . htmlspecialchars($shift['shifttype_name']);
|
||||
if (!empty($shift['title'])) {
|
||||
$panel_body .= ' (' . $shift['title'] . ')';
|
||||
$panel_body .= ' (' . htmlspecialchars($shift['title']) . ')';
|
||||
}
|
||||
|
||||
$panel_body .= '<br>' . icon('pin-map-fill') . $shift['room_name'];
|
||||
$panel_body .= '<br>' . icon('pin-map-fill') . htmlspecialchars($shift['location_name']);
|
||||
|
||||
foreach ($shift['needed_angels'] as $needed_angels) {
|
||||
$panel_body .= '<br>' . icon('person')
|
||||
. '<span class="text-' . $shift['style'] . '">'
|
||||
. $needed_angels['need'] . ' × ' . $needed_angels['angeltype_name']
|
||||
. $needed_angels['need'] . ' × ' . htmlspecialchars($needed_angels['angeltype_name'])
|
||||
. '</span>';
|
||||
}
|
||||
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\ShiftCalendarRenderer;
|
||||
use Engelsystem\ShiftsFilterRenderer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Room $room
|
||||
* @param ShiftsFilterRenderer $shiftsFilterRenderer
|
||||
* @param ShiftCalendarRenderer $shiftCalendarRenderer
|
||||
* @return string
|
||||
*/
|
||||
function Room_view(Room $room, ShiftsFilterRenderer $shiftsFilterRenderer, ShiftCalendarRenderer $shiftCalendarRenderer)
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
$assignNotice = '';
|
||||
if (config('signup_requires_arrival') && !$user->state->arrived) {
|
||||
$assignNotice = info(render_user_arrived_hint(), true);
|
||||
}
|
||||
|
||||
$description = '';
|
||||
if ($room->description) {
|
||||
$description = '<h3>' . __('Description') . '</h3>';
|
||||
$parsedown = new Parsedown();
|
||||
$description .= $parsedown->parse($room->description);
|
||||
}
|
||||
|
||||
$dect = '';
|
||||
if (config('enable_dect') && $room->dect) {
|
||||
$dect = heading(__('Contact'), 3)
|
||||
. description([__('DECT') => sprintf('<a href="tel:%s">%1$s</a>', $room->dect)]);
|
||||
}
|
||||
|
||||
$tabs = [];
|
||||
if ($room->map_url) {
|
||||
$tabs[__('Map')] = sprintf(
|
||||
'<div class="map">'
|
||||
. '<iframe style="width: 100%%; min-height: 400px; border: 0 none;" src="%s"></iframe>'
|
||||
. '</div>',
|
||||
$room->map_url
|
||||
);
|
||||
}
|
||||
|
||||
$tabs[__('Shifts')] = div('first', [
|
||||
$shiftsFilterRenderer->render(page_link_to('rooms', [
|
||||
'action' => 'view',
|
||||
'room_id' => $room->id,
|
||||
]), ['rooms' => [$room->id]]),
|
||||
$shiftCalendarRenderer->render(),
|
||||
]);
|
||||
|
||||
$selected_tab = 0;
|
||||
$request = request();
|
||||
if ($request->has('shifts_filter_day')) {
|
||||
$selected_tab = count($tabs) - 1;
|
||||
}
|
||||
|
||||
return page_with_title(icon('pin-map-fill') . $room->name, [
|
||||
$assignNotice,
|
||||
auth()->can('admin_rooms') ? buttons([
|
||||
button(
|
||||
page_link_to('admin/rooms/edit/' . $room->id),
|
||||
icon('pencil') . __('edit')
|
||||
),
|
||||
]) : '',
|
||||
$dect,
|
||||
$description,
|
||||
tabs($tabs, $selected_tab),
|
||||
], true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Room $room
|
||||
* @return string
|
||||
*/
|
||||
function Room_name_render(Room $room)
|
||||
{
|
||||
if (auth()->can('view_rooms')) {
|
||||
return '<a href="' . room_link($room) . '">' . icon('pin-map-fill') . $room->name . '</a>';
|
||||
}
|
||||
|
||||
return icon('pin-map-fill') . $room->name;
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Engelsystem;
|
||||
|
||||
use Engelsystem\Helpers\Carbon;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Illuminate\Support\Collection;
|
||||
|
@ -61,28 +62,28 @@ class ShiftCalendarRenderer
|
|||
}
|
||||
|
||||
/**
|
||||
* Assigns the shifts to different lanes per room if they collide
|
||||
* Assigns the shifts to different lanes per location if they collide
|
||||
*
|
||||
* @param Shift[] $shifts The shifts to assign
|
||||
* @return array Returns an array that assigns a room_id to an array of ShiftCalendarLane containing the shifts
|
||||
* @return array Returns an array that assigns a location_id to an array of ShiftCalendarLane containing the shifts
|
||||
*/
|
||||
private function assignShiftsToLanes($shifts)
|
||||
{
|
||||
// array that assigns a room id to a list of lanes (per room)
|
||||
// array that assigns a location id to a list of lanes (per location)
|
||||
$lanes = [];
|
||||
|
||||
foreach ($shifts as $shift) {
|
||||
$room = $shift->room;
|
||||
$header = Room_name_render($room);
|
||||
if (!isset($lanes[$room->id])) {
|
||||
// initialize room with one lane
|
||||
$lanes[$room->id] = [
|
||||
$location = $shift->location;
|
||||
$header = location_name_render($location);
|
||||
if (!isset($lanes[$location->id])) {
|
||||
// initialize location with one lane
|
||||
$lanes[$location->id] = [
|
||||
new ShiftCalendarLane($header),
|
||||
];
|
||||
}
|
||||
// Try to add the shift to the existing lanes for this room
|
||||
// Try to add the shift to the existing lanes for this location
|
||||
$shift_added = false;
|
||||
foreach ($lanes[$room->id] as $lane) {
|
||||
foreach ($lanes[$location->id] as $lane) {
|
||||
/** @var ShiftCalendarLane $lane */
|
||||
if ($lane->shiftFits($shift)) {
|
||||
$lane->addShift($shift);
|
||||
|
@ -90,11 +91,11 @@ class ShiftCalendarRenderer
|
|||
break;
|
||||
}
|
||||
}
|
||||
// If all lanes for this room are busy, create a new lane and add shift to it
|
||||
// If all lanes for this location are busy, create a new lane and add shift to it
|
||||
if (!$shift_added) {
|
||||
$newLane = new ShiftCalendarLane($header);
|
||||
$newLane->addShift($shift);
|
||||
$lanes[$room->id][] = $newLane;
|
||||
$lanes[$location->id][] = $newLane;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,8 +154,8 @@ class ShiftCalendarRenderer
|
|||
private function renderShiftLanes()
|
||||
{
|
||||
$html = '';
|
||||
foreach ($this->lanes as $room_lanes) {
|
||||
foreach ($room_lanes as $lane) {
|
||||
foreach ($this->lanes as $location_lanes) {
|
||||
foreach ($location_lanes as $lane) {
|
||||
$html .= $this->renderLane($lane);
|
||||
}
|
||||
}
|
||||
|
@ -212,20 +213,21 @@ class ShiftCalendarRenderer
|
|||
*/
|
||||
private function renderTick($time, $label = false)
|
||||
{
|
||||
$time = Carbon::createFromTimestamp($time);
|
||||
$class = $label ? 'tick bg-' . theme_type() : 'tick ';
|
||||
if ($time % (24 * 60 * 60) == 23 * 60 * 60) {
|
||||
if ($time->isStartOfDay()) {
|
||||
if (!$label) {
|
||||
return div($class . ' day');
|
||||
}
|
||||
return div($class . ' day', [
|
||||
date(__('m-d'), $time) . '<br>' . date(__('H:i'), $time),
|
||||
$time->format(__('m-d')) . '<br>' . $time->format(__('H:i')),
|
||||
]);
|
||||
} elseif ($time % (60 * 60) == 0) {
|
||||
} elseif ($time->isStartOfHour()) {
|
||||
if (!$label) {
|
||||
return div($class . ' hour');
|
||||
}
|
||||
return div($class . ' hour', [
|
||||
date(__('m-d'), $time) . '<br>' . date(__('H:i'), $time),
|
||||
$time->format(__('m-d')) . '<br>' . $time->format(__('H:i')),
|
||||
]);
|
||||
}
|
||||
return div($class);
|
||||
|
@ -242,7 +244,7 @@ class ShiftCalendarRenderer
|
|||
|
||||
$time_slot = [
|
||||
div('header ' . $bg, [
|
||||
__('Time'),
|
||||
__('log.time'),
|
||||
]),
|
||||
];
|
||||
for ($block = 0; $block < $this->getBlocksPerSlot(); $block++) {
|
||||
|
@ -312,7 +314,7 @@ class ShiftCalendarRenderer
|
|||
badge(__('Help needed'), 'danger'),
|
||||
badge(__('Other angeltype needed / collides with my shifts'), 'warning'),
|
||||
badge(__('Shift is full'), 'success'),
|
||||
badge(__('Shift running/ended or you have not arrived'), 'secondary'),
|
||||
badge(__('Shift is running/ended or you have not arrived'), 'secondary'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class ShiftCalendarShiftRenderer
|
|||
{
|
||||
$info_text = '';
|
||||
if ($shift->title != '') {
|
||||
$info_text = icon('info-circle') . $shift->title . '<br>';
|
||||
$info_text = icon('info-circle') . htmlspecialchars($shift->title) . '<br>';
|
||||
}
|
||||
list($shift_signup_state, $shifts_row) = $this->renderShiftNeededAngeltypes(
|
||||
$shift,
|
||||
|
@ -43,8 +43,6 @@ class ShiftCalendarShiftRenderer
|
|||
$blocks = ceil(($shift->end->timestamp - $shift->start->timestamp) / ShiftCalendarRenderer::SECONDS_PER_ROW);
|
||||
$blocks = max(1, $blocks);
|
||||
|
||||
$room = $shift->room;
|
||||
|
||||
return [
|
||||
$blocks,
|
||||
div(
|
||||
|
@ -57,7 +55,7 @@ class ShiftCalendarShiftRenderer
|
|||
$this->renderShiftHead($shift, $class, $shift_signup_state->getFreeEntries()),
|
||||
div('card-body ' . $this->classBg(), [
|
||||
$info_text,
|
||||
Room_name_render($room),
|
||||
location_name_render($shift->location),
|
||||
]),
|
||||
$shifts_row,
|
||||
]
|
||||
|
@ -192,14 +190,14 @@ class ShiftCalendarShiftRenderer
|
|||
// No link and add a text hint, when the shift ended
|
||||
ShiftSignupStatus::NOT_ARRIVED => $inner_text . ' (' . __('please arrive for signup') . ')',
|
||||
ShiftSignupStatus::NOT_YET => $inner_text . ' (' . __('not yet') . ')',
|
||||
ShiftSignupStatus::ANGELTYPE => $angeltype->restricted
|
||||
// User has to be confirmed on the angeltype first
|
||||
ShiftSignupStatus::ANGELTYPE => $angeltype->restricted || !$angeltype->shift_self_signup
|
||||
// User has to be confirmed on the angeltype first or can't sign up by themselves
|
||||
? $inner_text . icon('mortarboard-fill')
|
||||
// Add link to join the angeltype first
|
||||
: $inner_text . '<br />'
|
||||
. button(
|
||||
page_link_to('user_angeltypes', ['action' => 'add', 'angeltype_id' => $angeltype->id]),
|
||||
sprintf(__('Become %s'), $angeltype->name),
|
||||
url('/user-angeltypes', ['action' => 'add', 'angeltype_id' => $angeltype->id]),
|
||||
sprintf(__('Become %s'), htmlspecialchars($angeltype->name)),
|
||||
'btn-sm'
|
||||
),
|
||||
// Shift collides or user is already signed up: No signup allowed
|
||||
|
@ -249,20 +247,24 @@ class ShiftCalendarShiftRenderer
|
|||
if (auth()->can('admin_shifts')) {
|
||||
$header_buttons = '<div class="ms-auto d-print-none">' . table_buttons([
|
||||
button(
|
||||
page_link_to('user_shifts', ['edit_shift' => $shift->id]),
|
||||
url('/user-shifts', ['edit_shift' => $shift->id]),
|
||||
icon('pencil'),
|
||||
'btn-' . $class . ' btn-sm border-light text-white'
|
||||
'btn-' . $class . ' btn-sm border-light text-white',
|
||||
'',
|
||||
__('form.edit')
|
||||
),
|
||||
button(
|
||||
page_link_to('user_shifts', ['delete_shift' => $shift->id]),
|
||||
url('/user-shifts', ['delete_shift' => $shift->id]),
|
||||
icon('trash'),
|
||||
'btn-' . $class . ' btn-sm border-light text-white'
|
||||
'btn-' . $class . ' btn-sm border-light text-white',
|
||||
'',
|
||||
__('form.delete')
|
||||
),
|
||||
]) . '</div>';
|
||||
}
|
||||
$shift_heading = $shift->start->format('H:i') . ' ‐ '
|
||||
. $shift->end->format('H:i') . ' — '
|
||||
. $shift->shiftType->name;
|
||||
. htmlspecialchars($shift->shiftType->name);
|
||||
|
||||
if ($needed_angeltypes_count > 0) {
|
||||
$shift_heading = '<span class="badge bg-light text-danger me-1">' . $needed_angeltypes_count . '</span> ' . $shift_heading;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue