diff --git a/config/routes.php b/config/routes.php
index 237e2a63..0e8bcdbc 100644
--- a/config/routes.php
+++ b/config/routes.php
@@ -51,6 +51,15 @@ $route->addGroup(
}
);
+// User admin settings
+$route->addGroup(
+ '/users/{user_id:\d+}',
+ function (RouteCollector $route): void {
+ $route->get('/certificates', 'Admin\\UserSettingsController@certificate');
+ $route->post('/certificates/ifsg', 'Admin\\UserSettingsController@saveIfsgCertificate');
+ }
+);
+
// Password recovery
$route->addGroup(
'/password/reset',
diff --git a/db/factories/User/LicenseFactory.php b/db/factories/User/LicenseFactory.php
index 5240c971..19f0c7e8 100644
--- a/db/factories/User/LicenseFactory.php
+++ b/db/factories/User/LicenseFactory.php
@@ -24,6 +24,7 @@ class LicenseFactory extends Factory
$ifsg_certificate = $this->faker->boolean(0.1);
$ifsg_certificate_light = $this->faker->boolean(0.5) && !$ifsg_certificate;
+ $ifsg_confirmed = $this->faker->boolean(0.5) && ($ifsg_certificate || $ifsg_certificate_light);
return [
'user_id' => User::factory(),
@@ -35,6 +36,7 @@ class LicenseFactory extends Factory
'drive_12t' => $drive_12t,
'ifsg_certificate' => $ifsg_certificate,
'ifsg_certificate_light' => $ifsg_certificate_light,
+ 'ifsg_confirmed' => $ifsg_confirmed,
];
}
}
diff --git a/db/migrations/2024_03_05_000000_add_ifsg_confirmed_to_users_licenses.php b/db/migrations/2024_03_05_000000_add_ifsg_confirmed_to_users_licenses.php
new file mode 100644
index 00000000..f4efb70e
--- /dev/null
+++ b/db/migrations/2024_03_05_000000_add_ifsg_confirmed_to_users_licenses.php
@@ -0,0 +1,31 @@
+schema->table('users_licenses', function (Blueprint $table): void {
+ $table->boolean('ifsg_confirmed')->default(false)->after('ifsg_certificate');
+ });
+ }
+
+ /**
+ * Reverse the migration
+ */
+ public function down(): void
+ {
+ $this->schema->table('users_licenses', function (Blueprint $table): void {
+ $table->dropColumn('ifsg_confirmed');
+ });
+ }
+}
diff --git a/db/migrations/2024_03_05_000001_add_user_ifsg_edit_permission.php b/db/migrations/2024_03_05_000001_add_user_ifsg_edit_permission.php
new file mode 100644
index 00000000..96ab3d4e
--- /dev/null
+++ b/db/migrations/2024_03_05_000001_add_user_ifsg_edit_permission.php
@@ -0,0 +1,46 @@
+schema->getConnection();
+ $db->table('privileges')
+ ->insert([
+ 'name' => 'user.ifsg.edit', 'description' => 'Edit IfSG Certificate',
+ ]);
+
+ $editIfsg = $db->table('privileges')
+ ->where('name', 'user.ifsg.edit')
+ ->get(['id'])
+ ->first();
+
+ $shico = 60;
+ $team_coordinator = 65;
+ $db->table('group_privileges')
+ ->insertOrIgnore([
+ ['group_id' => $shico, 'privilege_id' => $editIfsg->id],
+ ['group_id' => $team_coordinator, 'privilege_id' => $editIfsg->id],
+ ]);
+ }
+
+ /**
+ * Reverse the migration
+ */
+ public function down(): void
+ {
+ $db = $this->schema->getConnection();
+ $db->table('privileges')
+ ->where('name', 'user.ifsg.edit')
+ ->delete();
+ }
+}
diff --git a/includes/controller/users_controller.php b/includes/controller/users_controller.php
index c1fe0022..c6dab7fd 100644
--- a/includes/controller/users_controller.php
+++ b/includes/controller/users_controller.php
@@ -1,6 +1,7 @@
with(['user', 'creator'])
->get();
+ $is_ifsg_supporter = (bool) AngelType::whereRequiresIfsgCertificate(true)
+ ->leftJoin('user_angel_type', 'user_angel_type.angel_type_id', 'angel_types.id')
+ ->where('user_angel_type.user_id', $user->id)
+ ->where('user_angel_type.supporter', true)
+ ->count();
+
return [
htmlspecialchars($user_source->displayName),
User_view(
@@ -261,7 +268,8 @@ function user_controller()
$tshirt_score,
auth()->can('admin_active'),
auth()->can('admin_user_worklog'),
- $worklogs
+ $worklogs,
+ auth()->can('user.ifsg.edit') || $is_ifsg_supporter,
),
];
}
diff --git a/includes/view/AngelTypes_view.php b/includes/view/AngelTypes_view.php
index 78ae5fa1..1bdc3880 100644
--- a/includes/view/AngelTypes_view.php
+++ b/includes/view/AngelTypes_view.php
@@ -197,10 +197,10 @@ function AngelType_view_buttons(
if ($angeltype->requires_driver_license) {
$buttons[] = button(
url('/settings/certificates'),
- icon('person-vcard') . __('my driving license')
+ icon('person-vcard') . __('My driving license')
);
}
- if (config('isfg_enabled') && $angeltype->requires_ifsg_certificate) {
+ if (config('ifsg_enabled') && $angeltype->requires_ifsg_certificate) {
$buttons[] = button(
url('/settings/certificates'),
icon('card-checklist') . __('angeltype.ifsg.own')
@@ -294,14 +294,35 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
$member['has_license_forklift'] = icon_bool($member->license->drive_forklift);
}
if ($angeltype->requires_ifsg_certificate && config('ifsg_enabled')) {
- $member['ifsg_certificate'] = icon_bool($member->license->ifsg_certificate);
+ $ifsg_certificate = $member->license->ifsg_certificate;
+ $member['ifsg_certificate'] = ($member->license->ifsg_confirmed && $ifsg_certificate)
+ ? icon('check2-all', 'text-success')
+ : icon_bool($ifsg_certificate);
if (config('ifsg_light_enabled')) {
- $member['ifsg_certificate_light'] = icon_bool($member->license->ifsg_certificate_light);
+ $ifsg_certificate_light = $member->license->ifsg_certificate_light;
+ $member['ifsg_certificate_light'] = ($member->license->ifsg_confirmed && $ifsg_certificate_light)
+ ? icon('check2-all', 'text-success')
+ : icon_bool($ifsg_certificate_light);
}
}
+ $edit_certificates = '';
+ if (
+ ($angeltype->requires_driver_license || $angeltype->requires_ifsg_certificate)
+ && ($admin_user_angeltypes || auth()->can('user.ifsg.edit'))
+ ) {
+ $edit_certificates =
+ button(
+ url('/users/' . $member->id . '/certificates'),
+ icon('card-checklist'),
+ 'btn-sm',
+ '',
+ __('Edit certificates'),
+ );
+ }
if ($angeltype->restricted && empty($member->pivot->confirm_user_id)) {
$member['actions'] = table_buttons([
+ $edit_certificates,
button(
url(
'/user-angeltypes',
@@ -323,6 +344,7 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
} elseif ($member->pivot->supporter) {
if ($admin_angeltypes || ($admin_user_angeltypes && config('supporters_can_promote'))) {
$member['actions'] = table_buttons([
+ $edit_certificates,
button(
url('/user-angeltypes', [
'action' => 'update',
@@ -336,12 +358,15 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
),
]);
} else {
- $member['actions'] = '';
+ $member['actions'] = $edit_certificates
+ ? table_buttons([$edit_certificates,])
+ : '';
}
$supporters[] = $member;
} else {
if ($admin_user_angeltypes) {
$member['actions'] = table_buttons([
+ $edit_certificates,
($admin_angeltypes || config('supporters_can_promote')) ?
button(
url('/user-angeltypes', [
@@ -366,6 +391,10 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
__('Remove'),
),
]);
+ } elseif ($edit_certificates) {
+ $member['actions'] = table_buttons([
+ $edit_certificates,
+ ]);
}
$members_confirmed[] = $member;
}
@@ -408,7 +437,10 @@ function AngelType_view_table_headers(AngelType $angeltype, $supporter, $admin_a
]);
}
- if (config('ifsg_enabled') && $angeltype->requires_ifsg_certificate && ($supporter || $admin_angeltypes)) {
+ if (
+ config('ifsg_enabled') && $angeltype->requires_ifsg_certificate
+ && ($supporter || $admin_angeltypes || auth()->can('user.ifsg.edit'))
+ ) {
if (config('ifsg_light_enabled')) {
$headers['ifsg_certificate_light'] = __('ifsg.certificate_light');
}
diff --git a/includes/view/UserAngelTypes_view.php b/includes/view/UserAngelTypes_view.php
index aa916256..d559d450 100644
--- a/includes/view/UserAngelTypes_view.php
+++ b/includes/view/UserAngelTypes_view.php
@@ -151,7 +151,9 @@ function UserAngelType_add_view(AngelType $angeltype, $users_source, $user_id)
msg(),
form([
form_info(__('Angeltype'), htmlspecialchars($angeltype->name)),
- form_checkbox('auto_confirm_user', __('Confirm user'), true),
+ $angeltype->restricted
+ ? form_checkbox('auto_confirm_user', __('Confirm user'), true)
+ : '',
form_select('user_id', __('general.user'), $users, $user_id),
form_submit('submit', icon('plus-lg') . __('Add')),
]),
diff --git a/includes/view/User_view.php b/includes/view/User_view.php
index aef21678..73794ffd 100644
--- a/includes/view/User_view.php
+++ b/includes/view/User_view.php
@@ -532,6 +532,7 @@ function User_view_worklog(Worklog $worklog, $admin_user_worklog_privilege)
* @param bool $tshirt_admin
* @param bool $admin_user_worklog_privilege
* @param Worklog[]|Collection $user_worklogs
+ * @param bool $admin_ifsg
*
* @return string
*/
@@ -546,7 +547,8 @@ function User_view(
$tshirt_score,
$tshirt_admin,
$admin_user_worklog_privilege,
- $user_worklogs
+ $user_worklogs,
+ $admin_ifsg
) {
$goodie = GoodieType::from(config('goodie_type'));
$goodie_enabled = $goodie !== GoodieType::None;
@@ -629,6 +631,10 @@ function User_view(
icon('valentine') . __('Vouchers')
)
: '',
+ $admin_ifsg ? button(
+ url('/users/' . $user_source->id . '/certificates'),
+ icon('card-checklist') . __('settings.certificates')
+ ) : '',
$admin_user_worklog_privilege ? button(
url('/admin/user/' . $user_source->id . '/worklog'),
icon('clock-history') . __('worklog.add')
diff --git a/resources/lang/de_DE/default.po b/resources/lang/de_DE/default.po
index 2e7f470c..4397b419 100644
--- a/resources/lang/de_DE/default.po
+++ b/resources/lang/de_DE/default.po
@@ -368,6 +368,9 @@ msgstr "Du darfst diesen Benutzer nicht von diesem Engeltyp entfernen."
msgid "User %s removed from %s."
msgstr "Benutzer %s von %s entfernt."
+msgid "Edit certificates"
+msgstr "Zertifikate bearbeiten"
+
msgid "Remove angeltype"
msgstr "Engeltyp löschen"
@@ -911,7 +914,7 @@ msgstr "Kontakt"
msgid "Primary contact person/desk for user questions."
msgstr "Ansprechpartner für Fragen."
-msgid "my driving license"
+msgid "My driving license"
msgstr "Meine Führerschein-Infos"
msgid ""
@@ -1736,11 +1739,28 @@ msgstr "Gabelstapler"
msgid "settings.certificates.ifsg_light"
msgstr "Ich wurde vor Ort nach IfSG §43 (Frikadellendiplom light) belehrt."
+msgid "settings.certificates.ifsg_light_admin"
+msgstr "Wurde vor Ort nach IfSG §43 (Frikadellendiplom light) belehrt."
+
msgid "settings.certificates.ifsg"
msgstr "Ich habe eine Belehrung nach §43 IfSG (Frikadellendiplom) bei meinem Gesundheitsamt "
"erhalten und innerhalb von 3 Monaten die Zweitbelehrung durch uns oder meinen Arbeitgeber/Koch/Verein bekommen. "
"Zusätzlich ist die Zweitbelehrung nicht älter als zwei Jahre."
+msgid "settings.certificates.ifsg_admin"
+msgstr "Hat eine Belehrung nach §43 IfSG (Frikadellendiplom) vom Gesundheitsamt "
+"erhalten und innerhalb von 3 Monaten die Zweitbelehrung durch uns oder einen Arbeitgeber/Koch/Verein bekommen. "
+"Zusätzlich ist die Zweitbelehrung nicht älter als zwei Jahre."
+
+msgid "settings.certificates.confirmed"
+msgstr "Zertifikat bestätigt"
+
+msgid "settings.certificates.ifsg_confirmed.hint"
+msgstr "Deine Gesundheitsbelehrung wurde bestätigt, du kannst deine Angaben nicht mehr selber ändern."
+
+msgid "settings.certificates.confirmation.info"
+msgstr "Du hast persönlich überprüft, dass die Zertifizierung / Bescheinigung den Anforderungen genügt."
+
msgid "settings.certificates.success"
msgstr "Zertifikate wurden erfolgreich aktualisiert."
diff --git a/resources/lang/en_US/default.po b/resources/lang/en_US/default.po
index 4d3248b1..39ee1995 100644
--- a/resources/lang/en_US/default.po
+++ b/resources/lang/en_US/default.po
@@ -437,11 +437,28 @@ msgstr "Forklift"
msgid "settings.certificates.ifsg_light"
msgstr "I was instructed about IfSG §43 (aka Frikadellendiplom light) on site."
+msgid "settings.certificates.ifsg_light_admin"
+msgstr "Was instructed about IfSG §43 (aka Frikadellendiplom light) on site."
+
msgid "settings.certificates.ifsg"
msgstr "I have gotten the instruction about §43 IfSG (aka Frikadellendiplom) from my Health Department "
-"and a second instruction from us or my employer/chef/assosiation within 3 months. "
+"and a second instruction from us or my employer/chef/association within 3 months. "
"Additionally my second instruction is not older than 2 years."
+msgid "settings.certificates.ifsg_admin"
+msgstr "Got the instruction about §43 IfSG (aka Frikadellendiplom) from a Health Department "
+"and a second instruction from us or his employer/chef/association within 3 months. "
+"Additionally the second instruction is not older than 2 years."
+
+msgid "settings.certificates.confirmed"
+msgstr "Certificate confirmed"
+
+msgid "settings.certificates.ifsg_confirmed.hint"
+msgstr "Your health instruction has been confirmed, you can no longer change it by yourself."
+
+msgid "settings.certificates.confirmation.info"
+msgstr "You personally checked that the certificate / license meets the requirements."
+
msgid "settings.certificates.success"
msgstr "Certificates were updated successfully."
@@ -449,13 +466,13 @@ msgid "angeltype.ifsg.required"
msgstr "Requires health instruction"
msgid "ifsg.certificate"
-msgstr "health instruction"
+msgstr "Health instruction"
msgid "ifsg.certificate_light"
-msgstr "health instruction on site"
+msgstr "Health instruction on site"
msgid "angeltype.ifsg.own"
-msgstr "my health instruction"
+msgstr "My health instruction"
msgid "angeltype.ifsg.required.info"
msgstr "This angeltype requires a health instruction. Please enter your health instruction information!"
diff --git a/resources/views/pages/settings/certificates-admin.twig b/resources/views/pages/settings/certificates-admin.twig
new file mode 100644
index 00000000..f993f97b
--- /dev/null
+++ b/resources/views/pages/settings/certificates-admin.twig
@@ -0,0 +1,43 @@
+{% extends 'pages/settings/certificates.twig' %}
+{% import 'macros/form.twig' as f %}
+{% import 'macros/base.twig' as m %}
+
+{% block row_content %}
+
+
+ {% if config('ifsg_enabled') %}
+
+ {% endif %}
+
+
+{% endblock %}
diff --git a/resources/views/pages/settings/certificates.twig b/resources/views/pages/settings/certificates.twig
index d0d1eb78..3fba994d 100644
--- a/resources/views/pages/settings/certificates.twig
+++ b/resources/views/pages/settings/certificates.twig
@@ -7,20 +7,33 @@
{% block row_content %}
{% if config('ifsg_enabled') %}
-
{% endif %}
diff --git a/resources/views/pages/settings/settings.twig b/resources/views/pages/settings/settings.twig
index 35034ee3..bf54bbb5 100644
--- a/resources/views/pages/settings/settings.twig
+++ b/resources/views/pages/settings/settings.twig
@@ -8,7 +8,12 @@
{% block container_title %}
{{ __('settings.settings') }}
- {{ block('title') }}
+
+ {{ block('title') }}
+ {% if is_admin|default(false) %}
+ ({{ admin_user.name }})
+ {% endif %}
+
{% endblock %}
@@ -16,12 +21,14 @@
diff --git a/src/Controllers/Admin/UserSettingsController.php b/src/Controllers/Admin/UserSettingsController.php
new file mode 100644
index 00000000..0b753f9e
--- /dev/null
+++ b/src/Controllers/Admin/UserSettingsController.php
@@ -0,0 +1,142 @@
+checkPermission('user.ifsg.edit', $this->isIfsgSupporter());
+ $user = $this->getUser($request);
+
+ return $this->view(
+ $user,
+ 'pages/settings/certificates-admin',
+ [
+ 'certificates' => $user->license,
+ ]
+ );
+ }
+
+ public function saveIfsgCertificate(Request $request): Response
+ {
+ if (!config('ifsg_enabled')) {
+ throw new HttpNotFound();
+ }
+
+ $this->checkPermission('user.ifsg.edit', $this->isIfsgSupporter());
+ $user = $this->getUser($request);
+
+ $data = $this->validate($request, [
+ 'ifsg_certificate_light' => 'optional|checked',
+ 'ifsg_certificate' => 'optional|checked',
+ 'ifsg_confirmed' => 'optional|checked',
+ ]);
+
+ if (config('ifsg_light_enabled')) {
+ $user->license->ifsg_certificate_light = !$data['ifsg_certificate'] && $data['ifsg_certificate_light'];
+ }
+ $user->license->ifsg_certificate = (bool) $data['ifsg_certificate'];
+ $user->license->ifsg_confirmed = $data['ifsg_confirmed']
+ && ($user->license->ifsg_certificate || $user->license->ifsg_certificate_light);
+
+ $user->license->save();
+ $this->addNotification('settings.certificates.success');
+ $this->log->info('Certificate "{certificate}" of user {user} ({id}) is {confirmation}.', [
+ 'certificate' => $user->license->ifsg_certificate_light
+ ? 'IfSG light'
+ : ($user->license->ifsg_certificate
+ ? 'IfSG'
+ : 'no IfSG'
+ ),
+ 'user' => $user->name,
+ 'id' => $user->id,
+ 'confirmation' => $user->license->ifsg_confirmed ? 'confirmed' : 'unconfirmed',
+ ]);
+
+ return $this->redirect->to('/users/' . $user->id . '/certificates');
+ }
+
+ public function settingsMenu(User $user): array
+ {
+ $menu = [
+ url('/users', ['action' => 'view', 'user_id' => $user->id]) => [
+ 'title' => 'general.back', 'icon' => 'chevron-left',
+ ],
+ ];
+
+ if (config('ifsg_enabled')) {
+ $menu[url('/users/' . $user->id . '/certificates')] = [
+ 'title' => 'settings.certificates',
+ 'icon' => 'card-checklist',
+ 'permission' => $this->isIfsgSupporter() ? null : 'user.ifsg.edit',
+ ];
+ }
+
+ return $menu;
+ }
+
+ protected function checkPermission(string | array $abilities, bool $overwrite = false): void
+ {
+ if (!$overwrite && !$this->auth->can($abilities)) {
+ throw new HttpForbidden();
+ }
+ }
+
+ protected function view(User $user, string $view, array $data = []): Response
+ {
+ return $this->response->withView(
+ $view,
+ array_merge([
+ 'settings_menu' => $this->settingsMenu($user),
+ 'is_admin' => true,
+ 'admin_user' => $user,
+ ], $data)
+ );
+ }
+
+ protected function getUser(Request $request): User
+ {
+ $userId = $request->getAttribute('user_id');
+ return User::findOrFail($userId);
+ }
+
+ public function isIfsgSupporter(): bool
+ {
+ return (bool) AngelType::whereRequiresIfsgCertificate(true)
+ ->leftJoin('user_angel_type', 'user_angel_type.angel_type_id', 'angel_types.id')
+ ->where('user_angel_type.user_id', $this->auth->user()?->id)
+ ->where('user_angel_type.supporter', true)
+ ->count();
+ }
+}
diff --git a/src/Controllers/SettingsController.php b/src/Controllers/SettingsController.php
index a6fbc8e4..e0c9697b 100644
--- a/src/Controllers/SettingsController.php
+++ b/src/Controllers/SettingsController.php
@@ -242,29 +242,28 @@ class SettingsController extends BaseController
public function certificate(): Response
{
- $user = $this->auth->user();
-
if (!config('ifsg_enabled') && !$this->checkDrivingLicense()) {
throw new HttpNotFound();
}
+ $user = $this->auth->user();
return $this->response->withView(
'pages/settings/certificates',
[
- 'settings_menu' => $this->settingsMenu(),
- 'driving_license' => $this->checkDrivingLicense(),
- 'certificates' => $user->license,
+ 'settings_menu' => $this->settingsMenu(),
+ 'driving_license' => $this->checkDrivingLicense(),
+ 'certificates' => $user->license,
]
);
}
public function saveIfsgCertificate(Request $request): Response
{
- if (!config('ifsg_enabled')) {
+ $user = $this->auth->user();
+ if (!config('ifsg_enabled') || $user->license->ifsg_confirmed) {
throw new HttpNotFound();
}
- $user = $this->auth->user();
$data = $this->validate($request, [
'ifsg_certificate_light' => 'optional|checked',
'ifsg_certificate' => 'optional|checked',
@@ -274,8 +273,8 @@ class SettingsController extends BaseController
$user->license->ifsg_certificate_light = !$data['ifsg_certificate'] && $data['ifsg_certificate_light'];
}
$user->license->ifsg_certificate = (bool) $data['ifsg_certificate'];
- $user->license->save();
+ $user->license->save();
$this->addNotification('settings.certificates.success');
return $this->redirect->to('/settings/certificates');
diff --git a/src/Models/AngelType.php b/src/Models/AngelType.php
index 3fdca538..1db06014 100644
--- a/src/Models/AngelType.php
+++ b/src/Models/AngelType.php
@@ -42,6 +42,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
* @method static QueryBuilder|AngelType[] whereContactEmail($value)
* @method static QueryBuilder|AngelType[] whereRestricted($value)
* @method static QueryBuilder|AngelType[] whereRequiresDriverLicense($value)
+ * @method static QueryBuilder|AngelType[] whereRequiresIfsgCertificate($value)
* @method static QueryBuilder|AngelType[] whereNoSelfSignup($value)
* @method static QueryBuilder|AngelType[] whereShowOnDashboard($value)
* @method static QueryBuilder|AngelType[] whereHideRegister($value)
diff --git a/src/Models/User/License.php b/src/Models/User/License.php
index a25102bb..565ef292 100644
--- a/src/Models/User/License.php
+++ b/src/Models/User/License.php
@@ -16,6 +16,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
* @property bool $drive_12t
* @property bool $ifsg_certificate_light
* @property bool $ifsg_certificate
+ * @property bool $ifsg_confirmed
*
* @method static QueryBuilder|License[] whereHasCar($value)
* @method static QueryBuilder|License[] whereDriveForklift($value)
@@ -25,6 +26,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
* @method static QueryBuilder|License[] whereDrive12T($value)
* @method static QueryBuilder|License[] whereIfsgCertificateLight($value)
* @method static QueryBuilder|License[] whereIfsgCertificate($value)
+ * @method static QueryBuilder|License[] whereIfsgConfirmed($value)
*/
class License extends HasUserModel
{
@@ -35,14 +37,15 @@ class License extends HasUserModel
/** @var array
Default attributes */
protected $attributes = [ // phpcs:ignore
- 'has_car' => false,
- 'drive_forklift' => false,
- 'drive_car' => false,
- 'drive_3_5t' => false,
- 'drive_7_5t' => false,
- 'drive_12t' => false,
+ 'has_car' => false,
+ 'drive_forklift' => false,
+ 'drive_car' => false,
+ 'drive_3_5t' => false,
+ 'drive_7_5t' => false,
+ 'drive_12t' => false,
'ifsg_certificate_light' => false,
- 'ifsg_certificate' => false,
+ 'ifsg_certificate' => false,
+ 'ifsg_confirmed' => false,
];
/**
@@ -60,18 +63,20 @@ class License extends HasUserModel
'drive_12t',
'ifsg_certificate_light',
'ifsg_certificate',
+ 'ifsg_confirmed',
];
/** @var array */
protected $casts = [ // phpcs:ignore
- 'has_car' => 'boolean',
- 'drive_forklift' => 'boolean',
- 'drive_car' => 'boolean',
- 'drive_3_5t' => 'boolean',
- 'drive_7_5t' => 'boolean',
- 'drive_12t' => 'boolean',
+ 'has_car' => 'boolean',
+ 'drive_forklift' => 'boolean',
+ 'drive_car' => 'boolean',
+ 'drive_3_5t' => 'boolean',
+ 'drive_7_5t' => 'boolean',
+ 'drive_12t' => 'boolean',
'ifsg_certificate_light' => 'boolean',
- 'ifsg_certificate' => 'boolean',
+ 'ifsg_certificate' => 'boolean',
+ 'ifsg_confirmed' => 'boolean',
];
/**
diff --git a/tests/Unit/Controllers/Admin/UserSettingsControllerTest.php b/tests/Unit/Controllers/Admin/UserSettingsControllerTest.php
new file mode 100644
index 00000000..96b9d42a
--- /dev/null
+++ b/tests/Unit/Controllers/Admin/UserSettingsControllerTest.php
@@ -0,0 +1,235 @@
+ false]);
+
+ $this->expectException(HttpNotFound::class);
+ $this->controller->certificate($this->request);
+ }
+
+ /**
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::checkPermission
+ */
+ public function testCertificateNotAllowed(): void
+ {
+ config(['ifsg_enabled' => true]);
+
+ $this->expectException(HttpForbidden::class);
+ $this->controller->certificate($this->request);
+ }
+
+ /**
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::__construct
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::certificate
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::checkPermission
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::getUser
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::view
+ */
+ public function testCertificateByPermission(): void
+ {
+ config(['ifsg_enabled' => true]);
+ $this->setExpects($this->auth, 'can', ['user.ifsg.edit'], true, $this->atLeastOnce());
+
+ $this->response->expects($this->once())
+ ->method('withView')
+ ->willReturnCallback(function (string $view, array $data): Response {
+ $this->assertArrayHasKey('certificates', $data);
+ $this->assertArrayHasKey('settings_menu', $data);
+ $this->assertArrayHasKey('is_admin', $data);
+ $this->assertTrue($data['is_admin']);
+ $this->assertArrayHasKey('admin_user', $data);
+ $this->assertEquals($this->userChanged->id, $data['admin_user']->id);
+ return $this->response;
+ });
+
+ $this->controller->certificate($this->request);
+ }
+
+ /**
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::certificate
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::checkPermission
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::isIfsgSupporter
+ */
+ public function testCertificateByAngelTypeSupporter(): void
+ {
+ config(['ifsg_enabled' => true]);
+ $this->setExpects($this->response, 'withView', null, $this->response);
+
+ $angelType = AngelType::factory()->create(['requires_ifsg_certificate' => true]);
+ $this->user->userAngelTypes()->attach($angelType, ['supporter' => true]);
+
+ $this->controller->certificate($this->request);
+ }
+
+ /**
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::saveIfsgCertificate
+ */
+ public function testSaveIfsgCertificateDisabled(): void
+ {
+ config(['ifsg_enabled' => false]);
+
+ $this->expectException(HttpNotFound::class);
+ $this->controller->saveIfsgCertificate($this->request);
+ }
+
+ /**
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::saveIfsgCertificate
+ */
+ public function testSaveIfsgCertificateNotAllowed(): void
+ {
+ config(['ifsg_enabled' => true]);
+
+ $this->expectException(HttpForbidden::class);
+ $this->controller->saveIfsgCertificate($this->request);
+ }
+
+ /**
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::saveIfsgCertificate
+ */
+ public function testSaveIfsgCertificateConfirmed(): void
+ {
+ config(['ifsg_enabled' => true]);
+ $this->setExpects($this->auth, 'can', ['user.ifsg.edit'], true, $this->atLeastOnce());
+
+ $body = [
+ 'ifsg_certificate' => true,
+ 'ifsg_confirmed' => true,
+ ];
+ $this->request = $this->request->withParsedBody($body);
+
+ $this->response->expects($this->once())
+ ->method('redirectTo')
+ ->with('http://localhost/users/' . $this->userChanged->id . '/certificates')
+ ->willReturn($this->response);
+
+ $this->controller->saveIfsgCertificate($this->request);
+ $this->assertTrue($this->log->hasInfoThatContains('Certificate'));
+
+ $this->assertFalse($this->userChanged->license->ifsg_certificate_light);
+ $this->assertTrue($this->userChanged->license->ifsg_certificate);
+ $this->assertTrue($this->userChanged->license->ifsg_confirmed);
+ }
+
+ /**
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::saveIfsgCertificate
+ */
+ public function testSaveIfsgCertificate(): void
+ {
+ config(['ifsg_enabled' => true]);
+ $this->setExpects($this->auth, 'can', ['user.ifsg.edit'], true, $this->atLeastOnce());
+
+ $body = [
+ 'ifsg_certificate' => true,
+ ];
+ $this->request = $this->request->withParsedBody($body);
+
+ $this->response->expects($this->once())
+ ->method('redirectTo')
+ ->with('http://localhost/users/' . $this->userChanged->id . '/certificates')
+ ->willReturn($this->response);
+
+ $this->controller->saveIfsgCertificate($this->request);
+
+ $this->assertFalse($this->userChanged->license->ifsg_certificate_light);
+ $this->assertTrue($this->userChanged->license->ifsg_certificate);
+ $this->assertFalse($this->userChanged->license->ifsg_confirmed);
+ }
+
+ /**
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::saveIfsgCertificate
+ */
+ public function testSaveIfsgCertificateLite(): void
+ {
+ config(['ifsg_enabled' => true, 'ifsg_light_enabled' => true]);
+ $this->setExpects($this->auth, 'can', ['user.ifsg.edit'], true, $this->atLeastOnce());
+
+ $body = [
+ 'ifsg_certificate_light' => true,
+ ];
+ $this->request = $this->request->withParsedBody($body);
+
+ $this->response->expects($this->once())
+ ->method('redirectTo')
+ ->with('http://localhost/users/' . $this->userChanged->id . '/certificates')
+ ->willReturn($this->response);
+
+ $this->controller->saveIfsgCertificate($this->request);
+
+ $this->assertTrue($this->userChanged->license->ifsg_certificate_light);
+ $this->assertFalse($this->userChanged->license->ifsg_certificate);
+ $this->assertFalse($this->userChanged->license->ifsg_confirmed);
+ }
+
+ /**
+ * @covers \Engelsystem\Controllers\Admin\UserSettingsController::settingsMenu
+ */
+ public function testSettingsMenu(): void
+ {
+ $menu = $this->controller->settingsMenu($this->userChanged);
+ $this->assertArrayHasKey('http://localhost/users?action=view&user_id=' . $this->userChanged->id, $menu);
+
+ config(['ifsg_enabled' => true]);
+ $menu = $this->controller->settingsMenu($this->userChanged);
+ $this->assertArrayHasKey('http://localhost/users/' . $this->userChanged->id . '/certificates', $menu);
+ }
+
+ /**
+ * Setup environment
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ $this->app->bind('http.urlGenerator', UrlGenerator::class);
+
+ $this->user = User::factory()->create();
+
+ $this->userChanged = User::factory()
+ ->has(License::factory())
+ ->create();
+
+ $this->auth = $this->createMock(Authenticator::class);
+ $this->app->instance(Authenticator::class, $this->auth);
+
+ $this->setExpects($this->auth, 'user', null, $this->user, $this->any());
+
+ $this->request = $this->request->withAttribute('user_id', $this->userChanged->id);
+
+ $this->controller = $this->app->make(UserSettingsController::class);
+ $this->controller->setValidator(new Validator());
+ }
+}
diff --git a/tests/Unit/Controllers/SettingsControllerTest.php b/tests/Unit/Controllers/SettingsControllerTest.php
index af961809..8aabac29 100644
--- a/tests/Unit/Controllers/SettingsControllerTest.php
+++ b/tests/Unit/Controllers/SettingsControllerTest.php
@@ -805,7 +805,7 @@ class SettingsControllerTest extends ControllerTest
$this->setExpects($this->auth, 'user', null, $this->user, $this->once());
$body = [
- 'ifsg_certificate' => true,
+ 'ifsg_certificate' => true,
];
$this->request = $this->request->withParsedBody($body);