ifsg: can be confirmed and edited by admins

This commit is contained in:
Xu 2024-03-05 17:42:38 +01:00 committed by Igor Scheller
parent 400edd9a19
commit 873803eb2d
19 changed files with 666 additions and 48 deletions

View File

@ -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',

View File

@ -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,
];
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Migrations;
use Engelsystem\Database\Migration\Migration;
use Illuminate\Database\Schema\Blueprint;
class AddIfsgConfirmedToUsersLicenses extends Migration
{
/**
* Run the migration
*/
public function up(): void
{
$this->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');
});
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Migrations;
use Engelsystem\Database\Migration\Migration;
class AddUserIfsgEditPermission extends Migration
{
/**
* Run the migration
*/
public function up(): void
{
$db = $this->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();
}
}

View File

@ -1,6 +1,7 @@
<?php
use Engelsystem\Database\Db;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\User\State;
use Engelsystem\Models\User\User;
@ -248,6 +249,12 @@ function user_controller()
->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,
),
];
}

View File

@ -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');
}

View File

@ -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')),
]),

View File

@ -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')

View File

@ -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."

View File

@ -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!"

View File

@ -0,0 +1,43 @@
{% extends 'pages/settings/certificates.twig' %}
{% import 'macros/form.twig' as f %}
{% import 'macros/base.twig' as m %}
{% block row_content %}
<div class="row">
{% if config('ifsg_enabled') %}
<form
action="{{ url('/users/' ~ admin_user.id ~ '/certificates/ifsg') }}"
enctype="multipart/form-data" method="post"
>
{{ csrf() }}
<div class="col-md-12 pb-3">
<h3>{{ __('settings.certificates.title.ifsg') }}</h3>
{% if config('ifsg_light_enabled') %}
{{ f.checkbox('ifsg_certificate_light', __('settings.certificates.ifsg_light_admin'), {
'checked': certificates.ifsg_certificate_light,
}) }}
{% endif %}
{{ f.checkbox('ifsg_certificate', __('settings.certificates.ifsg_admin'), {
'checked': certificates.ifsg_certificate,
}) }}
<div class="row">
<div class="col-auto">
{{ f.submit(__('form.save'), {'icon_left': 'save'}) }}
</div>
<div class="col-auto">
{{ f.checkbox(
'ifsg_confirmed',
__('settings.certificates.confirmed') ~ f.info(__('settings.certificates.confirmation.info')),
{'raw_label': true, 'checked': certificates.ifsg_confirmed}
) }}
</div>
</div>
</div>
</form>
{% endif %}
</div>
{% endblock %}

View File

@ -7,20 +7,33 @@
{% block row_content %}
<div class="row">
{% if config('ifsg_enabled') %}
<form action="{{ url('/settings/certificates/ifsg') }}" enctype="multipart/form-data" method="post">
<form
action="{{ url('/settings/certificates/ifsg') }}"
enctype="multipart/form-data" method="post"
>
{{ csrf() }}
<div class="col-md-12 pb-3">
<h3>{{ __('settings.certificates.title.ifsg') }}</h3>
{{ m.info(__('settings.certificates.info')) }}
{% if certificates.ifsg_confirmed %}
<p class="text-success">{{ __('settings.certificates.ifsg_confirmed.hint') }}</p>
{% endif %}
{% if config('ifsg_light_enabled') %}
{{ f.checkbox('ifsg_certificate_light', __('settings.certificates.ifsg_light'), {
'checked': certificates.ifsg_certificate_light,
'checked': certificates.ifsg_certificate_light,
'disabled': certificates.ifsg_confirmed,
}) }}
{% endif %}
{{ f.checkbox('ifsg_certificate', __('settings.certificates.ifsg'), {
'checked': certificates.ifsg_certificate,
'checked': certificates.ifsg_certificate,
'disabled': certificates.ifsg_confirmed,
}) }}
{{ f.submit(__('form.save'), {'icon_left': 'save'}) }}
{% if not certificates.ifsg_confirmed %}
{{ f.submit(__('form.save'), {'icon_left': 'save'}) }}
{% endif %}
</div>
</form>
{% endif %}

View File

@ -8,7 +8,12 @@
{% block container_title %}
<h1 id="settings-title">
{{ __('settings.settings') }}
<small class="text-muted">{{ block('title') }}</small>
<small class="text-muted">
{{ block('title') }}
{% if is_admin|default(false) %}
({{ admin_user.name }})
{% endif %}
</small>
</h1>
{% endblock %}
@ -16,12 +21,14 @@
<div class="col-md-3 settings-menu">
<ul class="nav nav-pills flex-column mt-3 user-settings">
{% for url,title in settings_menu %}
<li class="nav-item{% if title.hidden ?? false and url != request.url() %} d-none{% endif %}">
<a class="nav-link {% if url == request.url() %}active{% endif %}" href="{{ url }}">
{{ m.icon(title.icon ?? 'gear-fill') }}
{{ __(title.title ?? title) }}
</a>
</li>
{% if not title.permission|default(false) or has_permission_to(title.permission) %}
<li class="nav-item{% if title.hidden|default(false) and url != request.url() %} d-none{% endif %}">
<a class="nav-link {% if url == request.url() %}active{% endif %}" href="{{ url }}">
{{ m.icon(title.icon ?? 'gear-fill') }}
{{ __(title.title ?? title) }}
</a>
</li>
{% endif %}
{% endfor %}
</ul>
</div>

View File

@ -0,0 +1,142 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Controllers\Admin;
use Engelsystem\Config\Config;
use Engelsystem\Controllers\BaseController;
use Engelsystem\Controllers\HasUserNotifications;
use Engelsystem\Http\Exceptions\HttpForbidden;
use Engelsystem\Http\Exceptions\HttpNotFound;
use Engelsystem\Http\Response;
use Engelsystem\Http\Redirector;
use Engelsystem\Http\Request;
use Engelsystem\Helpers\Authenticator;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\User\User;
use Psr\Log\LoggerInterface;
class UserSettingsController extends BaseController
{
use HasUserNotifications;
public function __construct(
protected Authenticator $auth,
protected Config $config,
protected LoggerInterface $log,
protected Redirector $redirect,
protected Response $response
) {
}
public function certificate(Request $request): Response
{
if (!config('ifsg_enabled')) {
throw new HttpNotFound();
}
$this->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();
}
}

View File

@ -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');

View File

@ -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)

View File

@ -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<string, bool> 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<string> */
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',
];
/**

View File

@ -0,0 +1,235 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Test\Unit\Controllers\Admin;
use Engelsystem\Controllers\Admin\UserSettingsController;
use Engelsystem\Helpers\Authenticator;
use Engelsystem\Http\Exceptions\HttpForbidden;
use Engelsystem\Http\Exceptions\HttpNotFound;
use Engelsystem\Http\Response;
use Engelsystem\Http\UrlGenerator;
use Engelsystem\Http\Validation\Validator;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\User\License;
use Engelsystem\Models\User\User;
use Engelsystem\Test\Unit\Controllers\ControllerTest;
use Engelsystem\Test\Unit\HasDatabase;
use PHPUnit\Framework\MockObject\MockObject;
class UserSettingsControllerTest extends ControllerTest
{
use HasDatabase;
protected Authenticator | MockObject $auth;
protected User $user;
protected User $userChanged;
protected UserSettingsController $controller;
/**
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::certificate
*/
public function testCertificateDisabled(): void
{
config(['ifsg_enabled' => 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());
}
}

View File

@ -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);