Compare commits
12
Commits
d86eb1fd2e
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
518f3a46d0 | ||
|
|
a05143bfbe | ||
|
|
29cedd5916 | ||
|
|
5c57dc823f | ||
|
|
d4908b6ab9 | ||
|
|
39a343911a | ||
|
|
66d560f98d | ||
|
|
86817731f4 | ||
|
|
9d639c8db1 | ||
|
|
8e599a5dd7 | ||
|
|
9072e764c0 | ||
|
|
24451d0f36 |
@@ -15,6 +15,7 @@ web_environment: []
|
|||||||
nodejs_version: "18"
|
nodejs_version: "18"
|
||||||
corepack_enable: false
|
corepack_enable: false
|
||||||
disable_upload_dirs_warning: true
|
disable_upload_dirs_warning: true
|
||||||
|
omit_containers: [ddev-ssh-agent]
|
||||||
|
|
||||||
xhgui_https_port: "8142"
|
xhgui_https_port: "8142"
|
||||||
xhgui_http_port: "8143"
|
xhgui_http_port: "8143"
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ APP_BPN_DEBUG=false
|
|||||||
# This hotel code will be assigned to admin users together with ROLE_HOTEL_MANAGER
|
# This hotel code will be assigned to admin users together with ROLE_HOTEL_MANAGER
|
||||||
# in dev and staging environments for testing purposes
|
# in dev and staging environments for testing purposes
|
||||||
APP_BPN_DEFAULT_HOTEL_CODE=
|
APP_BPN_DEFAULT_HOTEL_CODE=
|
||||||
APP_BPN_CRM_ID_ADMIN=1292
|
APP_BPN_CRM_ID_TEAM_ADMIN=1484
|
||||||
APP_BPN_CRM_ID_MANAGER=1293
|
APP_BPN_CRM_ID_MANAGER=1293
|
||||||
APP_BPN_CRM_ID_TEAMER=1070
|
APP_BPN_CRM_ID_TEAMER=1070
|
||||||
|
|
||||||
|
|||||||
Generated
+350
-312
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ security:
|
|||||||
property: email
|
property: email
|
||||||
|
|
||||||
role_hierarchy:
|
role_hierarchy:
|
||||||
ROLE_ADMIN: [ ROLE_ADMINISTRATIVE ]
|
ROLE_TEAM_ADMIN: [ ROLE_ADMINISTRATIVE ]
|
||||||
ROLE_MANAGER: [ ROLE_ADMINISTRATIVE ]
|
ROLE_MANAGER: [ ROLE_ADMINISTRATIVE ]
|
||||||
|
|
||||||
firewalls:
|
firewalls:
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ zenstruck_schedule:
|
|||||||
mailer:
|
mailer:
|
||||||
service: mailer
|
service: mailer
|
||||||
default_to: [email protected]
|
default_to: [email protected]
|
||||||
default_from: team@ep-reisen.de
|
default_from: noreply@ep-reisen.de
|
||||||
subject_prefix: "[E&P-Team]"
|
subject_prefix: "[E&P-Team]"
|
||||||
|
|
||||||
schedule_extensions:
|
schedule_extensions:
|
||||||
email_on_failure:
|
email_on_failure:
|
||||||
|
enabled: true
|
||||||
to: [email protected]
|
to: [email protected]
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json
|
# yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json
|
||||||
parameters:
|
parameters:
|
||||||
bpn_crm_id_admin: '%env(int:APP_BPN_CRM_ID_ADMIN)%'
|
bpn_crm_id_team_admin: '%env(int:APP_BPN_CRM_ID_TEAM_ADMIN)%'
|
||||||
bpn_crm_id_manager: '%env(int:APP_BPN_CRM_ID_MANAGER)%'
|
bpn_crm_id_manager: '%env(int:APP_BPN_CRM_ID_MANAGER)%'
|
||||||
bpn_crm_id_teamer: '%env(int:APP_BPN_CRM_ID_TEAMER)%'
|
bpn_crm_id_teamer: '%env(int:APP_BPN_CRM_ID_TEAMER)%'
|
||||||
bpn_default_hotel_code: '%env(default::APP_BPN_DEFAULT_HOTEL_CODE)%'
|
bpn_default_hotel_code: '%env(default::APP_BPN_DEFAULT_HOTEL_CODE)%'
|
||||||
@@ -162,7 +162,7 @@ services:
|
|||||||
App\BusProNet\ResponseParser:
|
App\BusProNet\ResponseParser:
|
||||||
arguments:
|
arguments:
|
||||||
$options:
|
$options:
|
||||||
bpn_crm_id_admin: '%bpn_crm_id_admin%'
|
bpn_crm_id_team_admin: '%bpn_crm_id_team_admin%'
|
||||||
bpn_crm_id_manager: '%bpn_crm_id_manager%'
|
bpn_crm_id_manager: '%bpn_crm_id_manager%'
|
||||||
bpn_crm_id_teamer: '%bpn_crm_id_teamer%'
|
bpn_crm_id_teamer: '%bpn_crm_id_teamer%'
|
||||||
bpn_crm_house_manager_ids: '%bpn_crm_house_manager_ids%'
|
bpn_crm_house_manager_ids: '%bpn_crm_house_manager_ids%'
|
||||||
|
|||||||
+20
-36
@@ -22,7 +22,7 @@ set('keep_releases', 3);
|
|||||||
// Rsync options, mainly files/dirs to exclude
|
// Rsync options, mainly files/dirs to exclude
|
||||||
$rsyncOptions = [
|
$rsyncOptions = [
|
||||||
'exclude' => [
|
'exclude' => [
|
||||||
'.cursor',
|
'.claude',
|
||||||
'.idea',
|
'.idea',
|
||||||
'.vscode',
|
'.vscode',
|
||||||
'.DS_Store',
|
'.DS_Store',
|
||||||
@@ -70,44 +70,33 @@ $rsyncOptions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
host('prod')
|
host('prod')
|
||||||
->setHostname('185.243.135.29')
|
|
||||||
->setRemoteUser('p704161')
|
|
||||||
->setForwardAgent(true)
|
|
||||||
->setSshMultiplexing(true)
|
|
||||||
->setDeployPath('/home/www/p704161/html/myep-team')
|
|
||||||
->set('writable_mode', 'chmod')
|
|
||||||
->set('http_user', 'p704161')
|
|
||||||
->set('bin/php', '/usr/local/bin/php')
|
|
||||||
->set('rsync_src', __DIR__)
|
|
||||||
->set('rsync', $rsyncOptions)
|
|
||||||
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{current_path}}/public/ --web-url=https://myep-team.ep-reisen.de')
|
|
||||||
;
|
|
||||||
|
|
||||||
host('staging')
|
|
||||||
->setHostname('185.243.135.29')
|
|
||||||
->setRemoteUser('p704161')
|
|
||||||
->setForwardAgent(true)
|
|
||||||
->setSshMultiplexing(true)
|
|
||||||
->setDeployPath('/home/www/p704161/html/myep-team-staging')
|
|
||||||
->set('writable_mode', 'chmod')
|
|
||||||
->set('http_user', 'p704161')
|
|
||||||
->set('bin/php', '/usr/local/bin/php')
|
|
||||||
->set('rsync_src', __DIR__)
|
|
||||||
->set('rsync', $rsyncOptions)
|
|
||||||
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{current_path}}/public/ --web-url=https://myep-team.ep-reisen.net')
|
|
||||||
;
|
|
||||||
|
|
||||||
host('hetzner')
|
|
||||||
->setHostname('dedi10193.your-server.de')
|
->setHostname('dedi10193.your-server.de')
|
||||||
->setRemoteUser('myepteam')
|
->setRemoteUser('myepteam')
|
||||||
->setForwardAgent(true)
|
->setForwardAgent(true)
|
||||||
->setSshMultiplexing(true)
|
->setSshMultiplexing(true)
|
||||||
->setDeployPath('/usr/home/myepteam/public_html/myep-team')
|
->setDeployPath('/usr/www/users/myepteam/prod')
|
||||||
->set('bin/php', '/usr/bin/php')
|
->set('bin/php', '/usr/bin/php')
|
||||||
->set('http_user', 'myepteam')
|
->set('http_user', 'myepteam')
|
||||||
->set('rsync_src', __DIR__)
|
->set('rsync_src', __DIR__)
|
||||||
->set('rsync', $rsyncOptions)
|
->set('rsync', $rsyncOptions)
|
||||||
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{current_path}}/public/ --web-url=https://myep-team.ep-reisen.net')
|
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{current_path}}/public/ --web-url=https://team.ep-reisen.de')
|
||||||
|
;
|
||||||
|
|
||||||
|
host('staging')
|
||||||
|
->setHostname('dedi10193.your-server.de')
|
||||||
|
->setRemoteUser('myepteam')
|
||||||
|
->setForwardAgent(true)
|
||||||
|
->setSshMultiplexing(true)
|
||||||
|
->setDeployPath('/usr/www/users/myepteam/staging')
|
||||||
|
->set('bin/php', '/usr/bin/php')
|
||||||
|
->set('http_user', 'myepteam')
|
||||||
|
->set('rsync_src', __DIR__)
|
||||||
|
->set('rsync', $rsyncOptions)
|
||||||
|
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{current_path}}/public/ --web-url=https://team.ep-reisen.net --web-basic-auth=team:staging')
|
||||||
|
->add('shared_files', [
|
||||||
|
'public/.htaccess',
|
||||||
|
'public/.htpasswd',
|
||||||
|
])
|
||||||
;
|
;
|
||||||
|
|
||||||
task('deploy', [
|
task('deploy', [
|
||||||
@@ -116,7 +105,6 @@ task('deploy', [
|
|||||||
'deploy:lock',
|
'deploy:lock',
|
||||||
'deploy:release',
|
'deploy:release',
|
||||||
'deploy:assets',
|
'deploy:assets',
|
||||||
'deploy:check-platform',
|
|
||||||
'rsync',
|
'rsync',
|
||||||
'deploy:shared',
|
'deploy:shared',
|
||||||
'deploy:writable',
|
'deploy:writable',
|
||||||
@@ -127,10 +115,6 @@ task('deploy', [
|
|||||||
'deploy:stop-workers',
|
'deploy:stop-workers',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
task('deploy:check-platform', function () {
|
|
||||||
runLocally('composer check-platform-reqs');
|
|
||||||
});
|
|
||||||
|
|
||||||
task('deploy:stop-workers', function () {
|
task('deploy:stop-workers', function () {
|
||||||
run('{{bin/console}} messenger:stop-workers');
|
run('{{bin/console}} messenger:stop-workers');
|
||||||
});
|
});
|
||||||
|
|||||||
+44
-12
@@ -30,17 +30,35 @@ assign:
|
|||||||
|
|
||||||
| Role | Label | Granted by | Revoked by | Hierarchy |
|
| Role | Label | Granted by | Revoked by | Hierarchy |
|
||||||
|------|-------|-----------|------------|-----------|
|
|------|-------|-----------|------------|-----------|
|
||||||
| `ROLE_ADMIN` | Admin | super admin, approving a CRM claim | the CRM, automatically | ⇒ `ROLE_ADMINISTRATIVE` |
|
| `ROLE_TEAM_ADMIN` | Admin | super admin, approving a CRM claim | the CRM, automatically | ⇒ `ROLE_ADMINISTRATIVE` |
|
||||||
| `ROLE_MANAGER` | Reisemanager | super admin, approving a CRM claim | the CRM, automatically | ⇒ `ROLE_ADMINISTRATIVE` |
|
| `ROLE_MANAGER` | Reisemanager | super admin, approving a CRM claim | the CRM, automatically | ⇒ `ROLE_ADMINISTRATIVE` |
|
||||||
| `ROLE_HOUSE_MANAGER` | Hausleitung | super admin, approving a CRM claim | the CRM, automatically | — |
|
| `ROLE_HOUSE_MANAGER` | Hausleitung | super admin, approving a CRM claim | the CRM, automatically | — |
|
||||||
| `ROLE_TEAMER` | Teamer | the CRM, automatically | the CRM, automatically | — |
|
| `ROLE_TEAMER` | Teamer | the CRM, automatically | the CRM, automatically | — |
|
||||||
|
|
||||||
|
### A note on the `TEAM_` prefix
|
||||||
|
|
||||||
|
`ROLE_TEAM_ADMIN`, `ROLE_TEAM_ADMIN_PENDING` and `ROLE_TEAM_SUPER_ADMIN` were renamed from
|
||||||
|
`ROLE_ADMIN`, `ROLE_ADMIN_PENDING` and `ROLE_SUPER_ADMIN`. The MyE&P identity provider is
|
||||||
|
shared with a sibling portal that uses `ROLE_ADMIN` for a different privilege, so the plain
|
||||||
|
name was ambiguous across the estate; the prefix makes it unambiguously *this* application's
|
||||||
|
admin. The German label is unchanged — it still reads "Admin" everywhere in the UI.
|
||||||
|
|
||||||
|
Two consequences worth remembering:
|
||||||
|
|
||||||
|
- **`ROLE_ADMINISTRATIVE` is a different role and was not renamed.** It is granted only by
|
||||||
|
the hierarchy, never stored, and it shares the old `ROLE_ADMIN` prefix — so any
|
||||||
|
search-and-replace over role names must match on a word boundary
|
||||||
|
(`ROLE_TEAM_ADMIN(?![A-Z_])`) or it will corrupt ~100 call sites silently.
|
||||||
|
- **`ELIGIBLE_ROLES` in `MyEpAuthenticator` is a wire contract**, not an internal name: it is
|
||||||
|
compared directly against the IdP's `roles` claim. It only works while MyE&P emits
|
||||||
|
`ROLE_TEAM_ADMIN`, so the two sides have to move together.
|
||||||
|
|
||||||
`User::PENDING_ROLES` holds a marker for each of the three administrative roles, keyed by
|
`User::PENDING_ROLES` holds a marker for each of the three administrative roles, keyed by
|
||||||
the role it stands for:
|
the role it stands for:
|
||||||
|
|
||||||
| Marker | Meaning |
|
| Marker | Meaning |
|
||||||
|--------|---------|
|
|--------|---------|
|
||||||
| `ROLE_ADMIN_PENDING` | the CRM claims this person is an admin, nobody has confirmed it |
|
| `ROLE_TEAM_ADMIN_PENDING` | the CRM claims this person is an admin, nobody has confirmed it |
|
||||||
| `ROLE_MANAGER_PENDING` | likewise for Reisemanager |
|
| `ROLE_MANAGER_PENDING` | likewise for Reisemanager |
|
||||||
| `ROLE_HOUSE_MANAGER_PENDING` | likewise for Hausleitung |
|
| `ROLE_HOUSE_MANAGER_PENDING` | likewise for Hausleitung |
|
||||||
|
|
||||||
@@ -50,10 +68,10 @@ effects are cosmetic (rendered as "Admin (nicht freigeschaltet)") and organisati
|
|||||||
put the user on the approval list). `ROLE_TEAMER` has no marker: it needs no approval.
|
put the user on the approval list). `ROLE_TEAMER` has no marker: it needs no approval.
|
||||||
|
|
||||||
Two further roles are synthesized by `User::getRoles()` and never stored: `ROLE_USER` for
|
Two further roles are synthesized by `User::getRoles()` and never stored: `ROLE_USER` for
|
||||||
everybody, and `ROLE_SUPER_ADMIN` when the separate `superAdmin` boolean column is set. A
|
everybody, and `ROLE_TEAM_SUPER_ADMIN` when the separate `superAdmin` boolean column is set. A
|
||||||
validation callback (`User::validateSuperAdmin()`) refuses `superAdmin` without
|
validation callback (`User::validateSuperAdmin()`) refuses `superAdmin` without
|
||||||
`ROLE_ADMIN` alongside it — super admin is an elevation, never a standalone grant. The sync
|
`ROLE_TEAM_ADMIN` alongside it — super admin is an elevation, never a standalone grant. The sync
|
||||||
enforces the same rule from the other side: revoking `ROLE_ADMIN` clears the flag, or the one
|
enforces the same rule from the other side: revoking `ROLE_TEAM_ADMIN` clears the flag, or the one
|
||||||
role that outranks every check in the application would outlive the role it depends on.
|
role that outranks every check in the application would outlive the role it depends on.
|
||||||
|
|
||||||
### Storage and accessors
|
### Storage and accessors
|
||||||
@@ -63,7 +81,7 @@ slice it, and picking the right one matters:
|
|||||||
|
|
||||||
| Accessor | Returns |
|
| Accessor | Returns |
|
||||||
|----------|---------|
|
|----------|---------|
|
||||||
| `getRoles()` | the column **plus** synthesized `ROLE_USER` / `ROLE_SUPER_ADMIN` — what Symfony authorises against |
|
| `getRoles()` | the column **plus** synthesized `ROLE_USER` / `ROLE_TEAM_SUPER_ADMIN` — what Symfony authorises against |
|
||||||
| `getAssignedRoles()` | only the four real roles from the column — what the sync works on |
|
| `getAssignedRoles()` | only the four real roles from the column — what the sync works on |
|
||||||
| `getPendingRoles()` | only the markers |
|
| `getPendingRoles()` | only the markers |
|
||||||
| `getNominatedRoles()` | the roles behind those markers, as `role => label` — what an approver acts on |
|
| `getNominatedRoles()` | the roles behind those markers, as `role => label` — what an approver acts on |
|
||||||
@@ -77,7 +95,7 @@ slice it, and picking the right one matters:
|
|||||||
|
|
||||||
| CRM attribute | Recognised by | Sets |
|
| CRM attribute | Recognised by | Sets |
|
||||||
|---------------|---------------|------|
|
|---------------|---------------|------|
|
||||||
| admin | attribute id `%bpn_crm_id_admin%`, selected | `isAdmin` |
|
| admin | attribute id `%bpn_crm_id_team_admin%`, selected | `isAdmin` |
|
||||||
| Reisemanager | attribute id `%bpn_crm_id_manager%`, selected | `isManager` |
|
| Reisemanager | attribute id `%bpn_crm_id_manager%`, selected | `isManager` |
|
||||||
| teamer | attribute id `%bpn_crm_id_teamer%`, selected | `isTeamer` |
|
| teamer | attribute id `%bpn_crm_id_teamer%`, selected | `isTeamer` |
|
||||||
| Hausleitung | attribute id listed in `%bpn_crm_house_manager_ids%`, selected | `isHouseManager` + the hotel code that id maps to |
|
| Hausleitung | attribute id listed in `%bpn_crm_house_manager_ids%`, selected | `isHouseManager` + the hotel code that id maps to |
|
||||||
@@ -111,12 +129,26 @@ roles were revoked.
|
|||||||
>
|
>
|
||||||
> | Parameter | Attribute |
|
> | Parameter | Attribute |
|
||||||
> |-----------|-----------|
|
> |-----------|-----------|
|
||||||
> | `APP_BPN_CRM_ID_ADMIN` | `Admin` |
|
> | `APP_BPN_CRM_ID_TEAM_ADMIN` | the team-admin selection — **not** the old portal-wide `Admin` (1292) |
|
||||||
> | `APP_BPN_CRM_ID_MANAGER` | `Manager` |
|
> | `APP_BPN_CRM_ID_MANAGER` | `Manager` |
|
||||||
> | `APP_BPN_CRM_ID_TEAMER` | `E&P Teamer - allg. Merkmal` |
|
> | `APP_BPN_CRM_ID_TEAMER` | `E&P Teamer - allg. Merkmal` |
|
||||||
>
|
>
|
||||||
> Matching is by id and never by label, so `Preisrechner Admin` does not trip the admin flag.
|
> Matching is by id and never by label, so `Preisrechner Admin` does not trip the admin flag.
|
||||||
>
|
>
|
||||||
|
> `APP_BPN_CRM_ID_TEAM_ADMIN` was renamed from `APP_BPN_CRM_ID_ADMIN` with the
|
||||||
|
> `ROLE_TEAM_ADMIN` rename, and its **value has to change too**. The old value 1292 is the
|
||||||
|
> portal-wide admin selection, which still means `ROLE_ADMIN` in the sibling portal — keeping
|
||||||
|
> it would have left this app granting its admin off the very selection the rename was meant
|
||||||
|
> to stop sharing. It ships as `0` — a valid int that matches no attribute, so the container
|
||||||
|
> boots but nobody is granted the role — and must be set to the new selection's id.
|
||||||
|
>
|
||||||
|
> **This is a hard cutover.** `revokeUnclaimedRoles()` withdraws any granted role the CRM no
|
||||||
|
> longer claims, and `revokeSuperAdminWithoutRoleAdmin()` takes the super admin flag down with
|
||||||
|
> `ROLE_TEAM_ADMIN`. So the new selection must exist **and already be assigned to every admin**
|
||||||
|
> in BusPro before this is deployed; otherwise each of them is demoted on their next login and
|
||||||
|
> needs a super admin to re-approve. Admins who also hold `ROLE_TEAMER` degrade to teamer
|
||||||
|
> access; an admin without it is blocked outright by `disableForRevokedCrmRoles()`.
|
||||||
|
>
|
||||||
> `bpn_crm_house_manager_ids` (`config/services.yaml`) is deployment-critical for the same
|
> `bpn_crm_house_manager_ids` (`config/services.yaml`) is deployment-critical for the same
|
||||||
> reason, and more sharply so: since roles are synced, an id missing from that map does not
|
> reason, and more sharply so: since roles are synced, an id missing from that map does not
|
||||||
> merely fail to nominate a Hausleitung, it **revokes** the role from everyone holding it, one
|
> merely fail to nominate a Hausleitung, it **revokes** the role from everyone holding it, one
|
||||||
@@ -137,7 +169,7 @@ roles were revoked.
|
|||||||
`BpnAuthenticator::getOrCreateLocalUser()` → `UserDataHandler::createLocalUser()` writes
|
`BpnAuthenticator::getOrCreateLocalUser()` → `UserDataHandler::createLocalUser()` writes
|
||||||
`collectRoles()` verbatim, together with the hotel codes from the Hausleitung attributes.
|
`collectRoles()` verbatim, together with the hotel codes from the Hausleitung attributes.
|
||||||
|
|
||||||
A CRM admin who is not also a teamer therefore starts with `['ROLE_ADMIN_PENDING']` and no
|
A CRM admin who is not also a teamer therefore starts with `['ROLE_TEAM_ADMIN_PENDING']` and no
|
||||||
privileges at all: they can authenticate, but `UserChecker` refuses the session until a
|
privileges at all: they can authenticate, but `UserChecker` refuses the session until a
|
||||||
super admin approves them.
|
super admin approves them.
|
||||||
|
|
||||||
@@ -148,7 +180,7 @@ the roles to **`syncRoles()`**, which is the whole policy in four steps:
|
|||||||
|
|
||||||
1. **revoke** every granted role the CRM no longer claims. This is what makes BusPro the
|
1. **revoke** every granted role the CRM no longer claims. This is what makes BusPro the
|
||||||
source of truth, and it applies to `ROLE_TEAMER` as much as to the administrative roles.
|
source of truth, and it applies to `ROLE_TEAMER` as much as to the administrative roles.
|
||||||
2. **clear the super admin flag** when `ROLE_ADMIN` was among them — `ROLE_SUPER_ADMIN` is
|
2. **clear the super admin flag** when `ROLE_TEAM_ADMIN` was among them — `ROLE_TEAM_SUPER_ADMIN` is
|
||||||
synthesized from a separate column and would otherwise survive its own precondition.
|
synthesized from a separate column and would otherwise survive its own precondition.
|
||||||
3. **`refreshPendingRoles()`** recomputes the marker set from the current claims. A marker
|
3. **`refreshPendingRoles()`** recomputes the marker set from the current claims. A marker
|
||||||
whose real role is already granted is dropped — an approved role is never marked again.
|
whose real role is already granted is dropped — an approved role is never marked again.
|
||||||
@@ -189,7 +221,7 @@ runs again on submit to catch a sync that revoked the claim while the dialog was
|
|||||||
A denial is not recorded anywhere: as long as the CRM keeps claiming the role, the
|
A denial is not recorded anywhere: as long as the CRM keeps claiming the role, the
|
||||||
nomination is back on the next login.
|
nomination is back on the next login.
|
||||||
|
|
||||||
**Super admin** is only offered to somebody who already holds `ROLE_ADMIN` — approve first,
|
**Super admin** is only offered to somebody who already holds `ROLE_TEAM_ADMIN` — approve first,
|
||||||
elevate afterwards. The one exception is a flag that outlived its role, which stays editable
|
elevate afterwards. The one exception is a flag that outlived its role, which stays editable
|
||||||
so the account can be saved at all while `User::validateSuperAdmin()` is violated; the sync
|
so the account can be saved at all while `User::validateSuperAdmin()` is violated; the sync
|
||||||
clears it (see 2), so it should never occur in practice.
|
clears it (see 2), so it should never occur in practice.
|
||||||
@@ -243,7 +275,7 @@ administrative users, teamers are an admin's business:
|
|||||||
|
|
||||||
| Surface | Who | Notes |
|
| Surface | Who | Notes |
|
||||||
|---------|-----|-------|
|
|---------|-----|-------|
|
||||||
| `/admin/teamer/disable-user/{uuid}` and `/administrative/teamer/enable-user/{uuid}` | `ROLE_ADMIN` | teamers; public reason mandatory, internal optional |
|
| `/admin/teamer/disable-user/{uuid}` and `/administrative/teamer/enable-user/{uuid}` | `ROLE_TEAM_ADMIN` | teamers; public reason mandatory, internal optional |
|
||||||
| "Account gesperrt" checkbox on the user edit form | super admin (`UserVoter`) | everyone else; both reasons optional |
|
| "Account gesperrt" checkbox on the user edit form | super admin (`UserVoter`) | everyone else; both reasons optional |
|
||||||
|
|
||||||
Both go through `User::setDisabled()`, which is a no-op when the state is unchanged — saving
|
Both go through `User::setDisabled()`, which is a no-op when the state is unchanged — saving
|
||||||
|
|||||||
@@ -162,17 +162,36 @@ class ApiClient
|
|||||||
$this->config['max_retries']
|
$this->config['max_retries']
|
||||||
);
|
);
|
||||||
$this->send($socket, $body);
|
$this->send($socket, $body);
|
||||||
$response = $this->receive($socket);
|
|
||||||
$this->disconnect($socket);
|
|
||||||
|
|
||||||
// message length (10 bytes) is prepended to actual message
|
try {
|
||||||
$xml = substr($response, 10);
|
// the length header is consumed by receive(), this is the payload
|
||||||
|
$xml = $this->receive($socket);
|
||||||
|
} finally {
|
||||||
|
$this->disconnect($socket);
|
||||||
|
}
|
||||||
|
|
||||||
if (true === $this->config['debug']) {
|
if (true === $this->config['debug']) {
|
||||||
$this->dumpXmlToFile('response', $requestId, $xml);
|
$this->dumpXmlToFile('response', $requestId, $xml);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->responseParser->parseXmlString($type, $xml);
|
try {
|
||||||
|
return $this->responseParser->parseXmlString($type, $xml);
|
||||||
|
} catch (ResponseParserException $e) {
|
||||||
|
// Keep the evidence even outside debug mode: without the raw response a parse
|
||||||
|
// failure is not diagnosable after the fact. app:cleanup:xml-dumps prunes it.
|
||||||
|
if (true !== $this->config['debug']) {
|
||||||
|
$this->dumpXmlToFile('response', $requestId, $xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger->error('Unable to parse BusProNet response', [
|
||||||
|
'request_id' => $requestId,
|
||||||
|
'type' => $type,
|
||||||
|
'response_length' => strlen($xml),
|
||||||
|
'error_message' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function dumpXmlToFile(string $type, string $requestId, string $body): void
|
private function dumpXmlToFile(string $type, string $requestId, string $body): void
|
||||||
|
|||||||
@@ -58,15 +58,58 @@ trait ApiClientTrait
|
|||||||
fwrite($socket, $send);
|
fwrite($socket, $send);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a single response message. The protocol prepends the payload length as a
|
||||||
|
* 10 byte header, so read exactly that many bytes rather than guessing at EOF:
|
||||||
|
* a peer that closes mid-stream would otherwise yield a silently truncated body.
|
||||||
|
*
|
||||||
|
* @throws ApiClientException
|
||||||
|
*/
|
||||||
private function receive($socket): string
|
private function receive($socket): string
|
||||||
{
|
{
|
||||||
$response = '';
|
$header = $this->readBytes($socket, 10);
|
||||||
|
|
||||||
while (false === feof($socket)) {
|
if (10 !== strlen($header)) {
|
||||||
$response .= fread($socket, 4096);
|
throw new ApiClientException(sprintf('Incomplete response header, got %d of 10 bytes', strlen($header)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response;
|
$expectedLength = (int) trim($header);
|
||||||
|
|
||||||
|
if (1 > $expectedLength) {
|
||||||
|
throw new ApiClientException(sprintf('Response announced an empty body (header "%s")', trim($header)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = $this->readBytes($socket, $expectedLength);
|
||||||
|
|
||||||
|
if (strlen($body) !== $expectedLength) {
|
||||||
|
throw new ApiClientException(sprintf('Truncated response, got %d of %d announced bytes', strlen($body), $expectedLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ApiClientException
|
||||||
|
*/
|
||||||
|
private function readBytes($socket, int $length): string
|
||||||
|
{
|
||||||
|
$buffer = '';
|
||||||
|
|
||||||
|
while (strlen($buffer) < $length && false === feof($socket)) {
|
||||||
|
$chunk = fread($socket, min(4096, $length - strlen($buffer)));
|
||||||
|
|
||||||
|
if (false === $chunk || '' === $chunk) {
|
||||||
|
if (true === (stream_get_meta_data($socket)['timed_out'] ?? false)) {
|
||||||
|
throw new ApiClientException(sprintf('Timed out reading response after %d of %d bytes', strlen($buffer), $length));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$buffer .= $chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function disconnect($socket): void
|
private function disconnect($socket): void
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\BusProNet\ApiClient;
|
|||||||
use App\BusProNet\ApiClientException;
|
use App\BusProNet\ApiClientException;
|
||||||
use App\BusProNet\Model\Country;
|
use App\BusProNet\Model\Country;
|
||||||
use App\BusProNet\Model\NotificationResponse;
|
use App\BusProNet\Model\NotificationResponse;
|
||||||
|
use App\BusProNet\ResponseParserException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Contracts\Cache\CacheInterface;
|
use Symfony\Contracts\Cache\CacheInterface;
|
||||||
use Symfony\Contracts\Cache\ItemInterface;
|
use Symfony\Contracts\Cache\ItemInterface;
|
||||||
@@ -35,7 +36,8 @@ class CountryDataProvider
|
|||||||
|
|
||||||
return $response->getItems();
|
return $response->getItems();
|
||||||
});
|
});
|
||||||
} catch (ApiClientException $e) {
|
} catch (ApiClientException|ResponseParserException $e) {
|
||||||
|
$this->logger->error('Unable to fetch country base data from BusProNet: '.$e->getMessage());
|
||||||
$countries = [];
|
$countries = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\BusProNet\ApiClient;
|
|||||||
use App\BusProNet\ApiClientException;
|
use App\BusProNet\ApiClientException;
|
||||||
use App\BusProNet\Model\Hotel;
|
use App\BusProNet\Model\Hotel;
|
||||||
use App\BusProNet\Model\NotificationResponse;
|
use App\BusProNet\Model\NotificationResponse;
|
||||||
|
use App\BusProNet\ResponseParserException;
|
||||||
use Psr\Cache\InvalidArgumentException;
|
use Psr\Cache\InvalidArgumentException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Contracts\Cache\CacheInterface;
|
use Symfony\Contracts\Cache\CacheInterface;
|
||||||
@@ -36,7 +37,8 @@ class HotelDataProvider
|
|||||||
|
|
||||||
return $response->getItems();
|
return $response->getItems();
|
||||||
});
|
});
|
||||||
} catch (ApiClientException|InvalidArgumentException $e) {
|
} catch (ApiClientException|InvalidArgumentException|ResponseParserException $e) {
|
||||||
|
$this->logger->error('Unable to fetch hotel base data from BusProNet: '.$e->getMessage());
|
||||||
$hotels = [];
|
$hotels = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\BusProNet\ApiClient;
|
|||||||
use App\BusProNet\ApiClientException;
|
use App\BusProNet\ApiClientException;
|
||||||
use App\BusProNet\Model\NotificationResponse;
|
use App\BusProNet\Model\NotificationResponse;
|
||||||
use App\BusProNet\Model\Pickup;
|
use App\BusProNet\Model\Pickup;
|
||||||
|
use App\BusProNet\ResponseParserException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Contracts\Cache\CacheInterface;
|
use Symfony\Contracts\Cache\CacheInterface;
|
||||||
use Symfony\Contracts\Cache\ItemInterface;
|
use Symfony\Contracts\Cache\ItemInterface;
|
||||||
@@ -35,7 +36,8 @@ class PickupDataProvider
|
|||||||
|
|
||||||
return $response->getItems();
|
return $response->getItems();
|
||||||
});
|
});
|
||||||
} catch (ApiClientException $e) {
|
} catch (ApiClientException|ResponseParserException $e) {
|
||||||
|
$this->logger->error('Unable to fetch pickup base data from BusProNet: '.$e->getMessage());
|
||||||
$pickups = [];
|
$pickups = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,10 +30,7 @@ class ResponseParser
|
|||||||
*/
|
*/
|
||||||
public function parseXmlString(string $type, string $content): mixed
|
public function parseXmlString(string $type, string $content): mixed
|
||||||
{
|
{
|
||||||
$xml = simplexml_load_string($content);
|
$xml = $this->loadXml($content);
|
||||||
if (false === $xml) {
|
|
||||||
throw new ResponseParserException('Unable to parse XML response');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override type when present in XML to catch error responses
|
// Override type when present in XML to catch error responses
|
||||||
$responseType = $type;
|
$responseType = $type;
|
||||||
@@ -65,7 +62,7 @@ class ResponseParser
|
|||||||
return $this->createHotelsResponse($xml);
|
return $this->createHotelsResponse($xml);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ResponseParserException('Unable to parse XML response');
|
throw new ResponseParserException(sprintf('Unrecognised BusProNet response type "%s"', $responseType));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createNotificationResponse(\SimpleXMLElement $xml): NotificationResponse
|
public function createNotificationResponse(\SimpleXMLElement $xml): NotificationResponse
|
||||||
@@ -200,7 +197,7 @@ class ResponseParser
|
|||||||
$isHouseManager = true;
|
$isHouseManager = true;
|
||||||
$hotelCodes[] = $houseManagerCode;
|
$hotelCodes[] = $houseManagerCode;
|
||||||
}
|
}
|
||||||
if ($this->config['bpn_crm_id_admin'] === $attribute->getId() && true === $attribute->isSelected()) {
|
if ($this->config['bpn_crm_id_team_admin'] === $attribute->getId() && true === $attribute->isSelected()) {
|
||||||
$isAdmin = true;
|
$isAdmin = true;
|
||||||
}
|
}
|
||||||
if ($this->config['bpn_crm_id_manager'] === $attribute->getId() && true === $attribute->isSelected()) {
|
if ($this->config['bpn_crm_id_manager'] === $attribute->getId() && true === $attribute->isSelected()) {
|
||||||
@@ -302,14 +299,58 @@ class ResponseParser
|
|||||||
return new BaseDataResponse($hotels);
|
return new BaseDataResponse($hotels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The BusProNet endpoint can answer with an empty or truncated body. Keep the libxml
|
||||||
|
* reason instead of collapsing every shape of broken response into one message.
|
||||||
|
*
|
||||||
|
* @throws ResponseParserException
|
||||||
|
*/
|
||||||
|
private function loadXml(string $content): \SimpleXMLElement
|
||||||
|
{
|
||||||
|
if ('' === trim($content)) {
|
||||||
|
throw new ResponseParserException(sprintf('Unable to parse XML response (%d bytes): empty response', strlen($content)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$previousUseErrors = libxml_use_internal_errors(true);
|
||||||
|
libxml_clear_errors();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$xml = simplexml_load_string($content);
|
||||||
|
|
||||||
|
if (false === $xml) {
|
||||||
|
throw new ResponseParserException(sprintf('Unable to parse XML response (%d bytes): %s', strlen($content), $this->describeLibxmlErrors()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $xml;
|
||||||
|
} finally {
|
||||||
|
libxml_clear_errors();
|
||||||
|
libxml_use_internal_errors($previousUseErrors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function describeLibxmlErrors(): string
|
||||||
|
{
|
||||||
|
$messages = [];
|
||||||
|
|
||||||
|
foreach (libxml_get_errors() as $error) {
|
||||||
|
$messages[] = sprintf('%s (line %d, column %d)', trim($error->message), $error->line, $error->column);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([] === $messages) {
|
||||||
|
return 'unknown XML error';
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode('; ', array_unique($messages));
|
||||||
|
}
|
||||||
|
|
||||||
private function resolveOptions(array $options): array
|
private function resolveOptions(array $options): array
|
||||||
{
|
{
|
||||||
$optionsResolver = new OptionsResolver();
|
$optionsResolver = new OptionsResolver();
|
||||||
$optionsResolver->setRequired(['bpn_crm_id_admin', 'bpn_crm_id_manager', 'bpn_crm_id_teamer', 'bpn_crm_house_manager_ids']);
|
$optionsResolver->setRequired(['bpn_crm_id_team_admin', 'bpn_crm_id_manager', 'bpn_crm_id_teamer', 'bpn_crm_house_manager_ids']);
|
||||||
$optionsResolver->setDefaults([
|
$optionsResolver->setDefaults([
|
||||||
'bpn_default_hotel_code' => null,
|
'bpn_default_hotel_code' => null,
|
||||||
]);
|
]);
|
||||||
$optionsResolver->setAllowedTypes('bpn_crm_id_admin', 'int');
|
$optionsResolver->setAllowedTypes('bpn_crm_id_team_admin', 'int');
|
||||||
$optionsResolver->setAllowedTypes('bpn_crm_id_manager', 'int');
|
$optionsResolver->setAllowedTypes('bpn_crm_id_manager', 'int');
|
||||||
$optionsResolver->setAllowedTypes('bpn_crm_id_teamer', 'int');
|
$optionsResolver->setAllowedTypes('bpn_crm_id_teamer', 'int');
|
||||||
$optionsResolver->setAllowedTypes('bpn_crm_house_manager_ids', 'array');
|
$optionsResolver->setAllowedTypes('bpn_crm_house_manager_ids', 'array');
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class UserDataHandler
|
|||||||
$claimedRoles = [];
|
$claimedRoles = [];
|
||||||
|
|
||||||
if ($crmAttributes->isAdmin()) {
|
if ($crmAttributes->isAdmin()) {
|
||||||
$claimedRoles[] = 'ROLE_ADMIN';
|
$claimedRoles[] = 'ROLE_TEAM_ADMIN';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($crmAttributes->isManager()) {
|
if ($crmAttributes->isManager()) {
|
||||||
@@ -370,7 +370,7 @@ class UserDataHandler
|
|||||||
* The whole policy, in the order it has to run:
|
* The whole policy, in the order it has to run:
|
||||||
*
|
*
|
||||||
* 1. revoke what is no longer claimed - the identity source leads;
|
* 1. revoke what is no longer claimed - the identity source leads;
|
||||||
* 2. drop the super admin flag along with ROLE_ADMIN, or the highest privilege in the
|
* 2. drop the super admin flag along with ROLE_TEAM_ADMIN, or the highest privilege in the
|
||||||
* application would outlive the role it depends on;
|
* application would outlive the role it depends on;
|
||||||
* 3. refresh the pending markers, after the revocation so that a role just revoked is
|
* 3. refresh the pending markers, after the revocation so that a role just revoked is
|
||||||
* not immediately marked again - it is unclaimed in both steps;
|
* not immediately marked again - it is unclaimed in both steps;
|
||||||
@@ -424,7 +424,7 @@ class UserDataHandler
|
|||||||
*
|
*
|
||||||
* Only the roles of User::ROLES are touched: getAssignedRoles() excludes the pending
|
* Only the roles of User::ROLES are touched: getAssignedRoles() excludes the pending
|
||||||
* markers as well as the implicit ROLE_USER, and the markers are dealt with by
|
* markers as well as the implicit ROLE_USER, and the markers are dealt with by
|
||||||
* refreshPendingRoles(). ROLE_SUPER_ADMIN is not a stored role at all but a flag, so
|
* refreshPendingRoles(). ROLE_TEAM_SUPER_ADMIN is not a stored role at all but a flag, so
|
||||||
* it is handled separately below.
|
* it is handled separately below.
|
||||||
*
|
*
|
||||||
* @param string[] $claimedRoles
|
* @param string[] $claimedRoles
|
||||||
@@ -450,22 +450,22 @@ class UserDataHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the super admin flag down with ROLE_ADMIN.
|
* Takes the super admin flag down with ROLE_TEAM_ADMIN.
|
||||||
*
|
*
|
||||||
* The flag is stored on its own and getRoles() turns it into ROLE_SUPER_ADMIN whatever
|
* The flag is stored on its own and getRoles() turns it into ROLE_TEAM_SUPER_ADMIN whatever
|
||||||
* else the user holds, so without this a person the CRM no longer calls an admin would
|
* else the user holds, so without this a person the CRM no longer calls an admin would
|
||||||
* keep the one role that outranks every check in the application. User::validateSuperAdmin()
|
* keep the one role that outranks every check in the application. User::validateSuperAdmin()
|
||||||
* enforces the same rule on the edit form, but only there.
|
* enforces the same rule on the edit form, but only there.
|
||||||
*/
|
*/
|
||||||
private function revokeSuperAdminWithoutRoleAdmin(User $user): void
|
private function revokeSuperAdminWithoutRoleAdmin(User $user): void
|
||||||
{
|
{
|
||||||
if (false === $user->isSuperAdmin() || true === $user->hasRole('ROLE_ADMIN')) {
|
if (false === $user->isSuperAdmin() || true === $user->hasRole('ROLE_TEAM_ADMIN')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->setSuperAdmin(false);
|
$user->setSuperAdmin(false);
|
||||||
|
|
||||||
$this->logger->info('Revoke super admin flag along with ROLE_ADMIN', [
|
$this->logger->info('Revoke super admin flag along with ROLE_TEAM_ADMIN', [
|
||||||
'user_id' => $user->getId(),
|
'user_id' => $user->getId(),
|
||||||
'user_email' => $user->getEmail(),
|
'user_email' => $user->getEmail(),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -56,11 +56,30 @@ class BpnImportCommand extends Command
|
|||||||
return Command::FAILURE;
|
return Command::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve the BusProNet base data once, before touching a single row. A destination
|
||||||
|
// cannot be written without its hotel, so an unavailable hotel list would otherwise
|
||||||
|
// skip every record and still report success. Holding both lists locally also keeps
|
||||||
|
// the loop off the providers: on a failed fetch nothing is cached, and a per-lookup
|
||||||
|
// ->get() would re-open the socket for every pickup of all 174 files.
|
||||||
|
$hotels = $this->hotelDataProvider->getAll();
|
||||||
|
$pickups = $this->pickupDataProvider->getAll();
|
||||||
|
|
||||||
|
if ([] === $hotels) {
|
||||||
|
$io->error('Hotel-Stammdaten konnten nicht von BusProNet geladen werden – Import abgebrochen.');
|
||||||
|
$this->logger->error('BPN import aborted: hotel base data unavailable');
|
||||||
|
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
$io->info('Found '.$totalCount.' XML files');
|
$io->info('Found '.$totalCount.' XML files');
|
||||||
$addedCount = 0;
|
$addedCount = 0;
|
||||||
$updatedCount = 0;
|
$updatedCount = 0;
|
||||||
$warnings = [];
|
$warnings = [];
|
||||||
|
|
||||||
|
if ([] === $pickups) {
|
||||||
|
$warnings[] = 'Zustiegs-Stammdaten konnten nicht von BusProNet geladen werden';
|
||||||
|
}
|
||||||
|
|
||||||
$progressBar = $io->createProgressBar($totalCount);
|
$progressBar = $io->createProgressBar($totalCount);
|
||||||
$progressBar->setFormat(" %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%\n %message%");
|
$progressBar->setFormat(" %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%\n %message%");
|
||||||
$progressBar->setMessage('Starting');
|
$progressBar->setMessage('Starting');
|
||||||
@@ -92,7 +111,7 @@ class BpnImportCommand extends Command
|
|||||||
foreach ($destinationXml->xpath('zustiege/zustieg') as $pickupXml) {
|
foreach ($destinationXml->xpath('zustiege/zustieg') as $pickupXml) {
|
||||||
$pickupBusProId = (int) $pickupXml->attributes()['idbuspro'];
|
$pickupBusProId = (int) $pickupXml->attributes()['idbuspro'];
|
||||||
if ($pickupBusProId) {
|
if ($pickupBusProId) {
|
||||||
if (null === $pickup = $this->pickupDataProvider->get($pickupBusProId)) {
|
if (null === $pickup = $pickups[$pickupBusProId] ?? null) {
|
||||||
$warnings[] = 'Pickup with busProId '.$pickupBusProId.' not found';
|
$warnings[] = 'Pickup with busProId '.$pickupBusProId.' not found';
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -109,7 +128,7 @@ class BpnImportCommand extends Command
|
|||||||
// Iterate over all hotel entries
|
// Iterate over all hotel entries
|
||||||
foreach ($destinationXml->xpath('hotel') as $hotelXml) {
|
foreach ($destinationXml->xpath('hotel') as $hotelXml) {
|
||||||
$hotelBusProId = (int) $hotelXml->attributes()['idbuspro'];
|
$hotelBusProId = (int) $hotelXml->attributes()['idbuspro'];
|
||||||
if (null === $hotel = $this->hotelDataProvider->get($hotelBusProId)) {
|
if (null === $hotel = $hotels[$hotelBusProId] ?? null) {
|
||||||
$warnings[] = 'Hotel with busProId '.$hotelBusProId.' not found';
|
$warnings[] = 'Hotel with busProId '.$hotelBusProId.' not found';
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,10 +91,8 @@ class TeamerStatusCommand extends Command
|
|||||||
$qb->expr()->eq('disposition.status', ':disposition_status')
|
$qb->expr()->eq('disposition.status', ':disposition_status')
|
||||||
))
|
))
|
||||||
->groupBy('teamer.id')
|
->groupBy('teamer.id')
|
||||||
->setParameters([
|
->setParameter('teamer_status', Teamer::STATUS_NEW)
|
||||||
'teamer_status' => Teamer::STATUS_NEW,
|
->setParameter('disposition_status', Disposition::STATUS_COMPLETED)
|
||||||
'disposition_status' => Disposition::STATUS_COMPLETED,
|
|
||||||
])
|
|
||||||
->getQuery()
|
->getQuery()
|
||||||
->getResult()
|
->getResult()
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class UserController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/autocomplete/user', name: 'app_admin_autocomplete_user')]
|
#[Route('/admin/autocomplete/user', name: 'app_admin_autocomplete_user')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Request $request): JsonResponse
|
public function index(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class ApproveController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/feedback/approve/{uuid}', name: 'app_admin_feedback_approve')]
|
#[Route('/admin/feedback/approve/{uuid}', name: 'app_admin_feedback_approve')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Feedback $feedback, Request $request): Response
|
public function index(Feedback $feedback, Request $request): Response
|
||||||
{
|
{
|
||||||
$form = $this->createForm(FeedbackApproveType::class, $feedback);
|
$form = $this->createForm(FeedbackApproveType::class, $feedback);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class ProvideController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/feedback/provide', name: 'app_admin_feedback_provide')]
|
#[Route('/admin/feedback/provide', name: 'app_admin_feedback_provide')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$form = $this->getFeedbackForm();
|
$form = $this->getFeedbackForm();
|
||||||
@@ -58,7 +58,7 @@ class ProvideController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/feedback/provide/form', name: 'app_admin_feedback_provide_form')]
|
#[Route('/admin/feedback/provide/form', name: 'app_admin_feedback_provide_form')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function form(Request $request): Response
|
public function form(Request $request): Response
|
||||||
{
|
{
|
||||||
$form = $this->getFeedbackForm();
|
$form = $this->getFeedbackForm();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class IndexController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin', name: 'app_admin_index')]
|
#[Route('/admin', name: 'app_admin_index')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
$applicationRepository = $this->entityManager->getRepository(Application::class);
|
$applicationRepository = $this->entityManager->getRepository(Application::class);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class IndexController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/log', name: 'app_admin_log_index')]
|
#[Route('/admin/log', name: 'app_admin_log_index')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$qb = $this
|
$qb = $this
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class CreateController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/availability/create', name: 'app_admin_system_availability_create')]
|
#[Route('/admin/system/availability/create', name: 'app_admin_system_availability_create')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$availability = new Availability();
|
$availability = new Availability();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class DeleteController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/availability/delete/{id}', name: 'app_admin_system_availability_delete', methods: ['POST'])]
|
#[Route('/admin/system/availability/delete/{id}', name: 'app_admin_system_availability_delete', methods: ['POST'])]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Availability $availability, Request $request): Response
|
public function index(Availability $availability, Request $request): Response
|
||||||
{
|
{
|
||||||
if (true === $request->isMethod('POST')) {
|
if (true === $request->isMethod('POST')) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class DuplicateController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/availability/duplicate/{id}', name: 'app_admin_system_availability_duplicate')]
|
#[Route('/admin/system/availability/duplicate/{id}', name: 'app_admin_system_availability_duplicate')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Availability $availability, Request $request): Response
|
public function index(Availability $availability, Request $request): Response
|
||||||
{
|
{
|
||||||
$copy = Availability::duplicate($availability);
|
$copy = Availability::duplicate($availability);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class EditController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/availability/edit/{id}', name: 'app_admin_system_availability_edit')]
|
#[Route('/admin/system/availability/edit/{id}', name: 'app_admin_system_availability_edit')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Availability $availability, Request $request): Response
|
public function index(Availability $availability, Request $request): Response
|
||||||
{
|
{
|
||||||
$form = $this->createForm(AvailabilityType::class, $availability);
|
$form = $this->createForm(AvailabilityType::class, $availability);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class IndexController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/availability', name: 'app_admin_system_availability_index')]
|
#[Route('/admin/system/availability', name: 'app_admin_system_availability_index')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$query = $this
|
$query = $this
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class EditController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/email-text/edit/{key}', name: 'app_admin_system_email_text_edit')]
|
#[Route('/admin/system/email-text/edit/{key}', name: 'app_admin_system_email_text_edit')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(EmailTextKey $key, Request $request): Response
|
public function index(EmailTextKey $key, Request $request): Response
|
||||||
{
|
{
|
||||||
$definition = $this->catalog->get($key);
|
$definition = $this->catalog->get($key);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class IndexController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/email-text', name: 'app_admin_system_email_text_index')]
|
#[Route('/admin/system/email-text', name: 'app_admin_system_email_text_index')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
// The list is driven by the catalogue, not by the table: a mail that has never
|
// The list is driven by the catalogue, not by the table: a mail that has never
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class PreviewController extends AbstractController
|
|||||||
* a real mail is being assembled.
|
* a real mail is being assembled.
|
||||||
*/
|
*/
|
||||||
#[Route('/admin/system/email-text/preview/{key}', name: 'app_admin_system_email_text_preview')]
|
#[Route('/admin/system/email-text/preview/{key}', name: 'app_admin_system_email_text_preview')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(EmailTextKey $key): Response
|
public function index(EmailTextKey $key): Response
|
||||||
{
|
{
|
||||||
$definition = $this->catalog->get($key);
|
$definition = $this->catalog->get($key);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class PreviewDraftController extends AbstractController
|
|||||||
* the submitted values instead of the stored ones.
|
* the submitted values instead of the stored ones.
|
||||||
*/
|
*/
|
||||||
#[Route('/admin/system/email-text/preview-draft/{key}', name: 'app_admin_system_email_text_preview_draft', methods: ['POST'])]
|
#[Route('/admin/system/email-text/preview-draft/{key}', name: 'app_admin_system_email_text_preview_draft', methods: ['POST'])]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(EmailTextKey $key, Request $request): Response
|
public function index(EmailTextKey $key, Request $request): Response
|
||||||
{
|
{
|
||||||
$definition = $this->catalog->get($key);
|
$definition = $this->catalog->get($key);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class ResetController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/email-text/reset/{key}', name: 'app_admin_system_email_text_reset')]
|
#[Route('/admin/system/email-text/reset/{key}', name: 'app_admin_system_email_text_reset')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(EmailTextKey $key, Request $request): Response
|
public function index(EmailTextKey $key, Request $request): Response
|
||||||
{
|
{
|
||||||
$emailText = $this->emailTextRepository->findByKey($key);
|
$emailText = $this->emailTextRepository->findByKey($key);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class CreateController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/fee/create', name: 'app_admin_system_fee_create')]
|
#[Route('/admin/system/fee/create', name: 'app_admin_system_fee_create')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$fee = new Fee();
|
$fee = new Fee();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class DeleteController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/fee/delete/{id}', name: 'app_admin_system_fee_delete')]
|
#[Route('/admin/system/fee/delete/{id}', name: 'app_admin_system_fee_delete')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Fee $fee, Request $request): Response
|
public function index(Fee $fee, Request $request): Response
|
||||||
{
|
{
|
||||||
if (true === $request->isMethod('POST')) {
|
if (true === $request->isMethod('POST')) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class DuplicateController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/fee/duplicate/{id}', name: 'app_admin_system_fee_duplicate')]
|
#[Route('/admin/system/fee/duplicate/{id}', name: 'app_admin_system_fee_duplicate')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Fee $fee, Request $request): Response
|
public function index(Fee $fee, Request $request): Response
|
||||||
{
|
{
|
||||||
$copy = Fee::duplicate($fee);
|
$copy = Fee::duplicate($fee);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class EditController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/fee/edit/{id}', name: 'app_admin_system_fee_edit')]
|
#[Route('/admin/system/fee/edit/{id}', name: 'app_admin_system_fee_edit')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Fee $fee, Request $request): Response
|
public function index(Fee $fee, Request $request): Response
|
||||||
{
|
{
|
||||||
$form = $this->createForm(FeeType::class, $fee);
|
$form = $this->createForm(FeeType::class, $fee);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class IndexController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/fee', name: 'app_admin_system_fee_index')]
|
#[Route('/admin/system/fee', name: 'app_admin_system_fee_index')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
$fees = $this->feeRepository->getList();
|
$fees = $this->feeRepository->getList();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class CreateController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/feedback-set/create', name: 'app_admin_system_feedback_set_create')]
|
#[Route('/admin/system/feedback-set/create', name: 'app_admin_system_feedback_set_create')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$feedbackSet = new FeedbackSet();
|
$feedbackSet = new FeedbackSet();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class DeleteController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/feedback-set/delete/{id}', name: 'app_admin_system_feedback_set_delete')]
|
#[Route('/admin/system/feedback-set/delete/{id}', name: 'app_admin_system_feedback_set_delete')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
#[IsGranted('DELETE', subject: 'feedbackSet')]
|
#[IsGranted('DELETE', subject: 'feedbackSet')]
|
||||||
public function index(FeedbackSet $feedbackSet, Request $request): Response
|
public function index(FeedbackSet $feedbackSet, Request $request): Response
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class EditController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/feedback-set/edit/{id}', name: 'app_admin_system_feedback_set_edit')]
|
#[Route('/admin/system/feedback-set/edit/{id}', name: 'app_admin_system_feedback_set_edit')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(FeedbackSet $feedbackSet, Request $request): Response
|
public function index(FeedbackSet $feedbackSet, Request $request): Response
|
||||||
{
|
{
|
||||||
$form = $this->createForm(FeedbackSetType::class, $feedbackSet);
|
$form = $this->createForm(FeedbackSetType::class, $feedbackSet);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class IndexController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/feedback-set', name: 'app_admin_system_feedback_set_index')]
|
#[Route('/admin/system/feedback-set', name: 'app_admin_system_feedback_set_index')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
$feedbackSets = $this
|
$feedbackSets = $this
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class CreateController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/job-profile/create', name: 'app_admin_system_job_profile_create')]
|
#[Route('/admin/system/job-profile/create', name: 'app_admin_system_job_profile_create')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$jobProfile = new JobProfile();
|
$jobProfile = new JobProfile();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class DeleteController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/job-profile/delete/{id}', name: 'app_admin_system_job_profile_delete')]
|
#[Route('/admin/system/job-profile/delete/{id}', name: 'app_admin_system_job_profile_delete')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(JobProfile $jobProfile, Request $request): Response
|
public function index(JobProfile $jobProfile, Request $request): Response
|
||||||
{
|
{
|
||||||
if (true === $request->isMethod('POST')) {
|
if (true === $request->isMethod('POST')) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class EditController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/job-profile/edit/{id}', name: 'app_admin_system_job_profile_edit')]
|
#[Route('/admin/system/job-profile/edit/{id}', name: 'app_admin_system_job_profile_edit')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(JobProfile $jobProfile, Request $request): Response
|
public function index(JobProfile $jobProfile, Request $request): Response
|
||||||
{
|
{
|
||||||
$form = $this->createForm(JobProfileType::class, $jobProfile);
|
$form = $this->createForm(JobProfileType::class, $jobProfile);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class IndexController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/job-profile', name: 'app_admin_system_job_profile_index')]
|
#[Route('/admin/system/job-profile', name: 'app_admin_system_job_profile_index')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
$jobProfiles = $this
|
$jobProfiles = $this
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class CreateController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/training/create', name: 'app_admin_system_training_create')]
|
#[Route('/admin/system/training/create', name: 'app_admin_system_training_create')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$training = new Training();
|
$training = new Training();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class DeleteController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/training/delete/{id}', name: 'app_admin_system_training_delete')]
|
#[Route('/admin/system/training/delete/{id}', name: 'app_admin_system_training_delete')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Training $training, Request $request): Response
|
public function index(Training $training, Request $request): Response
|
||||||
{
|
{
|
||||||
if (true === $request->isMethod('POST')) {
|
if (true === $request->isMethod('POST')) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class EditController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/training/edit/{id}', name: 'app_admin_system_training_edit')]
|
#[Route('/admin/system/training/edit/{id}', name: 'app_admin_system_training_edit')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Training $training, Request $request): Response
|
public function index(Training $training, Request $request): Response
|
||||||
{
|
{
|
||||||
$form = $this->createForm(TrainingType::class, $training);
|
$form = $this->createForm(TrainingType::class, $training);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class IndexController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/training', name: 'app_admin_system_training_index')]
|
#[Route('/admin/system/training', name: 'app_admin_system_training_index')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
$trainings = $this
|
$trainings = $this
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class IndexController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/system/user', name: 'app_admin_system_user_index')]
|
#[Route('/admin/system/user', name: 'app_admin_system_user_index')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
$users = $this->userRepository->getAdministrativeUsers();
|
$users = $this->userRepository->getAdministrativeUsers();
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
|||||||
class CrmSelectionsController extends AbstractController
|
class CrmSelectionsController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route('/admin/teamer/crm-selections/{uuid}', name: 'app_admin_teamer_crm_selections')]
|
#[Route('/admin/teamer/crm-selections/{uuid}', name: 'app_admin_teamer_crm_selections')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Teamer $teamer): Response
|
public function index(Teamer $teamer): Response
|
||||||
{
|
{
|
||||||
return $this->render('admin/teamer/crm_selections.html.twig', [
|
return $this->render('admin/teamer/crm_selections.html.twig', [
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class DeleteAccountController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/teamer/delete-account/{uuid}', name: 'app_admin_teamer_delete_account')]
|
#[Route('/admin/teamer/delete-account/{uuid}', name: 'app_admin_teamer_delete_account')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Teamer $teamer, Request $request): Response
|
public function index(Teamer $teamer, Request $request): Response
|
||||||
{
|
{
|
||||||
if (true === $request->isMethod(Request::METHOD_POST)) {
|
if (true === $request->isMethod(Request::METHOD_POST)) {
|
||||||
@@ -44,7 +44,7 @@ class DeleteAccountController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/teamer/restore-account/{uuid}', name: 'app_admin_teamer_restore_account')]
|
#[Route('/admin/teamer/restore-account/{uuid}', name: 'app_admin_teamer_restore_account')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function restore(Teamer $teamer, Request $request): Response
|
public function restore(Teamer $teamer, Request $request): Response
|
||||||
{
|
{
|
||||||
if (true === $request->isMethod(Request::METHOD_POST)) {
|
if (true === $request->isMethod(Request::METHOD_POST)) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class DisableUserController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/teamer/disable-user/{uuid}', name: 'app_admin_teamer_disable_user')]
|
#[Route('/admin/teamer/disable-user/{uuid}', name: 'app_admin_teamer_disable_user')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Teamer $teamer, Request $request): Response
|
public function index(Teamer $teamer, Request $request): Response
|
||||||
{
|
{
|
||||||
$user = $teamer->getUser();
|
$user = $teamer->getUser();
|
||||||
@@ -50,7 +50,7 @@ class DisableUserController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/administrative/teamer/enable-user/{uuid}', name: 'app_admin_teamer_enable_user')]
|
#[Route('/administrative/teamer/enable-user/{uuid}', name: 'app_admin_teamer_enable_user')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function enable(Teamer $teamer, Request $request): Response
|
public function enable(Teamer $teamer, Request $request): Response
|
||||||
{
|
{
|
||||||
$user = $teamer->getUser();
|
$user = $teamer->getUser();
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class MailingController extends AbstractController
|
|||||||
* the real send goes through the confirmation modal below.
|
* the real send goes through the confirmation modal below.
|
||||||
*/
|
*/
|
||||||
#[Route('/admin/teamer/mailing', name: 'app_admin_teamer_mailing')]
|
#[Route('/admin/teamer/mailing', name: 'app_admin_teamer_mailing')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$form = $this->createMailingForm($request);
|
$form = $this->createMailingForm($request);
|
||||||
@@ -82,7 +82,7 @@ class MailingController extends AbstractController
|
|||||||
* one that was parked.
|
* one that was parked.
|
||||||
*/
|
*/
|
||||||
#[Route('/admin/teamer/mailing/draft', name: 'app_admin_teamer_mailing_draft', methods: ['POST'])]
|
#[Route('/admin/teamer/mailing/draft', name: 'app_admin_teamer_mailing_draft', methods: ['POST'])]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function draft(Request $request): Response
|
public function draft(Request $request): Response
|
||||||
{
|
{
|
||||||
$mailingDto = $this->createMailingForm($request)->getData();
|
$mailingDto = $this->createMailingForm($request)->getData();
|
||||||
@@ -93,7 +93,7 @@ class MailingController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/teamer/mailing/discard', name: 'app_admin_teamer_mailing_discard')]
|
#[Route('/admin/teamer/mailing/discard', name: 'app_admin_teamer_mailing_discard')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function discard(): Response
|
public function discard(): Response
|
||||||
{
|
{
|
||||||
$this->draftHandler->resetDraft();
|
$this->draftHandler->resetDraft();
|
||||||
@@ -102,7 +102,7 @@ class MailingController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/teamer/mailing/confirm', name: 'app_admin_teamer_mailing_confirm', methods: ['POST'])]
|
#[Route('/admin/teamer/mailing/confirm', name: 'app_admin_teamer_mailing_confirm', methods: ['POST'])]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function confirm(Request $request): Response
|
public function confirm(Request $request): Response
|
||||||
{
|
{
|
||||||
$form = $this->createMailingForm($request);
|
$form = $this->createMailingForm($request);
|
||||||
@@ -119,7 +119,7 @@ class MailingController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/teamer/mailing/send', name: 'app_admin_teamer_mailing_send', methods: ['POST'])]
|
#[Route('/admin/teamer/mailing/send', name: 'app_admin_teamer_mailing_send', methods: ['POST'])]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function send(Request $request): Response
|
public function send(Request $request): Response
|
||||||
{
|
{
|
||||||
$form = $this->createMailingForm($request);
|
$form = $this->createMailingForm($request);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class RemarksController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/teamer/remarks/{uuid}', name: 'app_admin_teamer_remarks_internal')]
|
#[Route('/admin/teamer/remarks/{uuid}', name: 'app_admin_teamer_remarks_internal')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Teamer $teamer, Request $request): Response
|
public function index(Teamer $teamer, Request $request): Response
|
||||||
{
|
{
|
||||||
$returnUrl = $this->getReturnUrl($request, 'app_administrative_teamer_index');
|
$returnUrl = $this->getReturnUrl($request, 'app_administrative_teamer_index');
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class SkillsController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/admin/teamer/skills/{uuid}', name: 'app_admin_teamer_skills')]
|
#[Route('/admin/teamer/skills/{uuid}', name: 'app_admin_teamer_skills')]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(Teamer $teamer, Request $request): Response
|
public function index(Teamer $teamer, Request $request): Response
|
||||||
{
|
{
|
||||||
$trainings = $this->trainingRepository->getList();
|
$trainings = $this->trainingRepository->getList();
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class CreateController extends AbstractController
|
|||||||
path: '/admin/teamer/skills/training-attendance/create/{training_id}/{teamer_id}',
|
path: '/admin/teamer/skills/training-attendance/create/{training_id}/{teamer_id}',
|
||||||
name: 'app_admin_teamer_skills_training_attendance_create'
|
name: 'app_admin_teamer_skills_training_attendance_create'
|
||||||
)]
|
)]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(
|
public function index(
|
||||||
#[MapEntity(mapping: ['training_id' => 'id'])]
|
#[MapEntity(mapping: ['training_id' => 'id'])]
|
||||||
Training $training,
|
Training $training,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class DeleteController extends AbstractController
|
|||||||
path: '/admin/teamer/skills/training-attendance/delete/{uuid}',
|
path: '/admin/teamer/skills/training-attendance/delete/{uuid}',
|
||||||
name: 'app_admin_teamer_skills_training_attendance_delete'
|
name: 'app_admin_teamer_skills_training_attendance_delete'
|
||||||
)]
|
)]
|
||||||
#[IsGranted('ROLE_ADMIN')]
|
#[IsGranted('ROLE_TEAM_ADMIN')]
|
||||||
public function index(TrainingAttendance $attendance, Request $request): Response
|
public function index(TrainingAttendance $attendance, Request $request): Response
|
||||||
{
|
{
|
||||||
if (true === $request->isMethod('POST')) {
|
if (true === $request->isMethod('POST')) {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class CallOffController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/administrative/assignment/call-off/{uuid}', name: 'app_administrative_assignment_call_off')]
|
#[Route('/administrative/assignment/call-off/{uuid}', name: 'app_administrative_assignment_call_off')]
|
||||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
#[IsGranted('CALL_OFF', subject: 'assignment')]
|
||||||
public function index(Assignment $assignment, Request $request): Response
|
public function index(Assignment $assignment, Request $request): Response
|
||||||
{
|
{
|
||||||
if (true === $request->isMethod('POST')) {
|
if (true === $request->isMethod('POST')) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
class PublishController extends AbstractController
|
class PublishController extends AbstractController
|
||||||
{
|
{
|
||||||
@@ -23,6 +24,7 @@ class PublishController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/administrative/assignment/publish/{uuid}', name: 'app_administrative_assignment_publish')]
|
#[Route('/administrative/assignment/publish/{uuid}', name: 'app_administrative_assignment_publish')]
|
||||||
|
#[IsGranted('PUBLISH', subject: 'assignment')]
|
||||||
public function index(Assignment $assignment, Request $request): Response
|
public function index(Assignment $assignment, Request $request): Response
|
||||||
{
|
{
|
||||||
$returnUrl = $this->getReturnUrl($request, 'app_administrative_assignment_index');
|
$returnUrl = $this->getReturnUrl($request, 'app_administrative_assignment_index');
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
class EditController extends AbstractController
|
class EditController extends AbstractController
|
||||||
{
|
{
|
||||||
@@ -27,6 +28,7 @@ class EditController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/administrative/destination/edit/{id}', name: 'app_administrative_system_destination_edit')]
|
#[Route('/administrative/destination/edit/{id}', name: 'app_administrative_system_destination_edit')]
|
||||||
|
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||||
public function index(Destination $destination, Request $request): Response
|
public function index(Destination $destination, Request $request): Response
|
||||||
{
|
{
|
||||||
$destinationDto = DestinationDto::fromEntity($destination);
|
$destinationDto = DestinationDto::fromEntity($destination);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class IndexController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/administrative/system/faq/sort', name: 'app_administrative_system_faq_sort', methods: ['POST'])]
|
#[Route('/administrative/system/faq/sort', name: 'app_administrative_system_faq_sort', methods: ['POST'])]
|
||||||
|
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||||
public function sort(Request $request): JsonResponse
|
public function sort(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$data = json_decode($request->getContent(), true);
|
$data = json_decode($request->getContent(), true);
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ class ApplicationFilterController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/common/application/filter/reset', name: 'app_common_application_filter_reset')]
|
#[Route('/common/application/filter/reset', name: 'app_common_application_filter_reset')]
|
||||||
|
#[IsGranted('ROLE_USER')]
|
||||||
public function reset(Request $request): Response
|
public function reset(Request $request): Response
|
||||||
{
|
{
|
||||||
$this->filterHandler->resetFilterSettings();
|
$this->filterHandler->resetFilterSettings();
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ class AssignmentFilterController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/common/assignment/filter/reset', name: 'app_common_assignment_filter_reset')]
|
#[Route('/common/assignment/filter/reset', name: 'app_common_assignment_filter_reset')]
|
||||||
|
#[IsGranted('ROLE_USER')]
|
||||||
public function reset(Request $request): Response
|
public function reset(Request $request): Response
|
||||||
{
|
{
|
||||||
$this->filterHandler->resetFilterSettings();
|
$this->filterHandler->resetFilterSettings();
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ class DocumentFilterController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/common/document/filter/reset', name: 'app_common_document_filter_reset')]
|
#[Route('/common/document/filter/reset', name: 'app_common_document_filter_reset')]
|
||||||
|
#[IsGranted('ROLE_USER')]
|
||||||
public function reset(Request $request): Response
|
public function reset(Request $request): Response
|
||||||
{
|
{
|
||||||
$this->filterHandler->resetFilterSettings();
|
$this->filterHandler->resetFilterSettings();
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class FeedbackFilterController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/common/feedback/filter/reset', name: 'app_common_feedback_filter_reset')]
|
#[Route('/common/feedback/filter/reset', name: 'app_common_feedback_filter_reset')]
|
||||||
|
#[IsGranted('ROLE_USER')]
|
||||||
public function reset(Request $request): Response
|
public function reset(Request $request): Response
|
||||||
{
|
{
|
||||||
$this->filterHandler->resetFilterSettings();
|
$this->filterHandler->resetFilterSettings();
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class TeamerFilterController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/common/teamer/filter/reset', name: 'app_common_teamer_filter_reset')]
|
#[Route('/common/teamer/filter/reset', name: 'app_common_teamer_filter_reset')]
|
||||||
|
#[IsGranted('ROLE_USER')]
|
||||||
public function reset(Request $request): Response
|
public function reset(Request $request): Response
|
||||||
{
|
{
|
||||||
$this->filterHandler->resetFilterSettings();
|
$this->filterHandler->resetFilterSettings();
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ class TimelineFilterController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/common/timeline/filter/reset', name: 'app_common_timeline_filter_reset')]
|
#[Route('/common/timeline/filter/reset', name: 'app_common_timeline_filter_reset')]
|
||||||
|
#[IsGranted('ROLE_USER')]
|
||||||
public function reset(Request $request): Response
|
public function reset(Request $request): Response
|
||||||
{
|
{
|
||||||
$this->filterHandler->resetFilterSettings();
|
$this->filterHandler->resetFilterSettings();
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use App\Repository\UploadRepository;
|
|||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
class IndexController extends AbstractController
|
class IndexController extends AbstractController
|
||||||
{
|
{
|
||||||
@@ -18,6 +19,7 @@ class IndexController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/management', name: 'app_manager_index')]
|
#[Route('/management', name: 'app_manager_index')]
|
||||||
|
#[IsGranted('ROLE_MANAGER')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
$dispositions = $this->dispositionRepository->getNew();
|
$dispositions = $this->dispositionRepository->getNew();
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use App\Repository\ContactRepository;
|
|||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
class ContactController extends AbstractController
|
class ContactController extends AbstractController
|
||||||
{
|
{
|
||||||
@@ -15,6 +16,7 @@ class ContactController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/teamer/contact', name: 'app_teamer_contact')]
|
#[Route('/teamer/contact', name: 'app_teamer_contact')]
|
||||||
|
#[IsGranted('ROLE_USER')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
$allContacts = $this
|
$allContacts = $this
|
||||||
|
|||||||
+7
-7
@@ -22,7 +22,7 @@ class User implements UserInterface, TimestampableEntityInterface, SoftDeletable
|
|||||||
* Assignable roles and their labels.
|
* Assignable roles and their labels.
|
||||||
*/
|
*/
|
||||||
public const ROLES = [
|
public const ROLES = [
|
||||||
'ROLE_ADMIN' => 'Admin',
|
'ROLE_TEAM_ADMIN' => 'Team Admin',
|
||||||
'ROLE_MANAGER' => 'Reisemanager',
|
'ROLE_MANAGER' => 'Reisemanager',
|
||||||
'ROLE_HOUSE_MANAGER' => 'Hausleitung',
|
'ROLE_HOUSE_MANAGER' => 'Hausleitung',
|
||||||
'ROLE_TEAMER' => 'Teamer',
|
'ROLE_TEAMER' => 'Teamer',
|
||||||
@@ -35,7 +35,7 @@ class User implements UserInterface, TimestampableEntityInterface, SoftDeletable
|
|||||||
* a super admin.
|
* a super admin.
|
||||||
*/
|
*/
|
||||||
public const PENDING_ROLES = [
|
public const PENDING_ROLES = [
|
||||||
'ROLE_ADMIN' => 'ROLE_ADMIN_PENDING',
|
'ROLE_TEAM_ADMIN' => 'ROLE_TEAM_ADMIN_PENDING',
|
||||||
'ROLE_MANAGER' => 'ROLE_MANAGER_PENDING',
|
'ROLE_MANAGER' => 'ROLE_MANAGER_PENDING',
|
||||||
'ROLE_HOUSE_MANAGER' => 'ROLE_HOUSE_MANAGER_PENDING',
|
'ROLE_HOUSE_MANAGER' => 'ROLE_HOUSE_MANAGER_PENDING',
|
||||||
];
|
];
|
||||||
@@ -194,7 +194,7 @@ class User implements UserInterface, TimestampableEntityInterface, SoftDeletable
|
|||||||
$roles = ['ROLE_USER', ...$this->roles];
|
$roles = ['ROLE_USER', ...$this->roles];
|
||||||
|
|
||||||
if (true === $this->isSuperAdmin()) {
|
if (true === $this->isSuperAdmin()) {
|
||||||
$roles[] = 'ROLE_SUPER_ADMIN';
|
$roles[] = 'ROLE_TEAM_SUPER_ADMIN';
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_unique($roles);
|
return array_unique($roles);
|
||||||
@@ -223,7 +223,7 @@ class User implements UserInterface, TimestampableEntityInterface, SoftDeletable
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The manually assignable roles held by the user, i.e. without the implicit ROLE_USER
|
* The manually assignable roles held by the user, i.e. without the implicit ROLE_USER
|
||||||
* and ROLE_SUPER_ADMIN added by getRoles() and without any pending marker. Used to
|
* and ROLE_TEAM_SUPER_ADMIN added by getRoles() and without any pending marker. Used to
|
||||||
* edit role assignments: saving them resolves the pending approvals.
|
* edit role assignments: saving them resolves the pending approvals.
|
||||||
*/
|
*/
|
||||||
public function getAssignedRoles(): array
|
public function getAssignedRoles(): array
|
||||||
@@ -283,12 +283,12 @@ class User implements UserInterface, TimestampableEntityInterface, SoftDeletable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Super admin is an elevation of ROLE_ADMIN, never a standalone grant.
|
* Super admin is an elevation of ROLE_TEAM_ADMIN, never a standalone grant.
|
||||||
*/
|
*/
|
||||||
#[Assert\Callback]
|
#[Assert\Callback]
|
||||||
public function validateSuperAdmin(ExecutionContextInterface $context): void
|
public function validateSuperAdmin(ExecutionContextInterface $context): void
|
||||||
{
|
{
|
||||||
if (true === $this->superAdmin && false === in_array('ROLE_ADMIN', $this->roles, true)) {
|
if (true === $this->superAdmin && false === in_array('ROLE_TEAM_ADMIN', $this->roles, true)) {
|
||||||
$context
|
$context
|
||||||
->buildViolation('Nur Admins können zu Superadmins ernannt werden.')
|
->buildViolation('Nur Admins können zu Superadmins ernannt werden.')
|
||||||
->atPath('superAdmin')
|
->atPath('superAdmin')
|
||||||
@@ -311,7 +311,7 @@ class User implements UserInterface, TimestampableEntityInterface, SoftDeletable
|
|||||||
|
|
||||||
public function getDefaultRoute(): string
|
public function getDefaultRoute(): string
|
||||||
{
|
{
|
||||||
if ($this->hasRole('ROLE_ADMIN')) {
|
if ($this->hasRole('ROLE_TEAM_ADMIN')) {
|
||||||
return 'app_admin_index';
|
return 'app_admin_index';
|
||||||
} elseif ($this->hasRole('ROLE_MANAGER')) {
|
} elseif ($this->hasRole('ROLE_MANAGER')) {
|
||||||
return 'app_manager_index';
|
return 'app_manager_index';
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class UserType extends AbstractType
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Super admin is an elevation of an existing role, never a grant of its own, so the
|
// Super admin is an elevation of an existing role, never a grant of its own, so the
|
||||||
// field exists only for somebody who already holds ROLE_ADMIN - offering it to
|
// field exists only for somebody who already holds ROLE_TEAM_ADMIN - offering it to
|
||||||
// anyone else would only produce the violation from User::validateSuperAdmin().
|
// anyone else would only produce the violation from User::validateSuperAdmin().
|
||||||
// A flag already set without the role is the exception: it has to stay editable, or
|
// A flag already set without the role is the exception: it has to stay editable, or
|
||||||
// that user could not be saved at all until BusPro claims them an admin again.
|
// that user could not be saved at all until BusPro claims them an admin again.
|
||||||
@@ -78,7 +78,7 @@ class UserType extends AbstractType
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false === in_array('ROLE_ADMIN', $user->getAssignedRoles(), true) && false === $user->isSuperAdmin()) {
|
if (false === in_array('ROLE_TEAM_ADMIN', $user->getAssignedRoles(), true) && false === $user->isSuperAdmin()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ abstract class AbstractMenuBuilder
|
|||||||
* Note that "app_admin_" does not match the shared "app_administrative_" routes.
|
* Note that "app_admin_" does not match the shared "app_administrative_" routes.
|
||||||
*/
|
*/
|
||||||
protected const AREA_ROUTE_PREFIXES = [
|
protected const AREA_ROUTE_PREFIXES = [
|
||||||
'app_admin_' => 'ROLE_ADMIN',
|
'app_admin_' => 'ROLE_TEAM_ADMIN',
|
||||||
'app_manager_' => 'ROLE_MANAGER',
|
'app_manager_' => 'ROLE_MANAGER',
|
||||||
'app_house_manager_' => 'ROLE_HOUSE_MANAGER',
|
'app_house_manager_' => 'ROLE_HOUSE_MANAGER',
|
||||||
'app_teamer_' => 'ROLE_TEAMER',
|
'app_teamer_' => 'ROLE_TEAMER',
|
||||||
@@ -29,7 +29,7 @@ abstract class AbstractMenuBuilder
|
|||||||
* Priority order of the area roles, must stay in sync with User::getDefaultRoute().
|
* Priority order of the area roles, must stay in sync with User::getDefaultRoute().
|
||||||
*/
|
*/
|
||||||
protected const ROLE_PRIORITY = [
|
protected const ROLE_PRIORITY = [
|
||||||
'ROLE_ADMIN',
|
'ROLE_TEAM_ADMIN',
|
||||||
'ROLE_MANAGER',
|
'ROLE_MANAGER',
|
||||||
'ROLE_HOUSE_MANAGER',
|
'ROLE_HOUSE_MANAGER',
|
||||||
'ROLE_TEAMER',
|
'ROLE_TEAMER',
|
||||||
@@ -140,7 +140,7 @@ abstract class AbstractMenuBuilder
|
|||||||
|
|
||||||
protected function addAdminItem(ItemInterface $menu): void
|
protected function addAdminItem(ItemInterface $menu): void
|
||||||
{
|
{
|
||||||
if ($this->security->isGranted('ROLE_ADMIN')) {
|
if ($this->security->isGranted('ROLE_TEAM_ADMIN')) {
|
||||||
$this->addDivider($menu);
|
$this->addDivider($menu);
|
||||||
$menu->addChild('zum Adminbereich', [
|
$menu->addChild('zum Adminbereich', [
|
||||||
'route' => 'app_admin_index',
|
'route' => 'app_admin_index',
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class MenuBuilder extends AbstractMenuBuilder
|
|||||||
public function createMainMenu(array $options): ItemInterface
|
public function createMainMenu(array $options): ItemInterface
|
||||||
{
|
{
|
||||||
return match ($this->resolveArea()) {
|
return match ($this->resolveArea()) {
|
||||||
'ROLE_ADMIN' => $this->adminMenuBuilder->createMainMenu($options),
|
'ROLE_TEAM_ADMIN' => $this->adminMenuBuilder->createMainMenu($options),
|
||||||
'ROLE_MANAGER' => $this->managerMenuBuilder->createMainMenu($options),
|
'ROLE_MANAGER' => $this->managerMenuBuilder->createMainMenu($options),
|
||||||
'ROLE_HOUSE_MANAGER' => $this->houseManagerMenuBuilder->createMainMenu($options),
|
'ROLE_HOUSE_MANAGER' => $this->houseManagerMenuBuilder->createMainMenu($options),
|
||||||
'ROLE_TEAMER' => $this->teamerMenuBuilder->createMainMenu($options),
|
'ROLE_TEAMER' => $this->teamerMenuBuilder->createMainMenu($options),
|
||||||
@@ -43,7 +43,7 @@ class MenuBuilder extends AbstractMenuBuilder
|
|||||||
public function createTeamerMenu(array $options): ItemInterface
|
public function createTeamerMenu(array $options): ItemInterface
|
||||||
{
|
{
|
||||||
return match ($this->resolveArea()) {
|
return match ($this->resolveArea()) {
|
||||||
'ROLE_ADMIN' => $this->adminMenuBuilder->createTeamerMenu($options),
|
'ROLE_TEAM_ADMIN' => $this->adminMenuBuilder->createTeamerMenu($options),
|
||||||
'ROLE_MANAGER' => $this->managerMenuBuilder->createTeamerMenu($options),
|
'ROLE_MANAGER' => $this->managerMenuBuilder->createTeamerMenu($options),
|
||||||
default => $this->createRootElement(),
|
default => $this->createRootElement(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -148,7 +148,8 @@ class AvailabilityRepository extends ServiceEntityRepository
|
|||||||
$qb->expr()->eq('availability.dateTo', ':dateTo'),
|
$qb->expr()->eq('availability.dateTo', ':dateTo'),
|
||||||
$qb->expr()->isNull('availability.owner')
|
$qb->expr()->isNull('availability.owner')
|
||||||
))
|
))
|
||||||
->setParameters($fields)
|
->setParameter('dateFrom', $fields['dateFrom'])
|
||||||
|
->setParameter('dateTo', $fields['dateTo'])
|
||||||
->getQuery()
|
->getQuery()
|
||||||
->getResult()
|
->getResult()
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use App\Entity\User;
|
|||||||
abstract class AbstractRequiredTeamerCheck implements RequiredTeamerCheckInterface
|
abstract class AbstractRequiredTeamerCheck implements RequiredTeamerCheckInterface
|
||||||
{
|
{
|
||||||
private const EXCLUDED_ROLES = [
|
private const EXCLUDED_ROLES = [
|
||||||
'ROLE_ADMIN',
|
'ROLE_TEAM_ADMIN',
|
||||||
'ROLE_MANAGER',
|
'ROLE_MANAGER',
|
||||||
'ROLE_HOUSE_MANAGER',
|
'ROLE_HOUSE_MANAGER',
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class MyEpAuthenticator extends AbstractAuthenticator
|
|||||||
* is dropped rather than stored, so that no role this application assigns a meaning
|
* is dropped rather than stored, so that no role this application assigns a meaning
|
||||||
* to can be set from the outside.
|
* to can be set from the outside.
|
||||||
*/
|
*/
|
||||||
private const ELIGIBLE_ROLES = ['ROLE_ADMIN', 'ROLE_TEAMER', 'ROLE_MANAGER', 'ROLE_HOUSE_MANAGER'];
|
private const ELIGIBLE_ROLES = ['ROLE_TEAM_ADMIN', 'ROLE_TEAMER', 'ROLE_MANAGER', 'ROLE_HOUSE_MANAGER'];
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly MyEpClient $client,
|
private readonly MyEpClient $client,
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class DispositionVoter extends Voter
|
|||||||
static::CONTRACT, static::INVOICE => false === $disposition->isSkipFormalities()
|
static::CONTRACT, static::INVOICE => false === $disposition->isSkipFormalities()
|
||||||
&& ($this->security->isGranted('ROLE_ADMINISTRATIVE')
|
&& ($this->security->isGranted('ROLE_ADMINISTRATIVE')
|
||||||
|| $this->assertTeamerAccess($token, $disposition)),
|
|| $this->assertTeamerAccess($token, $disposition)),
|
||||||
static::DELETE => $this->security->isGranted('ROLE_ADMIN'),
|
static::DELETE => $this->security->isGranted('ROLE_TEAM_ADMIN'),
|
||||||
static::FEEDBACK => false === $disposition->isSkipFormalities()
|
static::FEEDBACK => false === $disposition->isSkipFormalities()
|
||||||
&& ($this->security->isGranted('ROLE_ADMINISTRATIVE')
|
&& ($this->security->isGranted('ROLE_ADMINISTRATIVE')
|
||||||
|| $this->assertHouseManagerAccess($token, $disposition)),
|
|| $this->assertHouseManagerAccess($token, $disposition)),
|
||||||
@@ -162,7 +162,7 @@ class DispositionVoter extends Voter
|
|||||||
private function assertAdminDocumentUploadAllowed(Disposition $disposition): bool
|
private function assertAdminDocumentUploadAllowed(Disposition $disposition): bool
|
||||||
{
|
{
|
||||||
if (false === $this->security->isGranted('ROLE_ADMINISTRATIVE')
|
if (false === $this->security->isGranted('ROLE_ADMINISTRATIVE')
|
||||||
&& false === $this->security->isGranted('ROLE_ADMIN')) {
|
&& false === $this->security->isGranted('ROLE_TEAM_ADMIN')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class FeedbackVoter extends Voter
|
|||||||
/** @var Feedback $feedback */
|
/** @var Feedback $feedback */
|
||||||
$feedback = $subject;
|
$feedback = $subject;
|
||||||
|
|
||||||
if (in_array('ROLE_ADMIN', $token->getRoleNames())) {
|
if (in_array('ROLE_TEAM_ADMIN', $token->getRoleNames())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class ImpersonationVoter extends Voter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Admin is the only role allowed to impersonate
|
// Admin is the only role allowed to impersonate
|
||||||
if (false === $this->security->isGranted('ROLE_ADMIN')) {
|
if (false === $this->security->isGranted('ROLE_TEAM_ADMIN')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,12 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
|||||||
abstract class AbstractFilterHandler
|
abstract class AbstractFilterHandler
|
||||||
{
|
{
|
||||||
protected string $namespace = 'filter:default';
|
protected string $namespace = 'filter:default';
|
||||||
protected string $modelClass = AbstractFilterDto::class;
|
|
||||||
|
/**
|
||||||
|
* The DTO a subclass builds. No default: AbstractFilterDto is abstract, so any value here
|
||||||
|
* would only fatal on instantiation - every handler declares its own.
|
||||||
|
*/
|
||||||
|
protected string $modelClass;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected readonly RequestStack $requestStack,
|
protected readonly RequestStack $requestStack,
|
||||||
@@ -29,6 +34,8 @@ abstract class AbstractFilterHandler
|
|||||||
public function setModelClass(string $modelClass): static
|
public function setModelClass(string $modelClass): static
|
||||||
{
|
{
|
||||||
$this->modelClass = $modelClass;
|
$this->modelClass = $modelClass;
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequest(FormInterface $form): AbstractFilterDto
|
public function handleRequest(FormInterface $form): AbstractFilterDto
|
||||||
@@ -50,13 +57,9 @@ abstract class AbstractFilterHandler
|
|||||||
$this->getSession()->remove($this->namespace);
|
$this->getSession()->remove($this->namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFilterSettings(): AbstractFilterDto
|
abstract public function getFilterSettings(): AbstractFilterDto;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function saveFilterSettings(AbstractFilterDto $filterDto): void
|
abstract protected function saveFilterSettings(AbstractFilterDto $filterDto): void;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getSession(): SessionInterface
|
protected function getSession(): SessionInterface
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class AppRuntime implements RuntimeExtensionInterface
|
|||||||
$user = $teamer->getUser();
|
$user = $teamer->getUser();
|
||||||
|
|
||||||
if (null !== $user) {
|
if (null !== $user) {
|
||||||
if ($user->hasRole('ROLE_ADMIN')) {
|
if ($user->hasRole('ROLE_TEAM_ADMIN')) {
|
||||||
$labelItems[] = 'Admin';
|
$labelItems[] = 'Admin';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{{ form_start(form) }}
|
{{ form_start(form) }}
|
||||||
<div class="flex flex-col space-y-4 pb-8">
|
<div class="flex flex-col space-y-4 pb-8">
|
||||||
{# only present for somebody who already holds ROLE_ADMIN, see UserType #}
|
{# only present for somebody who already holds ROLE_TEAM_ADMIN, see UserType #}
|
||||||
{% if form.superAdmin is defined %}
|
{% if form.superAdmin is defined %}
|
||||||
{{ form_row(form.superAdmin) }}
|
{{ form_row(form.superAdmin) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<div class="pb-8">
|
<div class="pb-8">
|
||||||
{% include '_partials/_assignment_info_compact.html.twig' %}
|
{% include '_partials/_assignment_info_compact.html.twig' %}
|
||||||
</div>
|
</div>
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_TEAM_ADMIN') %}
|
||||||
<div class="col-span-2">
|
<div class="col-span-2">
|
||||||
<h2 class="font-bold text-lg pb-4">
|
<h2 class="font-bold text-lg pb-4">
|
||||||
Bewerbungen
|
Bewerbungen
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
<th>
|
<th>
|
||||||
{{ knp_pagination_sortable(pagination, 'Busbegleitung', 'assignment.pickup') }}
|
{{ knp_pagination_sortable(pagination, 'Busbegleitung', 'assignment.pickup') }}
|
||||||
</th>
|
</th>
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_TEAM_ADMIN') %}
|
||||||
<th>
|
<th>
|
||||||
Bewerbungen
|
Bewerbungen
|
||||||
</th>
|
</th>
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
-
|
-
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_TEAM_ADMIN') %}
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ path('app_administrative_assignment_detail', { 'uuid': assignment.uuid, 'r': return_url() }) }}" class="flex items-center space-x-2">
|
<a href="{{ path('app_administrative_assignment_detail', { 'uuid': assignment.uuid, 'r': return_url() }) }}" class="flex items-center space-x-2">
|
||||||
<span>{{ assignment.applications|length }}</span>
|
<span>{{ assignment.applications|length }}</span>
|
||||||
|
|||||||
@@ -102,7 +102,7 @@
|
|||||||
{{ knp_pagination_render(pagination) }}
|
{{ knp_pagination_render(pagination) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_TEAM_ADMIN') %}
|
||||||
<a href="{{ path('app_admin_feedback_provide') }}" class="btn" title="Feedback erfassen">
|
<a href="{{ path('app_admin_feedback_provide') }}" class="btn" title="Feedback erfassen">
|
||||||
Neu
|
Neu
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
Reset
|
Reset
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_TEAM_ADMIN') %}
|
||||||
<a href="{{ path('app_admin_teamer_mailing', { 'r': return_url() }) }}"
|
<a href="{{ path('app_admin_teamer_mailing', { 'r': return_url() }) }}"
|
||||||
class="btn btn--small"
|
class="btn btn--small"
|
||||||
title="Mail an die gefilterte Liste schreiben">
|
title="Mail an die gefilterte Liste schreiben">
|
||||||
@@ -113,7 +113,7 @@
|
|||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if teamer.deleted %}
|
{% if teamer.deleted %}
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_TEAM_ADMIN') %}
|
||||||
<button type="button"
|
<button type="button"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elseif teamer.user is not null and teamer.user.disabled %}
|
{% elseif teamer.user is not null and teamer.user.disabled %}
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_TEAM_ADMIN') %}
|
||||||
<button type="button"
|
<button type="button"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_TEAM_ADMIN') %}
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="text-red-500"
|
class="text-red-500"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
{{ icon('mask') }}
|
{{ icon('mask') }}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_TEAM_ADMIN') %}
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="text-red-500"
|
class="text-red-500"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
|
|||||||
@@ -80,7 +80,7 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_TEAM_ADMIN') %}
|
||||||
<h2 class="text-lg font-bold">
|
<h2 class="text-lg font-bold">
|
||||||
Interne Anmerkungen
|
Interne Anmerkungen
|
||||||
</h2>
|
</h2>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use App\BusProNet\Model\Pickup;
|
|||||||
use App\BusProNet\Model\ProfileResponse;
|
use App\BusProNet\Model\ProfileResponse;
|
||||||
use App\BusProNet\Model\ProfileUpdateResponse;
|
use App\BusProNet\Model\ProfileUpdateResponse;
|
||||||
use App\BusProNet\ResponseParser;
|
use App\BusProNet\ResponseParser;
|
||||||
|
use App\BusProNet\ResponseParserException;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class ResponseParserTest extends TestCase
|
class ResponseParserTest extends TestCase
|
||||||
@@ -178,6 +179,65 @@ class ResponseParserTest extends TestCase
|
|||||||
$this->assertEquals('Gaststätte', $hotel->getType());
|
$this->assertEquals('Gaststätte', $hotel->getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A broken response used to collapse into one opaque "Unable to parse XML response",
|
||||||
|
* which is what made the production import failure undiagnosable. Each shape must now
|
||||||
|
* name itself.
|
||||||
|
*/
|
||||||
|
public function testParseEmptyResponse(): void
|
||||||
|
{
|
||||||
|
$parser = $this->getParserInstance();
|
||||||
|
|
||||||
|
$this->expectException(ResponseParserException::class);
|
||||||
|
$this->expectExceptionMessage('empty response');
|
||||||
|
|
||||||
|
$parser->parseXmlString(ApiClient::TYPE_BASE_DATA_PICKUPS, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParseTruncatedResponse(): void
|
||||||
|
{
|
||||||
|
$content = '<?xml version="1.0" encoding="utf-8"?><ergebnis><satz typ="STAMMZUSTIEGE"></satz><zustieg id="1"';
|
||||||
|
|
||||||
|
$parser = $this->getParserInstance();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$parser->parseXmlString(ApiClient::TYPE_BASE_DATA_PICKUPS, $content);
|
||||||
|
$this->fail('Expected a ResponseParserException');
|
||||||
|
} catch (ResponseParserException $e) {
|
||||||
|
$this->assertStringContainsString('('.strlen($content).' bytes)', $e->getMessage());
|
||||||
|
$this->assertStringContainsString('line 1', $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParseWellFormedResponseOfAnUnknownType(): void
|
||||||
|
{
|
||||||
|
$content = '<?xml version="1.0" encoding="utf-8"?><ergebnis><satz typ="STAMMIRGENDWAS"></satz></ergebnis>';
|
||||||
|
|
||||||
|
$parser = $this->getParserInstance();
|
||||||
|
|
||||||
|
$this->expectException(ResponseParserException::class);
|
||||||
|
$this->expectExceptionMessage('Unrecognised BusProNet response type "STAMMIRGENDWAS"');
|
||||||
|
|
||||||
|
$parser->parseXmlString(ApiClient::TYPE_BASE_DATA_PICKUPS, $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParsingDoesNotLeakLibxmlErrorState(): void
|
||||||
|
{
|
||||||
|
$previous = libxml_use_internal_errors(false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
$this->getParserInstance()->parseXmlString(ApiClient::TYPE_BASE_DATA_PICKUPS, '<ergebnis');
|
||||||
|
} catch (ResponseParserException) {
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertFalse(libxml_use_internal_errors(false));
|
||||||
|
$this->assertSame([], libxml_get_errors());
|
||||||
|
} finally {
|
||||||
|
libxml_use_internal_errors($previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function loadFixture(string $filename): string
|
private function loadFixture(string $filename): string
|
||||||
{
|
{
|
||||||
return file_get_contents(__DIR__.'/../Resources/'.$filename);
|
return file_get_contents(__DIR__.'/../Resources/'.$filename);
|
||||||
@@ -186,7 +246,7 @@ class ResponseParserTest extends TestCase
|
|||||||
private function getParserInstance(): ResponseParser
|
private function getParserInstance(): ResponseParser
|
||||||
{
|
{
|
||||||
return new ResponseParser([
|
return new ResponseParser([
|
||||||
'bpn_crm_id_admin' => 1292,
|
'bpn_crm_id_team_admin' => 1292,
|
||||||
'bpn_crm_id_manager' => 1293,
|
'bpn_crm_id_manager' => 1293,
|
||||||
'bpn_crm_id_teamer' => 1070,
|
'bpn_crm_id_teamer' => 1070,
|
||||||
// Deliberately a small excerpt of the configured map: the fixtures only carry
|
// Deliberately a small excerpt of the configured map: the fixtures only carry
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class UserDataHandlerTest extends TestCase
|
|||||||
{
|
{
|
||||||
yield 'admin only yields the pending marker' => [
|
yield 'admin only yields the pending marker' => [
|
||||||
(new CrmAttributesResponse())->setAdmin(true),
|
(new CrmAttributesResponse())->setAdmin(true),
|
||||||
[User::PENDING_ROLES['ROLE_ADMIN']],
|
[User::PENDING_ROLES['ROLE_TEAM_ADMIN']],
|
||||||
];
|
];
|
||||||
|
|
||||||
yield 'manager only yields the pending marker' => [
|
yield 'manager only yields the pending marker' => [
|
||||||
@@ -64,12 +64,12 @@ class UserDataHandlerTest extends TestCase
|
|||||||
|
|
||||||
yield 'admin and teamer' => [
|
yield 'admin and teamer' => [
|
||||||
(new CrmAttributesResponse())->setAdmin(true)->setTeamer(true),
|
(new CrmAttributesResponse())->setAdmin(true)->setTeamer(true),
|
||||||
[User::PENDING_ROLES['ROLE_ADMIN'], 'ROLE_TEAMER'],
|
[User::PENDING_ROLES['ROLE_TEAM_ADMIN'], 'ROLE_TEAMER'],
|
||||||
];
|
];
|
||||||
|
|
||||||
yield 'admin and manager yield both markers' => [
|
yield 'admin and manager yield both markers' => [
|
||||||
(new CrmAttributesResponse())->setAdmin(true)->setManager(true),
|
(new CrmAttributesResponse())->setAdmin(true)->setManager(true),
|
||||||
[User::PENDING_ROLES['ROLE_ADMIN'], User::PENDING_ROLES['ROLE_MANAGER']],
|
[User::PENDING_ROLES['ROLE_TEAM_ADMIN'], User::PENDING_ROLES['ROLE_MANAGER']],
|
||||||
];
|
];
|
||||||
|
|
||||||
yield 'manager and house manager yield both markers, the roles stand on their own' => [
|
yield 'manager and house manager yield both markers, the roles stand on their own' => [
|
||||||
@@ -100,9 +100,9 @@ class UserDataHandlerTest extends TestCase
|
|||||||
public static function toPendingRolesProvider(): iterable
|
public static function toPendingRolesProvider(): iterable
|
||||||
{
|
{
|
||||||
yield 'admin' => [
|
yield 'admin' => [
|
||||||
['ROLE_ADMIN'],
|
['ROLE_TEAM_ADMIN'],
|
||||||
(new CrmAttributesResponse())->setAdmin(true),
|
(new CrmAttributesResponse())->setAdmin(true),
|
||||||
[User::PENDING_ROLES['ROLE_ADMIN']],
|
[User::PENDING_ROLES['ROLE_TEAM_ADMIN']],
|
||||||
];
|
];
|
||||||
|
|
||||||
yield 'manager and house manager are marked independently' => [
|
yield 'manager and house manager are marked independently' => [
|
||||||
@@ -118,9 +118,9 @@ class UserDataHandlerTest extends TestCase
|
|||||||
];
|
];
|
||||||
|
|
||||||
yield 'admin and house manager' => [
|
yield 'admin and house manager' => [
|
||||||
['ROLE_ADMIN', 'ROLE_HOUSE_MANAGER'],
|
['ROLE_TEAM_ADMIN', 'ROLE_HOUSE_MANAGER'],
|
||||||
(new CrmAttributesResponse())->setAdmin(true)->setHouseManager(true),
|
(new CrmAttributesResponse())->setAdmin(true)->setHouseManager(true),
|
||||||
[User::PENDING_ROLES['ROLE_ADMIN'], User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
[User::PENDING_ROLES['ROLE_TEAM_ADMIN'], User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
||||||
];
|
];
|
||||||
|
|
||||||
yield 'teamer has no marker' => [
|
yield 'teamer has no marker' => [
|
||||||
@@ -144,7 +144,7 @@ class UserDataHandlerTest extends TestCase
|
|||||||
->setEmail('[email protected]')
|
->setEmail('[email protected]')
|
||||||
->setBusProAddressId(1)
|
->setBusProAddressId(1)
|
||||||
->setBusProPersonId(2)
|
->setBusProPersonId(2)
|
||||||
->setRoles(['ROLE_ADMIN'])
|
->setRoles(['ROLE_TEAM_ADMIN'])
|
||||||
->setHotelCodes(['XYZ'])
|
->setHotelCodes(['XYZ'])
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ class UserDataHandlerTest extends TestCase
|
|||||||
$profileResponse,
|
$profileResponse,
|
||||||
true,
|
true,
|
||||||
['team' => ['selected' => true]],
|
['team' => ['selected' => true]],
|
||||||
['ROLE_ADMIN', 'ROLE_TEAMER'],
|
['ROLE_TEAM_ADMIN', 'ROLE_TEAMER'],
|
||||||
['DKS'],
|
['DKS'],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ class UserDataHandlerTest extends TestCase
|
|||||||
|
|
||||||
// the CRM leads: the still claimed role survives, the houses are replaced by its own
|
// the CRM leads: the still claimed role survives, the houses are replaced by its own
|
||||||
$this->assertSame(['DKS'], $user->getHotelCodes());
|
$this->assertSame(['DKS'], $user->getHotelCodes());
|
||||||
$this->assertTrue($user->hasRole('ROLE_ADMIN'));
|
$this->assertTrue($user->hasRole('ROLE_TEAM_ADMIN'));
|
||||||
|
|
||||||
$this->assertSame('New', $teamer->getFirstName());
|
$this->assertSame('New', $teamer->getFirstName());
|
||||||
$this->assertSame('Lastname', $teamer->getLastName());
|
$this->assertSame('Lastname', $teamer->getLastName());
|
||||||
@@ -248,9 +248,9 @@ class UserDataHandlerTest extends TestCase
|
|||||||
|
|
||||||
yield 'a claim beyond the approved role stays pending' => [
|
yield 'a claim beyond the approved role stays pending' => [
|
||||||
['ROLE_MANAGER'],
|
['ROLE_MANAGER'],
|
||||||
['ROLE_ADMIN', 'ROLE_MANAGER'],
|
['ROLE_TEAM_ADMIN', 'ROLE_MANAGER'],
|
||||||
['ROLE_MANAGER'],
|
['ROLE_MANAGER'],
|
||||||
[User::PENDING_ROLES['ROLE_ADMIN']],
|
[User::PENDING_ROLES['ROLE_TEAM_ADMIN']],
|
||||||
];
|
];
|
||||||
|
|
||||||
yield 'the claimed role changes' => [
|
yield 'the claimed role changes' => [
|
||||||
@@ -261,7 +261,7 @@ class UserDataHandlerTest extends TestCase
|
|||||||
];
|
];
|
||||||
|
|
||||||
yield 'a granted role is revoked once the CRM stops claiming it' => [
|
yield 'a granted role is revoked once the CRM stops claiming it' => [
|
||||||
['ROLE_ADMIN', 'ROLE_TEAMER'],
|
['ROLE_TEAM_ADMIN', 'ROLE_TEAMER'],
|
||||||
['ROLE_TEAMER'],
|
['ROLE_TEAMER'],
|
||||||
['ROLE_TEAMER'],
|
['ROLE_TEAMER'],
|
||||||
[],
|
[],
|
||||||
@@ -282,14 +282,14 @@ class UserDataHandlerTest extends TestCase
|
|||||||
->setFirstName('First')
|
->setFirstName('First')
|
||||||
->setLastName('Last')
|
->setLastName('Last')
|
||||||
->setEmail('[email protected]')
|
->setEmail('[email protected]')
|
||||||
->setRoles([User::PENDING_ROLES['ROLE_ADMIN']])
|
->setRoles([User::PENDING_ROLES['ROLE_TEAM_ADMIN']])
|
||||||
;
|
;
|
||||||
|
|
||||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||||
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], ['ROLE_ADMIN', 'ROLE_TEAMER']);
|
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], ['ROLE_TEAM_ADMIN', 'ROLE_TEAMER']);
|
||||||
|
|
||||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||||
$this->assertSame([User::PENDING_ROLES['ROLE_ADMIN']], $user->getPendingRoles());
|
$this->assertSame([User::PENDING_ROLES['ROLE_TEAM_ADMIN']], $user->getPendingRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -302,13 +302,13 @@ class UserDataHandlerTest extends TestCase
|
|||||||
->setFirstName('First')
|
->setFirstName('First')
|
||||||
->setLastName('Last')
|
->setLastName('Last')
|
||||||
->setEmail('[email protected]')
|
->setEmail('[email protected]')
|
||||||
->setRoles(['ROLE_ADMIN', 'ROLE_TEAMER'])
|
->setRoles(['ROLE_TEAM_ADMIN', 'ROLE_TEAMER'])
|
||||||
;
|
;
|
||||||
|
|
||||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||||
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], ['ROLE_ADMIN']);
|
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], ['ROLE_TEAM_ADMIN']);
|
||||||
|
|
||||||
$this->assertSame(['ROLE_ADMIN'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAM_ADMIN'], $user->getAssignedRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUpdateLocalUserGrantsTheTeamerRoleOnlyOnce(): void
|
public function testUpdateLocalUserGrantsTheTeamerRoleOnlyOnce(): void
|
||||||
@@ -327,8 +327,8 @@ class UserDataHandlerTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ROLE_SUPER_ADMIN is not a stored role but a flag getRoles() turns into one, so
|
* ROLE_TEAM_SUPER_ADMIN is not a stored role but a flag getRoles() turns into one, so
|
||||||
* revoking ROLE_ADMIN has to take it down explicitly - otherwise the highest privilege
|
* revoking ROLE_TEAM_ADMIN has to take it down explicitly - otherwise the highest privilege
|
||||||
* in the application would outlive the role it depends on.
|
* in the application would outlive the role it depends on.
|
||||||
*/
|
*/
|
||||||
public function testUpdateLocalUserTakesTheSuperAdminFlagDownWithRoleAdmin(): void
|
public function testUpdateLocalUserTakesTheSuperAdminFlagDownWithRoleAdmin(): void
|
||||||
@@ -337,7 +337,7 @@ class UserDataHandlerTest extends TestCase
|
|||||||
->setFirstName('First')
|
->setFirstName('First')
|
||||||
->setLastName('Last')
|
->setLastName('Last')
|
||||||
->setEmail('[email protected]')
|
->setEmail('[email protected]')
|
||||||
->setRoles(['ROLE_ADMIN', 'ROLE_TEAMER'])
|
->setRoles(['ROLE_TEAM_ADMIN', 'ROLE_TEAMER'])
|
||||||
->setSuperAdmin(true)
|
->setSuperAdmin(true)
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -346,7 +346,7 @@ class UserDataHandlerTest extends TestCase
|
|||||||
|
|
||||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||||
$this->assertFalse($user->isSuperAdmin());
|
$this->assertFalse($user->isSuperAdmin());
|
||||||
$this->assertFalse($user->hasRole('ROLE_SUPER_ADMIN'));
|
$this->assertFalse($user->hasRole('ROLE_TEAM_SUPER_ADMIN'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUpdateLocalUserKeepsTheSuperAdminFlagOfAStillClaimedAdmin(): void
|
public function testUpdateLocalUserKeepsTheSuperAdminFlagOfAStillClaimedAdmin(): void
|
||||||
@@ -355,15 +355,15 @@ class UserDataHandlerTest extends TestCase
|
|||||||
->setFirstName('First')
|
->setFirstName('First')
|
||||||
->setLastName('Last')
|
->setLastName('Last')
|
||||||
->setEmail('[email protected]')
|
->setEmail('[email protected]')
|
||||||
->setRoles(['ROLE_ADMIN', 'ROLE_TEAMER'])
|
->setRoles(['ROLE_TEAM_ADMIN', 'ROLE_TEAMER'])
|
||||||
->setSuperAdmin(true)
|
->setSuperAdmin(true)
|
||||||
;
|
;
|
||||||
|
|
||||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||||
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], ['ROLE_ADMIN']);
|
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], ['ROLE_TEAM_ADMIN']);
|
||||||
|
|
||||||
$this->assertTrue($user->isSuperAdmin());
|
$this->assertTrue($user->isSuperAdmin());
|
||||||
$this->assertTrue($user->hasRole('ROLE_SUPER_ADMIN'));
|
$this->assertTrue($user->hasRole('ROLE_TEAM_SUPER_ADMIN'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUpdateLocalUserReplacesTheHotelCodesWithTheOnesTheCrmReports(): void
|
public function testUpdateLocalUserReplacesTheHotelCodesWithTheOnesTheCrmReports(): void
|
||||||
@@ -394,7 +394,7 @@ class UserDataHandlerTest extends TestCase
|
|||||||
->setEmail('[email protected]')
|
->setEmail('[email protected]')
|
||||||
->setRoles([
|
->setRoles([
|
||||||
'ROLE_TEAMER',
|
'ROLE_TEAMER',
|
||||||
User::PENDING_ROLES['ROLE_ADMIN'],
|
User::PENDING_ROLES['ROLE_TEAM_ADMIN'],
|
||||||
User::PENDING_ROLES['ROLE_HOUSE_MANAGER'],
|
User::PENDING_ROLES['ROLE_HOUSE_MANAGER'],
|
||||||
])
|
])
|
||||||
;
|
;
|
||||||
@@ -403,8 +403,8 @@ class UserDataHandlerTest extends TestCase
|
|||||||
|
|
||||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||||
|
|
||||||
$this->assertTrue($handler->approveRole($user, 'ROLE_ADMIN'));
|
$this->assertTrue($handler->approveRole($user, 'ROLE_TEAM_ADMIN'));
|
||||||
$this->assertSame(['ROLE_TEAMER', 'ROLE_ADMIN'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAMER', 'ROLE_TEAM_ADMIN'], $user->getAssignedRoles());
|
||||||
|
|
||||||
// the other nomination is untouched: one decision at a time
|
// the other nomination is untouched: one decision at a time
|
||||||
$this->assertSame([User::PENDING_ROLES['ROLE_HOUSE_MANAGER']], $user->getPendingRoles());
|
$this->assertSame([User::PENDING_ROLES['ROLE_HOUSE_MANAGER']], $user->getPendingRoles());
|
||||||
@@ -437,13 +437,13 @@ class UserDataHandlerTest extends TestCase
|
|||||||
{
|
{
|
||||||
yield 'the CRM never claimed it' => [['ROLE_TEAMER'], 'ROLE_MANAGER'];
|
yield 'the CRM never claimed it' => [['ROLE_TEAMER'], 'ROLE_MANAGER'];
|
||||||
|
|
||||||
yield 'a different role is nominated' => [[User::PENDING_ROLES['ROLE_MANAGER']], 'ROLE_ADMIN'];
|
yield 'a different role is nominated' => [[User::PENDING_ROLES['ROLE_MANAGER']], 'ROLE_TEAM_ADMIN'];
|
||||||
|
|
||||||
yield 'already granted, so there is no marker left' => [['ROLE_ADMIN'], 'ROLE_ADMIN'];
|
yield 'already granted, so there is no marker left' => [['ROLE_TEAM_ADMIN'], 'ROLE_TEAM_ADMIN'];
|
||||||
|
|
||||||
yield 'teamer has no nomination to approve' => [['ROLE_TEAMER'], 'ROLE_TEAMER'];
|
yield 'teamer has no nomination to approve' => [['ROLE_TEAMER'], 'ROLE_TEAMER'];
|
||||||
|
|
||||||
yield 'not a role at all' => [[User::PENDING_ROLES['ROLE_ADMIN']], 'ROLE_SUPER_ADMIN'];
|
yield 'not a role at all' => [[User::PENDING_ROLES['ROLE_TEAM_ADMIN']], 'ROLE_TEAM_SUPER_ADMIN'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDisableForRevokedCrmRolesBlocksTheUserAndDropsThePendingMarkers(): void
|
public function testDisableForRevokedCrmRolesBlocksTheUserAndDropsThePendingMarkers(): void
|
||||||
@@ -452,7 +452,7 @@ class UserDataHandlerTest extends TestCase
|
|||||||
->setFirstName('First')
|
->setFirstName('First')
|
||||||
->setLastName('Last')
|
->setLastName('Last')
|
||||||
->setEmail('[email protected]')
|
->setEmail('[email protected]')
|
||||||
->setRoles(['ROLE_ADMIN', User::PENDING_ROLES['ROLE_MANAGER']])
|
->setRoles(['ROLE_TEAM_ADMIN', User::PENDING_ROLES['ROLE_MANAGER']])
|
||||||
;
|
;
|
||||||
|
|
||||||
$this->entityManager
|
$this->entityManager
|
||||||
@@ -468,7 +468,7 @@ class UserDataHandlerTest extends TestCase
|
|||||||
$this->assertSame('Automatisch gesperrt: keine Rollen in BusPro.', $user->getDisabledReasonInternal());
|
$this->assertSame('Automatisch gesperrt: keine Rollen in BusPro.', $user->getDisabledReasonInternal());
|
||||||
|
|
||||||
// the granted role is kept so the user stays reviewable, the marker is not
|
// the granted role is kept so the user stays reviewable, the marker is not
|
||||||
$this->assertSame(['ROLE_ADMIN'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAM_ADMIN'], $user->getAssignedRoles());
|
||||||
$this->assertSame([], $user->getPendingRoles());
|
$this->assertSame([], $user->getPendingRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,7 +480,7 @@ class UserDataHandlerTest extends TestCase
|
|||||||
->setFirstName('First')
|
->setFirstName('First')
|
||||||
->setLastName('Last')
|
->setLastName('Last')
|
||||||
->setEmail('[email protected]')
|
->setEmail('[email protected]')
|
||||||
->setRoles(['ROLE_ADMIN'])
|
->setRoles(['ROLE_TEAM_ADMIN'])
|
||||||
->setDisabledAt($disabledAt)
|
->setDisabledAt($disabledAt)
|
||||||
->setDisabledReason('Wegen Fehlverhaltens gesperrt.')
|
->setDisabledReason('Wegen Fehlverhaltens gesperrt.')
|
||||||
->setDisabledReasonInternal('Siehe Vorgang 4711.')
|
->setDisabledReasonInternal('Siehe Vorgang 4711.')
|
||||||
|
|||||||
@@ -30,18 +30,18 @@ class UserTest extends TestCase
|
|||||||
public function testPendingMarkersAreLabelledButNotAssignable(): void
|
public function testPendingMarkersAreLabelledButNotAssignable(): void
|
||||||
{
|
{
|
||||||
$user = (new User())->setRoles([
|
$user = (new User())->setRoles([
|
||||||
User::PENDING_ROLES['ROLE_ADMIN'],
|
User::PENDING_ROLES['ROLE_TEAM_ADMIN'],
|
||||||
User::PENDING_ROLES['ROLE_HOUSE_MANAGER'],
|
User::PENDING_ROLES['ROLE_HOUSE_MANAGER'],
|
||||||
'ROLE_TEAMER',
|
'ROLE_TEAMER',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
['Admin (nicht freigeschaltet)', 'Hausleitung (nicht freigeschaltet)', 'Teamer'],
|
['Team Admin (nicht freigeschaltet)', 'Hausleitung (nicht freigeschaltet)', 'Teamer'],
|
||||||
$user->getRolesLabels(),
|
$user->getRolesLabels(),
|
||||||
);
|
);
|
||||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
[User::PENDING_ROLES['ROLE_ADMIN'], User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
[User::PENDING_ROLES['ROLE_TEAM_ADMIN'], User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
||||||
$user->getPendingRoles(),
|
$user->getPendingRoles(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ class UserTest extends TestCase
|
|||||||
public function testSuperAdminWithRoleAdminIsValid(): void
|
public function testSuperAdminWithRoleAdminIsValid(): void
|
||||||
{
|
{
|
||||||
$user = (new User())
|
$user = (new User())
|
||||||
->setRoles(['ROLE_ADMIN'])
|
->setRoles(['ROLE_TEAM_ADMIN'])
|
||||||
->setSuperAdmin(true)
|
->setSuperAdmin(true)
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -170,19 +170,19 @@ class UserTest extends TestCase
|
|||||||
{
|
{
|
||||||
$user = (new User())->setRoles([
|
$user = (new User())->setRoles([
|
||||||
'ROLE_TEAMER',
|
'ROLE_TEAMER',
|
||||||
User::PENDING_ROLES['ROLE_ADMIN'],
|
User::PENDING_ROLES['ROLE_TEAM_ADMIN'],
|
||||||
User::PENDING_ROLES['ROLE_HOUSE_MANAGER'],
|
User::PENDING_ROLES['ROLE_HOUSE_MANAGER'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
['ROLE_ADMIN' => 'Admin', 'ROLE_HOUSE_MANAGER' => 'Hausleitung'],
|
['ROLE_TEAM_ADMIN' => 'Team Admin', 'ROLE_HOUSE_MANAGER' => 'Hausleitung'],
|
||||||
$user->getNominatedRoles(),
|
$user->getNominatedRoles(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAGrantedRoleIsNotNominated(): void
|
public function testAGrantedRoleIsNotNominated(): void
|
||||||
{
|
{
|
||||||
$user = (new User())->setRoles(['ROLE_ADMIN']);
|
$user = (new User())->setRoles(['ROLE_TEAM_ADMIN']);
|
||||||
|
|
||||||
$this->assertSame([], $user->getNominatedRoles());
|
$this->assertSame([], $user->getNominatedRoles());
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -19,7 +19,7 @@ class UserTypeTest extends KernelTestCase
|
|||||||
public function testRolesAndHotelCodesAreNotFields(): void
|
public function testRolesAndHotelCodesAreNotFields(): void
|
||||||
{
|
{
|
||||||
$user = (new User())
|
$user = (new User())
|
||||||
->setRoles(['ROLE_ADMIN'])
|
->setRoles(['ROLE_TEAM_ADMIN'])
|
||||||
->setHotelCodes(['DKS'])
|
->setHotelCodes(['DKS'])
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ class UserTypeTest extends KernelTestCase
|
|||||||
|
|
||||||
$form = $this->createForm($user);
|
$form = $this->createForm($user);
|
||||||
$form->submit([
|
$form->submit([
|
||||||
'roles' => ['ROLE_ADMIN'],
|
'roles' => ['ROLE_TEAM_ADMIN'],
|
||||||
'hotelCodes' => ['DKS'],
|
'hotelCodes' => ['DKS'],
|
||||||
'disabled' => null,
|
'disabled' => null,
|
||||||
]);
|
]);
|
||||||
@@ -49,14 +49,14 @@ class UserTypeTest extends KernelTestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Super admin is an elevation of ROLE_ADMIN, so it is not on offer for anybody else -
|
* Super admin is an elevation of ROLE_TEAM_ADMIN, so it is not on offer for anybody else -
|
||||||
* offering it would only ever produce the violation from User::validateSuperAdmin().
|
* offering it would only ever produce the violation from User::validateSuperAdmin().
|
||||||
*/
|
*/
|
||||||
public function testSuperAdminIsOnlyOfferedToAnAdmin(): void
|
public function testSuperAdminIsOnlyOfferedToAnAdmin(): void
|
||||||
{
|
{
|
||||||
$this->assertTrue($this->createForm((new User())->setRoles(['ROLE_ADMIN']))->has('superAdmin'));
|
$this->assertTrue($this->createForm((new User())->setRoles(['ROLE_TEAM_ADMIN']))->has('superAdmin'));
|
||||||
$this->assertFalse($this->createForm((new User())->setRoles(['ROLE_MANAGER']))->has('superAdmin'));
|
$this->assertFalse($this->createForm((new User())->setRoles(['ROLE_MANAGER']))->has('superAdmin'));
|
||||||
$this->assertFalse($this->createForm((new User())->setRoles([User::PENDING_ROLES['ROLE_ADMIN']]))->has('superAdmin'));
|
$this->assertFalse($this->createForm((new User())->setRoles([User::PENDING_ROLES['ROLE_TEAM_ADMIN']]))->has('superAdmin'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,7 +84,7 @@ class UserTypeTest extends KernelTestCase
|
|||||||
|
|
||||||
public function testSuperAdminIsAppointed(): void
|
public function testSuperAdminIsAppointed(): void
|
||||||
{
|
{
|
||||||
$user = (new User())->setRoles(['ROLE_ADMIN']);
|
$user = (new User())->setRoles(['ROLE_TEAM_ADMIN']);
|
||||||
|
|
||||||
$form = $this->createForm($user);
|
$form = $this->createForm($user);
|
||||||
$form->submit([
|
$form->submit([
|
||||||
@@ -98,7 +98,7 @@ class UserTypeTest extends KernelTestCase
|
|||||||
|
|
||||||
public function testSubmitBlocksTheAccountWithAReason(): void
|
public function testSubmitBlocksTheAccountWithAReason(): void
|
||||||
{
|
{
|
||||||
$user = (new User())->setRoles(['ROLE_ADMIN']);
|
$user = (new User())->setRoles(['ROLE_TEAM_ADMIN']);
|
||||||
|
|
||||||
$form = $this->createForm($user);
|
$form = $this->createForm($user);
|
||||||
$form->submit([
|
$form->submit([
|
||||||
@@ -117,7 +117,7 @@ class UserTypeTest extends KernelTestCase
|
|||||||
public function testSubmitUnblocksTheAccountAndClearsTheReasons(): void
|
public function testSubmitUnblocksTheAccountAndClearsTheReasons(): void
|
||||||
{
|
{
|
||||||
$user = (new User())
|
$user = (new User())
|
||||||
->setRoles(['ROLE_ADMIN'])
|
->setRoles(['ROLE_TEAM_ADMIN'])
|
||||||
->setDisabledAt(new \DateTimeImmutable('2026-01-01 08:00:00'))
|
->setDisabledAt(new \DateTimeImmutable('2026-01-01 08:00:00'))
|
||||||
->setDisabledReason('Für deinen Account liegt in BusPro keine Berechtigung mehr vor.')
|
->setDisabledReason('Für deinen Account liegt in BusPro keine Berechtigung mehr vor.')
|
||||||
->setDisabledReasonInternal('Automatisch gesperrt: keine Rollen in BusPro.')
|
->setDisabledReasonInternal('Automatisch gesperrt: keine Rollen in BusPro.')
|
||||||
@@ -135,13 +135,13 @@ class UserTypeTest extends KernelTestCase
|
|||||||
$this->assertFalse($user->isDisabled());
|
$this->assertFalse($user->isDisabled());
|
||||||
$this->assertNull($user->getDisabledReason());
|
$this->assertNull($user->getDisabledReason());
|
||||||
$this->assertNull($user->getDisabledReasonInternal());
|
$this->assertNull($user->getDisabledReasonInternal());
|
||||||
$this->assertSame(['ROLE_ADMIN'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAM_ADMIN'], $user->getAssignedRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSubmitUnblockingClearsTheReasonsEvenWhenTheirFieldsAreStillFilled(): void
|
public function testSubmitUnblockingClearsTheReasonsEvenWhenTheirFieldsAreStillFilled(): void
|
||||||
{
|
{
|
||||||
$user = (new User())
|
$user = (new User())
|
||||||
->setRoles(['ROLE_ADMIN'])
|
->setRoles(['ROLE_TEAM_ADMIN'])
|
||||||
->setDisabledAt(new \DateTimeImmutable('2026-01-01 08:00:00'))
|
->setDisabledAt(new \DateTimeImmutable('2026-01-01 08:00:00'))
|
||||||
->setDisabledReason('Für deinen Account liegt in BusPro keine Berechtigung mehr vor.')
|
->setDisabledReason('Für deinen Account liegt in BusPro keine Berechtigung mehr vor.')
|
||||||
->setDisabledReasonInternal('Automatisch gesperrt: keine Rollen in BusPro.')
|
->setDisabledReasonInternal('Automatisch gesperrt: keine Rollen in BusPro.')
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class BpnAuthenticatorTest extends TestCase
|
|||||||
|
|
||||||
public function testExistingUserWithoutClaimedRolesIsBlockedAndReturned(): void
|
public function testExistingUserWithoutClaimedRolesIsBlockedAndReturned(): void
|
||||||
{
|
{
|
||||||
$user = (new User())->setRoles(['ROLE_ADMIN']);
|
$user = (new User())->setRoles(['ROLE_TEAM_ADMIN']);
|
||||||
|
|
||||||
$this->stubApiClient($this->createCrmAttributes());
|
$this->stubApiClient($this->createCrmAttributes());
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ class BpnAuthenticatorTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testResponseWithoutAttributeGroupsRefusesTheLoginWithoutBlocking(): void
|
public function testResponseWithoutAttributeGroupsRefusesTheLoginWithoutBlocking(): void
|
||||||
{
|
{
|
||||||
$user = (new User())->setRoles(['ROLE_ADMIN']);
|
$user = (new User())->setRoles(['ROLE_TEAM_ADMIN']);
|
||||||
|
|
||||||
// an empty payload carries no roles either and must not read as a revocation
|
// an empty payload carries no roles either and must not read as a revocation
|
||||||
$this->stubApiClient(new CrmAttributesResponse());
|
$this->stubApiClient(new CrmAttributesResponse());
|
||||||
@@ -93,7 +93,7 @@ class BpnAuthenticatorTest extends TestCase
|
|||||||
} catch (UserNotFoundException) {
|
} catch (UserNotFoundException) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->assertSame(['ROLE_ADMIN'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAM_ADMIN'], $user->getAssignedRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -60,11 +60,11 @@ class MyEpAuthenticatorTest extends TestCase
|
|||||||
$this->repository->method('findOneBy')->willReturn(null);
|
$this->repository->method('findOneBy')->willReturn(null);
|
||||||
$this->repository->method('findBy')->willReturn([]);
|
$this->repository->method('findBy')->willReturn([]);
|
||||||
|
|
||||||
$user = $this->loadUser($this->createUserinfo(['ROLE_ADMIN', 'ROLE_TEAMER']));
|
$user = $this->loadUser($this->createUserinfo(['ROLE_TEAM_ADMIN', 'ROLE_TEAMER']));
|
||||||
|
|
||||||
$this->assertSame([User::PENDING_ROLES['ROLE_ADMIN']], $user->getPendingRoles());
|
$this->assertSame([User::PENDING_ROLES['ROLE_TEAM_ADMIN']], $user->getPendingRoles());
|
||||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||||
$this->assertNotContains('ROLE_ADMIN', $user->getRoles());
|
$this->assertNotContains('ROLE_TEAM_ADMIN', $user->getRoles());
|
||||||
$this->assertContains('ROLE_TEAMER', $user->getRoles());
|
$this->assertContains('ROLE_TEAMER', $user->getRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,14 +118,14 @@ class MyEpAuthenticatorTest extends TestCase
|
|||||||
$user = (new User())->setEmail('[email protected]')->setRoles(['ROLE_TEAMER']);
|
$user = (new User())->setEmail('[email protected]')->setRoles(['ROLE_TEAMER']);
|
||||||
$this->repository->method('findOneBy')->willReturn($user);
|
$this->repository->method('findOneBy')->willReturn($user);
|
||||||
|
|
||||||
$this->loadUser($this->createUserinfo(['ROLE_ADMIN', 'ROLE_MANAGER', 'ROLE_TEAMER']));
|
$this->loadUser($this->createUserinfo(['ROLE_TEAM_ADMIN', 'ROLE_MANAGER', 'ROLE_TEAMER']));
|
||||||
|
|
||||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
[User::PENDING_ROLES['ROLE_ADMIN'], User::PENDING_ROLES['ROLE_MANAGER']],
|
[User::PENDING_ROLES['ROLE_TEAM_ADMIN'], User::PENDING_ROLES['ROLE_MANAGER']],
|
||||||
$user->getPendingRoles(),
|
$user->getPendingRoles(),
|
||||||
);
|
);
|
||||||
$this->assertNotContains('ROLE_ADMIN', $user->getRoles());
|
$this->assertNotContains('ROLE_TEAM_ADMIN', $user->getRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -133,12 +133,12 @@ class MyEpAuthenticatorTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testAnAlreadyGrantedAdministrativeRoleIsKeptWhileStillClaimed(): void
|
public function testAnAlreadyGrantedAdministrativeRoleIsKeptWhileStillClaimed(): void
|
||||||
{
|
{
|
||||||
$user = (new User())->setEmail('[email protected]')->setRoles(['ROLE_ADMIN', 'ROLE_TEAMER']);
|
$user = (new User())->setEmail('[email protected]')->setRoles(['ROLE_TEAM_ADMIN', 'ROLE_TEAMER']);
|
||||||
$this->repository->method('findOneBy')->willReturn($user);
|
$this->repository->method('findOneBy')->willReturn($user);
|
||||||
|
|
||||||
$this->loadUser($this->createUserinfo(['ROLE_ADMIN', 'ROLE_TEAMER']));
|
$this->loadUser($this->createUserinfo(['ROLE_TEAM_ADMIN', 'ROLE_TEAMER']));
|
||||||
|
|
||||||
$this->assertSame(['ROLE_ADMIN', 'ROLE_TEAMER'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAM_ADMIN', 'ROLE_TEAMER'], $user->getAssignedRoles());
|
||||||
$this->assertSame([], $user->getPendingRoles());
|
$this->assertSame([], $user->getPendingRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ class MyEpAuthenticatorTest extends TestCase
|
|||||||
{
|
{
|
||||||
$user = (new User())
|
$user = (new User())
|
||||||
->setEmail('[email protected]')
|
->setEmail('[email protected]')
|
||||||
->setRoles(['ROLE_ADMIN', 'ROLE_TEAMER'])
|
->setRoles(['ROLE_TEAM_ADMIN', 'ROLE_TEAMER'])
|
||||||
->setSuperAdmin(true)
|
->setSuperAdmin(true)
|
||||||
->setHotelCodes(['SSL'])
|
->setHotelCodes(['SSL'])
|
||||||
;
|
;
|
||||||
@@ -163,7 +163,7 @@ class MyEpAuthenticatorTest extends TestCase
|
|||||||
|
|
||||||
// the flag would otherwise outlive the role it depends on
|
// the flag would otherwise outlive the role it depends on
|
||||||
$this->assertFalse($user->isSuperAdmin());
|
$this->assertFalse($user->isSuperAdmin());
|
||||||
$this->assertNotContains('ROLE_SUPER_ADMIN', $user->getRoles());
|
$this->assertNotContains('ROLE_TEAM_SUPER_ADMIN', $user->getRoles());
|
||||||
|
|
||||||
$this->assertSame(['HOTEL'], $user->getHotelCodes());
|
$this->assertSame(['HOTEL'], $user->getHotelCodes());
|
||||||
}
|
}
|
||||||
@@ -191,7 +191,7 @@ class MyEpAuthenticatorTest extends TestCase
|
|||||||
$this->repository->method('findOneBy')->willReturn($user);
|
$this->repository->method('findOneBy')->willReturn($user);
|
||||||
$this->entityManager->expects($this->never())->method('flush');
|
$this->entityManager->expects($this->never())->method('flush');
|
||||||
|
|
||||||
$userinfo = $this->createUserinfo(['ROLE_ADMIN', 'ROLE_TEAMER']);
|
$userinfo = $this->createUserinfo(['ROLE_TEAM_ADMIN', 'ROLE_TEAMER']);
|
||||||
$userinfo['profile']['hotel_codes'] = ['NEW'];
|
$userinfo['profile']['hotel_codes'] = ['NEW'];
|
||||||
|
|
||||||
// returned rather than refused, so the UserChecker can explain the deletion
|
// returned rather than refused, so the UserChecker can explain the deletion
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class DriverLicenseRequiredCheckTest extends TestCase
|
|||||||
public function mixedRoleProvider(): array
|
public function mixedRoleProvider(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
['ROLE_ADMIN'],
|
['ROLE_TEAM_ADMIN'],
|
||||||
['ROLE_MANAGER'],
|
['ROLE_MANAGER'],
|
||||||
['ROLE_HOUSE_MANAGER'],
|
['ROLE_HOUSE_MANAGER'],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class FinancialDataRequiredCheckTest extends TestCase
|
|||||||
public function mixedRoleProvider(): array
|
public function mixedRoleProvider(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
['ROLE_ADMIN'],
|
['ROLE_TEAM_ADMIN'],
|
||||||
['ROLE_MANAGER'],
|
['ROLE_MANAGER'],
|
||||||
['ROLE_HOUSE_MANAGER'],
|
['ROLE_HOUSE_MANAGER'],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class MealPreferenceRequiredCheckTest extends TestCase
|
|||||||
public function mixedRoleProvider(): array
|
public function mixedRoleProvider(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
['ROLE_ADMIN'],
|
['ROLE_TEAM_ADMIN'],
|
||||||
['ROLE_MANAGER'],
|
['ROLE_MANAGER'],
|
||||||
['ROLE_HOUSE_MANAGER'],
|
['ROLE_HOUSE_MANAGER'],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class PersonalDataVerificationRequiredCheckTest extends TestCase
|
|||||||
public function mixedRoleProvider(): array
|
public function mixedRoleProvider(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
['ROLE_ADMIN'],
|
['ROLE_TEAM_ADMIN'],
|
||||||
['ROLE_MANAGER'],
|
['ROLE_MANAGER'],
|
||||||
['ROLE_HOUSE_MANAGER'],
|
['ROLE_HOUSE_MANAGER'],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class UserVoterTest extends TestCase
|
|||||||
private function createUser(bool $superAdmin): User
|
private function createUser(bool $superAdmin): User
|
||||||
{
|
{
|
||||||
return (new User())
|
return (new User())
|
||||||
->setRoles(['ROLE_ADMIN'])
|
->setRoles(['ROLE_TEAM_ADMIN'])
|
||||||
->setSuperAdmin($superAdmin)
|
->setSuperAdmin($superAdmin)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,14 +97,14 @@ class AccountDeletionHandlerTest extends TestCase
|
|||||||
$teamer = new Teamer();
|
$teamer = new Teamer();
|
||||||
$user = (new User())
|
$user = (new User())
|
||||||
->setTeamer($teamer)
|
->setTeamer($teamer)
|
||||||
->setRoles(['ROLE_TEAMER', 'ROLE_ADMIN'])
|
->setRoles(['ROLE_TEAMER', 'ROLE_TEAM_ADMIN'])
|
||||||
;
|
;
|
||||||
$user->setDisabled(true);
|
$user->setDisabled(true);
|
||||||
$disabledAt = $user->getDisabledAt();
|
$disabledAt = $user->getDisabledAt();
|
||||||
|
|
||||||
$this->handler->delete($user, AccountDeletionHandler::SOURCE_ADMIN);
|
$this->handler->delete($user, AccountDeletionHandler::SOURCE_ADMIN);
|
||||||
|
|
||||||
$this->assertSame(['ROLE_TEAMER', 'ROLE_ADMIN'], $user->getAssignedRoles());
|
$this->assertSame(['ROLE_TEAMER', 'ROLE_TEAM_ADMIN'], $user->getAssignedRoles());
|
||||||
$this->assertSame($disabledAt, $user->getDisabledAt());
|
$this->assertSame($disabledAt, $user->getDisabledAt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user