driving license: can be confirmed and edited by admins and config options

This commit is contained in:
Xu 2024-03-14 18:33:57 +01:00 committed by Igor Scheller
parent 9639a0fe3f
commit 49cc935ceb
18 changed files with 515 additions and 88 deletions

View File

@ -364,6 +364,9 @@ return [
'voucher_start' => env('VOUCHER_START', null) ?: null,
],
// Enables Driving License
'driving_license_enabled' => (bool) env('DRIVING_LICENSE_ENABLED', true),
# Instruction in accordance with § 43 Para. 1 of the German Infection Protection Act (IfSG)
'ifsg_enabled' => (bool) env('IFSG_ENABLED', false),

View File

@ -57,6 +57,7 @@ $route->addGroup(
function (RouteCollector $route): void {
$route->get('/certificates', 'Admin\\UserSettingsController@certificate');
$route->post('/certificates/ifsg', 'Admin\\UserSettingsController@saveIfsgCertificate');
$route->post('/certificates/driving', 'Admin\\UserSettingsController@saveDrivingLicense');
}
);

View File

@ -21,6 +21,13 @@ class LicenseFactory extends Factory
$drive_12t = $drive_7_5t && $this->faker->boolean(.3);
$drive_forklift = ($drive_car && $this->faker->boolean(.1))
|| ($drive_12t && $this->faker->boolean(.7));
$drive_confirmed = $this->faker->boolean(0.5) && (
$drive_car
|| $drive_3_5t
|| $drive_7_5t
|| $drive_12t
|| $drive_forklift
);
$ifsg_certificate = $this->faker->boolean(0.1);
$ifsg_certificate_light = $this->faker->boolean(0.5) && !$ifsg_certificate;
@ -34,6 +41,7 @@ class LicenseFactory extends Factory
'drive_3_5t' => $drive_3_5t,
'drive_7_5t' => $drive_7_5t,
'drive_12t' => $drive_12t,
'drive_confirmed' => $drive_confirmed,
'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 AddDriveConfirmedToUsersLicenses extends Migration
{
/**
* Run the migration
*/
public function up(): void
{
$this->schema->table('users_licenses', function (Blueprint $table): void {
$table->boolean('drive_confirmed')->default(false)->after('drive_12t');
});
}
/**
* Reverse the migration
*/
public function down(): void
{
$this->schema->table('users_licenses', function (Blueprint $table): void {
$table->dropColumn('drive_confirmed');
});
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Migrations;
use Engelsystem\Database\Migration\Migration;
class AddUserDriveEditPermission extends Migration
{
/**
* Run the migration
*/
public function up(): void
{
$db = $this->schema->getConnection();
$db->table('privileges')
->insert([
'name' => 'user.drive.edit', 'description' => 'Edit Driving License',
]);
$editDrive = $db->table('privileges')
->where('name', 'user.drive.edit')
->get(['id'])
->first();
$shico = 60;
$team_coordinator = 65;
$db->table('group_privileges')
->insertOrIgnore([
['group_id' => $shico, 'privilege_id' => $editDrive->id],
['group_id' => $team_coordinator, 'privilege_id' => $editDrive->id],
]);
}
/**
* Reverse the migration
*/
public function down(): void
{
$db = $this->schema->getConnection();
$db->table('privileges')
->where('name', 'user.drive.edit')
->delete();
}
}

View File

@ -140,8 +140,12 @@ function angeltype_edit_controller()
engelsystem_log(
'Saved angeltype: ' . $angeltype->name . ($angeltype->restricted ? ', restricted' : '')
. ($angeltype->shift_self_signup ? ', shift_self_signup' : '')
. ($angeltype->requires_driver_license ? ', requires driver license' : '') . ', '
. ($angeltype->requires_ifsg_certificate ? ', requires ifsg certificate' : '') . ', '
. (config('driving_license_enabled')
? (($angeltype->requires_driver_license ? ', requires driver license' : '') . ', ')
: '')
. (config('ifsg_enabled')
? (($angeltype->requires_ifsg_certificate ? ', requires ifsg certificate' : '') . ', ')
: '')
. $angeltype->contact_name . ', '
. $angeltype->contact_dect . ', '
. $angeltype->contact_email . ', '

View File

@ -254,6 +254,12 @@ function user_controller()
->where('user_angel_type.supporter', true)
->count();
$is_drive_supporter = (bool) AngelType::whereRequiresDriverLicense(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(
@ -268,7 +274,10 @@ function user_controller()
auth()->can('admin_active'),
auth()->can('admin_user_worklog'),
$worklogs,
auth()->can('user.ifsg.edit') || $is_ifsg_supporter,
auth()->can('user.ifsg.edit')
|| $is_ifsg_supporter
|| auth()->can('user.drive.edit')
|| $is_drive_supporter,
),
];
}
@ -463,7 +472,7 @@ function user_driver_license_required_hint()
$user = auth()->user();
// User has already entered data, no hint needed.
if ($user->license->wantsToDrive()) {
if (!config('driving_license_enabled') || $user->license->wantsToDrive()) {
return null;
}

View File

@ -83,9 +83,39 @@ function AngelType_delete_view(AngelType $angeltype)
*/
function AngelType_edit_view(AngelType $angeltype, bool $supporter_mode)
{
$requires_ifsg = '';
$requires_driving_license = '';
if (config('ifsg_enabled')) {
$requires_ifsg = $supporter_mode ?
form_info(
__('angeltype.ifsg.required'),
$angeltype->requires_ifsg_certificate
? __('Yes')
: __('No')
) : form_checkbox(
'requires_ifsg_certificate',
__('angeltype.ifsg.required'),
$angeltype->requires_ifsg_certificate
);
}
if (config('driving_license_enabled')) {
$requires_driving_license = $supporter_mode ?
form_info(
__('Requires driver license'),
$angeltype->requires_driver_license
? __('Yes')
: __('No')
) : form_checkbox(
'requires_driver_license',
__('Requires driver license'),
$angeltype->requires_driver_license
);
}
$link = button($angeltype->id
? url('/angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id])
: url('/angeltypes'), icon('chevron-left'), 'btn-sm', '', __('general.back'));
return page_with_title(
$link . ' ' . (
$angeltype->id ?
@ -120,30 +150,8 @@ function AngelType_edit_view(AngelType $angeltype, bool $supporter_mode)
__('angeltypes.shift.self_signup.info') . '"></span>',
$angeltype->shift_self_signup
),
$supporter_mode ?
form_info(
__('Requires driver license'),
$angeltype->requires_driver_license
? __('Yes')
: __('No')
) :
form_checkbox(
'requires_driver_license',
__('Requires driver license'),
$angeltype->requires_driver_license
),
$supporter_mode && config('ifsg_enabled') ?
form_info(
__('angeltype.ifsg.required'),
$angeltype->requires_ifsg_certificate
? __('Yes')
: __('No')
) :
form_checkbox(
'requires_ifsg_certificate',
__('angeltype.ifsg.required'),
$angeltype->requires_ifsg_certificate
),
$requires_driving_license,
$requires_ifsg,
$supporter_mode
? form_info(__('Show on dashboard'), $angeltype->show_on_dashboard ? __('Yes') : __('No'))
: form_checkbox('show_on_dashboard', __('Show on dashboard'), $angeltype->show_on_dashboard),
@ -182,7 +190,7 @@ function AngelType_edit_view(AngelType $angeltype, bool $supporter_mode)
* @param UserAngelType|null $user_angeltype
* @param bool $admin_angeltypes
* @param bool $supporter
* @param License $user_driver_license
* @param License $user_license
* @param User|null $user
* @return string
*/
@ -191,10 +199,10 @@ function AngelType_view_buttons(
?UserAngelType $user_angeltype,
$admin_angeltypes,
$supporter,
$user_driver_license,
$user_license,
$user
) {
if ($angeltype->requires_driver_license) {
if (config('driving_license_enabled') && $angeltype->requires_driver_license) {
$buttons[] = button(
url('/settings/certificates'),
icon('person-vcard') . __('My driving license')
@ -216,7 +224,7 @@ function AngelType_view_buttons(
($admin_angeltypes ? 'Join' : ''),
);
} else {
if ($angeltype->requires_driver_license && !$user_driver_license->wantsToDrive()) {
if (config('driving_license_enabled') && $angeltype->requires_driver_license && !$user_license->wantsToDrive()) {
error(__('This angeltype requires a driver license. Please enter your driver license information!'));
}
@ -265,6 +273,13 @@ function AngelType_view_buttons(
return buttons($buttons);
}
function certificateIcon($confirmed, $certificate)
{
return ($confirmed && $certificate)
? icon('check2-all', 'text-success')
: icon_bool($certificate);
}
/**
* Renders and sorts the members of an angeltype into supporters, members and unconfirmed members.
*
@ -284,32 +299,36 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
if (config('enable_dect')) {
$member['dect'] = htmlspecialchars((string) $member->contact->dect);
}
if ($angeltype->requires_driver_license) {
$member['wants_to_drive'] = icon_bool($member->license->wantsToDrive());
if (config('driving_license_enabled') && $angeltype->requires_driver_license) {
$drive_confirmed = $member->license->drive_confirmed;
$member['wants_to_drive'] = certificateIcon($drive_confirmed, $member->license->wantsToDrive());
$member['has_car'] = icon_bool($member->license->has_car);
$member['has_license_car'] = icon_bool($member->license->drive_car);
$member['has_license_3_5t_transporter'] = icon_bool($member->license->drive_3_5t);
$member['has_license_7_5t_truck'] = icon_bool($member->license->drive_7_5t);
$member['has_license_12t_truck'] = icon_bool($member->license->drive_12t);
$member['has_license_forklift'] = icon_bool($member->license->drive_forklift);
$member['has_license_car'] = certificateIcon($drive_confirmed, $member->license->drive_car);
$member['has_license_3_5t_transporter'] = certificateIcon($drive_confirmed, $member->license->drive_3_5t);
$member['has_license_7_5t_truck'] = certificateIcon($drive_confirmed, $member->license->drive_7_5t);
$member['has_license_12t_truck'] = certificateIcon($drive_confirmed, $member->license->drive_12t);
$member['has_license_forklift'] = certificateIcon($drive_confirmed, $member->license->drive_forklift);
}
if ($angeltype->requires_ifsg_certificate && config('ifsg_enabled')) {
$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_enabled') && $angeltype->requires_ifsg_certificate) {
$ifsg_confirmed = $member->license->ifsg_confirmed;
$member['ifsg_certificate'] = certificateIcon($ifsg_confirmed, $member->license->ifsg_certificate);
if (config('ifsg_light_enabled')) {
$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);
$member['ifsg_certificate_light'] = certificateIcon($ifsg_confirmed, $member->license->ifsg_certificate_light);
}
}
$edit_certificates = '';
if (
($angeltype->requires_driver_license || $angeltype->requires_ifsg_certificate)
(
config('driving_license_enabled')
&& $angeltype->requires_driver_license
&& ($admin_user_angeltypes || auth()->can('user.drive.edit'))
)
|| (
config('ifsg_enabled')
&& $angeltype->requires_ifsg_certificate
&& ($admin_user_angeltypes || auth()->can('user.ifsg.edit'))
)
) {
$edit_certificates =
button(
@ -425,7 +444,10 @@ function AngelType_view_table_headers(AngelType $angeltype, $supporter, $admin_a
$headers['dect'] = __('general.dect');
}
if ($angeltype->requires_driver_license && ($supporter || $admin_angeltypes)) {
if (
config('driving_license_enabled') && $angeltype->requires_driver_license
&& ($supporter || $admin_angeltypes || auth()->can('user.drive.edit'))
) {
$headers = array_merge($headers, [
'wants_to_drive' => __('Driver'),
'has_car' => __('Has car'),
@ -461,7 +483,7 @@ function AngelType_view_table_headers(AngelType $angeltype, $supporter, $admin_a
* @param bool $admin_user_angeltypes
* @param bool $admin_angeltypes
* @param bool $supporter
* @param License $user_driver_license
* @param License $user_license
* @param User $user
* @param ShiftsFilterRenderer $shiftsFilterRenderer
* @param ShiftCalendarRenderer $shiftCalendarRenderer
@ -475,7 +497,7 @@ function AngelType_view(
$admin_user_angeltypes,
$admin_angeltypes,
$supporter,
$user_driver_license,
$user_license,
$user,
ShiftsFilterRenderer $shiftsFilterRenderer,
ShiftCalendarRenderer $shiftCalendarRenderer,
@ -485,7 +507,7 @@ function AngelType_view(
return page_with_title(
$link . ' ' . sprintf(__('Team %s'), htmlspecialchars($angeltype->name)),
[
AngelType_view_buttons($angeltype, $user_angeltype, $admin_angeltypes, $supporter, $user_driver_license, $user),
AngelType_view_buttons($angeltype, $user_angeltype, $admin_angeltypes, $supporter, $user_license, $user),
msg(),
tabs([
__('Info') => AngelType_view_info(

View File

@ -553,7 +553,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
* @param bool $admin_certificates
*
* @return string
*/
@ -569,7 +569,7 @@ function User_view(
$tshirt_admin,
$admin_user_worklog_privilege,
$user_worklogs,
$admin_ifsg
$admin_certificates
) {
$goodie = GoodieType::from(config('goodie_type'));
$goodie_enabled = $goodie !== GoodieType::None;
@ -653,7 +653,10 @@ function User_view(
icon('valentine') . __('Vouchers')
)
: '',
$admin_ifsg ? button(
(
$admin_certificates
&& (config('ifsg_enabled') || config('driving_license_enabled'))
) ? button(
url('/users/' . $user_source->id . '/certificates'),
icon('card-checklist') . __('settings.certificates')
) : '',

View File

@ -1552,7 +1552,7 @@ msgid "news.comments.delete.title"
msgstr "Kommentar \"%s\" löschen"
msgid "notification.news.updated.introduction"
msgstr "Die News %1$s wurde aktualisiert"
msgstr "Die News \"%1$s\" wurde aktualisiert"
msgid "notification.news.updated.text"
msgstr "Du kannst sie dir unter %3$s anschauen."
@ -1754,6 +1754,9 @@ 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.drive_confirmed.hint"
msgstr "Dein Führerschein 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."

View File

@ -254,7 +254,7 @@ msgid "news.comments.delete.title"
msgstr "Delete comment \"%s\""
msgid "notification.news.updated.introduction"
msgstr "The news %1$s was updated"
msgstr "The news \"%1$s\" was updated"
msgid "notification.news.updated.text"
msgstr "You can view it at %3$s"
@ -456,6 +456,9 @@ 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.drive_confirmed.hint"
msgstr "Your driving license 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."

View File

@ -38,6 +38,47 @@
</div>
</form>
{% endif %}
{% if config('driving_license_enabled') %}
<form
action="{{ url('/users/' ~ admin_user.id ~ '/certificates/driving') }}"
enctype="multipart/form-data" method="post"
>
{{ csrf() }}
<div class="col-md-12">
<h3>{{ __('settings.certificates.driving_license') }}</h3>
{{ f.checkbox('drive_car', __('settings.certificates.drive_car'), {
'checked': certificates.drive_car,
}) }}
{{ f.checkbox('drive_3_5t', __('settings.certificates.drive_3_5t'), {
'checked': certificates.drive_3_5t,
}) }}
{{ f.checkbox('drive_7_5t', __('settings.certificates.drive_7_5t'), {
'checked': certificates.drive_7_5t,
}) }}
{{ f.checkbox('drive_12t', __('settings.certificates.drive_12t'), {
'checked': certificates.drive_12t,
}) }}
{{ f.checkbox('drive_forklift', __('settings.certificates.drive_forklift'), {
'checked': certificates.drive_forklift,
}) }}
<div class="row">
<div class="col-auto">
{{ f.submit(__('form.save'), {'icon_left': 'save'}) }}
</div>
<div class="col-auto">
{{ f.checkbox(
'drive_confirmed',
__('settings.certificates.confirmed') ~ f.info(__('settings.certificates.confirmation.info')),
{'raw_label': true, 'checked': certificates.drive_confirmed}
) }}
</div>
</div>
</div>
</form>
{% endif %}
</div>
{% endblock %}

View File

@ -6,7 +6,7 @@
{% block row_content %}
<div class="row">
{% if config('ifsg_enabled') %}
{% if config('ifsg_enabled') and ifsg %}
<form
action="{{ url('/settings/certificates/ifsg') }}"
enctype="multipart/form-data" method="post"
@ -38,27 +38,42 @@
</form>
{% endif %}
{% if driving_license %}
<form action="{{ url('/settings/certificates/driving') }}" enctype="multipart/form-data" method="post">
{% if config('driving_license_enabled') and driving_license %}
<form
action="{{ url('/settings/certificates/driving') }}"
enctype="multipart/form-data" method="post"
>
{{ csrf() }}
<div class="col-md-12">
<h3>{{ __('settings.certificates.driving_license') }}</h3>
{{ m.info(__('settings.certificates.info')) }}
{% if certificates.drive_confirmed %}
<p class="text-success">{{ __('settings.certificates.drive_confirmed.hint') }}</p>
{% endif %}
{{ f.checkbox('drive_car', __('settings.certificates.drive_car'), {
'checked': certificates.drive_car,
'disabled': certificates.drive_confirmed,
}) }}
{{ f.checkbox('drive_3_5t', __('settings.certificates.drive_3_5t'), {
'checked': certificates.drive_3_5t,
'disabled': certificates.drive_confirmed,
}) }}
{{ f.checkbox('drive_7_5t', __('settings.certificates.drive_7_5t'), {
'checked': certificates.drive_7_5t,
'disabled': certificates.drive_confirmed,
}) }}
{{ f.checkbox('drive_12t', __('settings.certificates.drive_12t'), {
'checked': certificates.drive_12t,
'disabled': certificates.drive_confirmed,
}) }}
{{ f.checkbox('drive_forklift', __('settings.certificates.drive_forklift'), {
'checked': certificates.drive_forklift,
'disabled': certificates.drive_confirmed,
}) }}
{{ f.checkbox('has_car', __('settings.certificates.has_car'), {

View File

@ -32,11 +32,21 @@ class UserSettingsController extends BaseController
public function certificate(Request $request): Response
{
if (!config('ifsg_enabled')) {
if (!config('ifsg_enabled') && !config('driving_license_enabled')) {
throw new HttpNotFound();
}
$this->checkPermission('user.ifsg.edit', $this->isIfsgSupporter());
if (
!(
$this->auth->can('user.ifsg.edit')
|| $this->auth->can('user.drive.edit')
|| $this->isDriverLicenseSupporter()
|| $this->isIfsgSupporter()
)
) {
throw new HttpForbidden();
}
$user = $this->getUser($request);
return $this->view(
@ -87,6 +97,54 @@ class UserSettingsController extends BaseController
return $this->redirect->to('/users/' . $user->id . '/certificates');
}
public function saveDrivingLicense(Request $request): Response
{
if (!config('driving_license_enabled')) {
throw new HttpNotFound();
}
$this->checkPermission('user.drive.edit', $this->isDriverLicenseSupporter());
$user = $this->getUser($request);
$data = $this->validate($request, [
'drive_car' => 'optional|checked',
'drive_3_5t' => 'optional|checked',
'drive_7_5t' => 'optional|checked',
'drive_12t' => 'optional|checked',
'drive_forklift' => 'optional|checked',
'drive_confirmed' => 'optional|checked',
]);
$user->license->drive_car = (bool) $data['drive_car'];
$user->license->drive_3_5t = (bool) $data['drive_3_5t'];
$user->license->drive_7_5t = (bool) $data['drive_7_5t'];
$user->license->drive_12t = (bool) $data['drive_12t'];
$user->license->drive_forklift = (bool) $data['drive_forklift'];
$user->license->drive_confirmed = $data['drive_confirmed'] && (
$user->license->drive_car
|| $user->license->drive_3_5t
|| $user->license->drive_7_5t
|| $user->license->drive_12t
|| $user->license->drive_forklift
);
$user->license->save();
$this->addNotification('settings.certificates.success');
$this->log->info('Certificate "{certificate}" of user {user} ({id}) is {confirmation}.', [
'certificate' => ($user->license->drive_car ? 'car' : '')
. ($user->license->drive_3_5t ? ', 3.5t' : '')
. ($user->license->drive_7_5t ? ', 7.5t' : '')
. ($user->license->drive_12t ? ', 12t' : '')
. ($user->license->drive_forklift ? ', forklift' : ''),
'user' => $user->name,
'id' => $user->id,
'confirmation' => $user->license->drive_confirmed ? 'confirmed' : 'unconfirmed',
]);
return $this->redirect->to('/users/' . $user->id . '/certificates');
}
public function settingsMenu(User $user): array
{
$menu = [
@ -95,11 +153,16 @@ class UserSettingsController extends BaseController
],
];
if (config('ifsg_enabled')) {
if (config('ifsg_enabled') || config('driving_license_enabled')) {
$menu[url('/users/' . $user->id . '/certificates')] = [
'title' => 'settings.certificates',
'icon' => 'card-checklist',
'permission' => $this->isIfsgSupporter() ? null : 'user.ifsg.edit',
'permission' => (
$this->auth->can('user.ifsg.edit')
|| $this->isIfsgSupporter()
|| $this->auth->can('user.drive.edit')
|| $this->isDriverLicenseSupporter()
) ? null : '_',
];
}
@ -139,4 +202,13 @@ class UserSettingsController extends BaseController
->where('user_angel_type.supporter', true)
->count();
}
public function isDriverLicenseSupporter(): bool
{
return (bool) AngelType::whereRequiresDriverLicense(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,7 +242,10 @@ class SettingsController extends BaseController
public function certificate(): Response
{
if (!config('ifsg_enabled') && !$this->checkDrivingLicense()) {
if (
!(config('ifsg_enabled') && $this->checkIfsgCertificate())
&& !(config('driving_license_enabled') && $this->checkDrivingLicense())
) {
throw new HttpNotFound();
}
@ -252,6 +255,7 @@ class SettingsController extends BaseController
[
'settings_menu' => $this->settingsMenu(),
'driving_license' => $this->checkDrivingLicense(),
'ifsg' => $this->checkIfsgCertificate(),
'certificates' => $user->license,
]
);
@ -260,7 +264,7 @@ class SettingsController extends BaseController
public function saveIfsgCertificate(Request $request): Response
{
$user = $this->auth->user();
if (!config('ifsg_enabled') || $user->license->ifsg_confirmed) {
if (!config('ifsg_enabled') || $user->license->ifsg_confirmed || !$this->checkIfsgCertificate()) {
throw new HttpNotFound();
}
@ -282,7 +286,7 @@ class SettingsController extends BaseController
public function saveDrivingLicense(Request $request): Response
{
if (!$this->checkDrivingLicense()) {
if (!config('driving_license_enabled') || !$this->checkDrivingLicense()) {
throw new HttpNotFound();
}
@ -297,11 +301,13 @@ class SettingsController extends BaseController
]);
$user->license->has_car = (bool) $data['has_car'];
if (!$user->license->drive_confirmed) {
$user->license->drive_car = (bool) $data['drive_car'];
$user->license->drive_3_5t = (bool) $data['drive_3_5t'];
$user->license->drive_7_5t = (bool) $data['drive_7_5t'];
$user->license->drive_12t = (bool) $data['drive_12t'];
$user->license->drive_forklift = (bool) $data['drive_forklift'];
}
$user->license->save();
$this->addNotification('settings.certificates.success');
@ -394,7 +400,10 @@ class SettingsController extends BaseController
$menu[url('/settings/theme')] = 'settings.theme';
}
if (config('ifsg_enabled') || $this->checkDrivingLicense()) {
if (
(config('ifsg_enabled') && $this->checkIfsgCertificate())
|| (config('driving_license_enabled') && $this->checkDrivingLicense())
) {
$menu[url('/settings/certificates')] = ['title' => 'settings.certificates', 'icon' => 'card-checklist'];
}
@ -429,6 +438,13 @@ class SettingsController extends BaseController
})->isNotEmpty();
}
protected function checkIfsgCertificate(): bool
{
return $this->auth->user()->userAngelTypes->filter(function (AngelType $angelType) {
return $angelType->requires_ifsg_certificate;
})->isNotEmpty();
}
private function isRequired(string $key): string
{
$requiredFields = $this->config->get('required_user_fields');

View File

@ -14,6 +14,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
* @property bool $drive_3_5t
* @property bool $drive_7_5t
* @property bool $drive_12t
* @property bool $drive_confirmed
* @property bool $ifsg_certificate_light
* @property bool $ifsg_certificate
* @property bool $ifsg_confirmed
@ -24,6 +25,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
* @method static QueryBuilder|License[] whereDrive35T($value)
* @method static QueryBuilder|License[] whereDrive75T($value)
* @method static QueryBuilder|License[] whereDrive12T($value)
* @method static QueryBuilder|License[] whereDriveConfirmed($value)
* @method static QueryBuilder|License[] whereIfsgCertificateLight($value)
* @method static QueryBuilder|License[] whereIfsgCertificate($value)
* @method static QueryBuilder|License[] whereIfsgConfirmed($value)
@ -43,6 +45,7 @@ class License extends HasUserModel
'drive_3_5t' => false,
'drive_7_5t' => false,
'drive_12t' => false,
'drive_confirmed' => false,
'ifsg_certificate_light' => false,
'ifsg_certificate' => false,
'ifsg_confirmed' => false,
@ -61,6 +64,7 @@ class License extends HasUserModel
'drive_3_5t',
'drive_7_5t',
'drive_12t',
'drive_confirmed',
'ifsg_certificate_light',
'ifsg_certificate',
'ifsg_confirmed',
@ -74,6 +78,7 @@ class License extends HasUserModel
'drive_3_5t' => 'boolean',
'drive_7_5t' => 'boolean',
'drive_12t' => 'boolean',
'drive_confirmed' => 'boolean',
'ifsg_certificate_light' => 'boolean',
'ifsg_certificate' => 'boolean',
'ifsg_confirmed' => 'boolean',

View File

@ -42,11 +42,13 @@ class UserSettingsControllerTest extends ControllerTest
}
/**
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::checkPermission
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::certificate
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::isIfsgSupporter
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::isDriverLicenseSupporter
*/
public function testCertificateNotAllowed(): void
{
config(['ifsg_enabled' => true]);
config(['ifsg_enabled' => true, 'driving_license_enabled' => true]);
$this->expectException(HttpForbidden::class);
$this->controller->certificate($this->request);
@ -95,6 +97,22 @@ class UserSettingsControllerTest extends ControllerTest
$this->controller->certificate($this->request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::certificate
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::checkPermission
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::isDriverLicenseSupporter
*/
public function testDriverLicenseByAngelTypeSupporter(): void
{
config(['driving_license_enabled' => true]);
$this->setExpects($this->response, 'withView', null, $this->response);
$angelType = AngelType::factory()->create(['requires_driver_license' => true]);
$this->user->userAngelTypes()->attach($angelType, ['supporter' => true]);
$this->controller->certificate($this->request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::saveIfsgCertificate
*/
@ -108,6 +126,7 @@ class UserSettingsControllerTest extends ControllerTest
/**
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::saveIfsgCertificate
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::checkPermission
*/
public function testSaveIfsgCertificateNotAllowed(): void
{
@ -194,6 +213,91 @@ class UserSettingsControllerTest extends ControllerTest
$this->assertFalse($this->userChanged->license->ifsg_confirmed);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::saveDrivingLicense
*/
public function testSaveDrivingLicenseDisabled(): void
{
config(['driving_license_enabled' => false]);
$this->expectException(HttpNotFound::class);
$this->controller->saveDrivingLicense($this->request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::saveDrivingLicense
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::checkPermission
*/
public function testSaveDrivingLicenseNotAllowed(): void
{
config(['driving_license_enabled' => true]);
$this->expectException(HttpForbidden::class);
$this->controller->saveDrivingLicense($this->request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::saveDrivingLicense
*/
public function testSaveDrivingLicenseConfirmed(): void
{
config(['driving_license_enabled' => true]);
$this->setExpects($this->auth, 'can', ['user.drive.edit'], true, $this->atLeastOnce());
$body = [
'drive_car' => true,
'drive_3_5t' => true,
'drive_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->saveDrivingLicense($this->request);
$this->assertTrue($this->log->hasInfoThatContains('Certificate'));
$this->assertFalse($this->userChanged->license->drive_forklift);
$this->assertFalse($this->userChanged->license->drive_12t);
$this->assertFalse($this->userChanged->license->drive_7_5t);
$this->assertFalse($this->userChanged->license->has_car);
$this->assertTrue($this->userChanged->license->drive_car);
$this->assertTrue($this->userChanged->license->drive_3_5t);
$this->assertTrue($this->userChanged->license->drive_confirmed);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::saveDrivingLicense
*/
public function testSaveDrivingLicense(): void
{
config(['driving_license_enabled' => true]);
$this->setExpects($this->auth, 'can', ['user.drive.edit'], true, $this->atLeastOnce());
$body = [
'drive_forklift' => true,
'drive_12t' => 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->saveDrivingLicense($this->request);
$this->assertFalse($this->userChanged->license->drive_3_5t);
$this->assertFalse($this->userChanged->license->drive_7_5t);
$this->assertFalse($this->userChanged->license->drive_car);
$this->assertFalse($this->userChanged->license->has_car);
$this->assertTrue($this->userChanged->license->drive_forklift);
$this->assertTrue($this->userChanged->license->drive_12t);
$this->assertFalse($this->userChanged->license->drive_confirmed);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserSettingsController::settingsMenu
*/

View File

@ -689,6 +689,9 @@ class SettingsControllerTest extends ControllerTest
config(['ifsg_enabled' => true, 'ifsg_light_enabled' => true]);
$this->setExpects($this->auth, 'user', null, $this->user, $this->atLeastOnce());
$angelType = AngelType::factory()->create(['requires_ifsg_certificate' => true]);
$this->user->userAngelTypes()->attach($angelType);
$this->response->expects($this->once())
->method('withView')
->willReturnCallback(function ($view, $data) {
@ -707,7 +710,6 @@ class SettingsControllerTest extends ControllerTest
public function testCertificateIfsgNotConfigured(): void
{
config(['ifsg_enabled' => false]);
$this->setExpects($this->auth, 'user', null, $this->user, $this->atLeastOnce());
$this->expectException(HttpNotFound::class);
$this->controller->certificate();
@ -718,6 +720,7 @@ class SettingsControllerTest extends ControllerTest
*/
public function testCertificateDrivingLicense(): void
{
config(['driving_license_enabled' => true]);
$this->setExpects($this->auth, 'user', null, $this->user, $this->atLeastOnce());
$angelType = AngelType::factory()->create(['requires_driver_license' => true]);
@ -752,7 +755,10 @@ class SettingsControllerTest extends ControllerTest
public function testSaveIfsgCertificateLight(): void
{
config(['ifsg_enabled' => true, 'ifsg_light_enabled' => true]);
$this->setExpects($this->auth, 'user', null, $this->user, $this->once());
$this->setExpects($this->auth, 'user', null, $this->user, $this->atLeastOnce());
$angelType = AngelType::factory()->create(['requires_ifsg_certificate' => true]);
$this->user->userAngelTypes()->attach($angelType);
$body = [
'ifsg_certificate_light' => true,
@ -776,7 +782,11 @@ class SettingsControllerTest extends ControllerTest
public function testSaveIfsgCertificateLightWhileDisabled(): void
{
config(['ifsg_enabled' => true, 'ifsg_light_enabled' => false]);
$this->setExpects($this->auth, 'user', null, $this->user, $this->once());
$this->setExpects($this->auth, 'user', null, $this->user, $this->atLeastOnce());
$angelType = AngelType::factory()->create(['requires_ifsg_certificate' => true]);
$this->user->userAngelTypes()->attach($angelType);
$this->user->license->ifsg_certificate_light = false;
$this->user->license->save();
@ -798,11 +808,15 @@ class SettingsControllerTest extends ControllerTest
/**
* @covers \Engelsystem\Controllers\SettingsController::saveIfsgCertificate
* @covers \Engelsystem\Controllers\SettingsController::checkIfsgCertificate
*/
public function testSaveIfsgCertificate(): void
{
config(['ifsg_enabled' => true]);
$this->setExpects($this->auth, 'user', null, $this->user, $this->once());
$this->setExpects($this->auth, 'user', null, $this->user, $this->atLeastOnce());
$angelType = AngelType::factory()->create(['requires_ifsg_certificate' => true]);
$this->user->userAngelTypes()->attach($angelType);
$body = [
'ifsg_certificate' => true,
@ -826,7 +840,10 @@ class SettingsControllerTest extends ControllerTest
public function testSaveIfsgCertificateBoth(): void
{
config(['ifsg_enabled' => true]);
$this->setExpects($this->auth, 'user', null, $this->user, $this->once());
$this->setExpects($this->auth, 'user', null, $this->user, $this->atLeastOnce());
$angelType = AngelType::factory()->create(['requires_ifsg_certificate' => true]);
$this->user->userAngelTypes()->attach($angelType);
$body = [
'ifsg_certificate_light' => true,
@ -851,6 +868,7 @@ class SettingsControllerTest extends ControllerTest
*/
public function testSaveDrivingLicense(): void
{
config(['driving_license_enabled' => true]);
$this->setExpects($this->auth, 'user', null, $this->user, $this->atLeastOnce());
$angelType = AngelType::factory()->create(['requires_driver_license' => true]);
@ -893,6 +911,7 @@ class SettingsControllerTest extends ControllerTest
*/
public function testApi(): void
{
config(['ifsg_enabled' => true]);
$this->setExpects($this->auth, 'user', null, $this->user, $this->atLeastOnce());
/** @var Response|MockObject $response */
@ -993,11 +1012,33 @@ class SettingsControllerTest extends ControllerTest
/**
* @covers \Engelsystem\Controllers\SettingsController::settingsMenu
* @covers \Engelsystem\Controllers\SettingsController::checkOauthHidden
*/
public function testSettingsMenuWithIfsg(): void
{
config(['ifsg_enabled' => true]);
$this->setExpects($this->auth, 'user', null, $this->user, $this->atLeastOnce());
$angelType = AngelType::factory()->create(['requires_ifsg_certificate' => true]);
$this->user->userAngelTypes()->attach($angelType);
$menu = $this->controller->settingsMenu();
$this->assertArrayHasKey('http://localhost/settings/certificates', $menu);
$this->assertEquals(
['title' => 'settings.certificates', 'icon' => 'card-checklist'],
$menu['http://localhost/settings/certificates']
);
}
/**
* @covers \Engelsystem\Controllers\SettingsController::settingsMenu
*/
public function testSettingsMenuWithDrivingLicense(): void
{
config(['driving_license_enabled' => true]);
$this->setExpects($this->auth, 'user', null, $this->user, $this->atLeastOnce());
$angelType = AngelType::factory()->create(['requires_driver_license' => true]);
$this->user->userAngelTypes()->attach($angelType);
$menu = $this->controller->settingsMenu();
$this->assertArrayHasKey('http://localhost/settings/certificates', $menu);