Worklog Refactoring

This commit is contained in:
frischler 2022-12-08 17:40:24 +01:00 committed by GitHub
parent 9396a49412
commit bdc62eaac3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 800 additions and 464 deletions

View File

@ -112,10 +112,24 @@ $route->addGroup(
// User
$route->addGroup(
'/user/{id:\d+}',
// Shirts
function (RouteCollector $route) {
// Shirts
$route->get('/shirt', 'Admin\\UserShirtController@editShirt');
$route->post('/shirt', 'Admin\\UserShirtController@saveShirt');
// Worklogs
$route->get('/worklog', 'Admin\\UserWorkLogController@editWorklog');
$route->post('/worklog', 'Admin\\UserWorkLogController@saveWorklog');
$route->get('/worklog/{worklog_id:\d+}', 'Admin\\UserWorkLogController@editWorklog');
$route->post('/worklog/{worklog_id:\d+}', 'Admin\\UserWorkLogController@saveWorklog');
$route->get(
'/worklog/{worklog_id:\d+}/delete',
'Admin\\UserWorkLogController@showDeleteWorklog'
);
$route->post(
'/worklog/{worklog_id:\d+}/delete',
'Admin\\UserWorkLogController@deleteWorklog'
);
}
);

View File

@ -1,217 +0,0 @@
<?php
use Engelsystem\Models\User\User;
use Engelsystem\Models\Worklog;
/**
* Delete a work log entry.
*
* @return array
*/
function user_worklog_delete_controller()
{
$request = request();
$worklog = Worklog::find($request->input('user_worklog_id'));
if (empty($worklog)) {
throw_redirect(user_link(auth()->user()->id));
}
$user = $worklog->user;
if ($request->hasPostData('submit')) {
UserWorkLog_delete($worklog);
success(__('Work log entry deleted.'));
throw_redirect(user_link($user->id));
}
return [
UserWorkLog_delete_title(),
UserWorkLog_delete_view($user)
];
}
/**
* Edit work log for user.
*
* @return array
*/
function user_worklog_edit_controller()
{
$request = request();
$worklog = Worklog::find($request->input('user_worklog_id'));
if (empty($worklog)) {
throw_redirect(user_link(auth()->user()->id));
}
$user = $worklog->user;
if ($request->hasPostData('submit')) {
list ($valid, $worklog) = user_worklog_from_request($worklog);
if ($valid) {
$worklog->save();
engelsystem_log(sprintf(
'Updated work log for %s, %s hours, %s',
User_Nick_render($worklog->user, true),
$worklog->hours,
$worklog->comment
));
success(__('Work log entry updated.'));
throw_redirect(user_link($user->id));
}
}
return [
UserWorkLog_edit_title(),
UserWorkLog_edit_view($user, $worklog)
];
}
/**
* Handle form
*
* @param Worklog $worklog
* @return bool[]|Worklog[] [bool $valid, Worklog $worklog]
*/
function user_worklog_from_request(Worklog $worklog)
{
$request = request();
$valid = true;
$worklog->worked_at = DateTime::createFromFormat('Y-m-d H:i', $request->input('work_timestamp') . ' 00:00');
if (!$worklog->worked_at) {
$valid = false;
error(__('Please enter work date.'));
}
$worklog->hours = $request->input('work_hours');
if (!preg_match("/^\d+(\.\d{0,2})?$/", $request->input('work_hours'))) {
$valid = false;
error(__('Please enter work hours in format ##[.##]'));
}
$worklog->comment = $request->input('comment');
if (empty($worklog->comment)) {
$valid = false;
error(__('Please enter a comment.'));
}
if (mb_strlen($worklog->comment) > 200) {
$valid = false;
error(__('Comment too long.'));
}
return [
$valid,
$worklog
];
}
/**
* Add work log entry to user.
*
* @return array
*/
function user_worklog_add_controller()
{
$request = request();
$user = User::find($request->input('user_id'));
if (!$user) {
throw_redirect(user_link(auth()->user()->id));
}
$worklog = UserWorkLog_new($user->id);
if ($request->hasPostData('submit')) {
list ($valid, $worklog) = user_worklog_from_request($worklog);
if ($valid) {
UserWorkLog_create($worklog);
success(__('Work log entry created.'));
throw_redirect(user_link($user->id));
}
}
return [
UserWorkLog_add_title(),
UserWorkLog_add_view($user, $worklog)
];
}
/**
* Link to work log entry add for given user.
*
* @param User $user
*
* @return string
*/
function user_worklog_add_link(User $user)
{
return page_link_to('user_worklog', [
'action' => 'add',
'user_id' => $user->id,
]);
}
/**
* Link to work log entry edit.
*
* @param Worklog $worklog
* @return string
*/
function user_worklog_edit_link(Worklog $worklog)
{
return page_link_to('user_worklog', [
'action' => 'edit',
'user_worklog_id' => $worklog->id
]);
}
/**
* Link to work log entry delete.
*
* @param Worklog $worklog
* @param array[] $parameters
* @return string
*/
function user_worklog_delete_link(Worklog $worklog, $parameters = [])
{
return page_link_to('user_worklog', array_merge([
'action' => 'delete',
'user_worklog_id' => $worklog->id
], $parameters));
}
/**
* Work log entry actions
*
* @return array
*/
function user_worklog_controller()
{
$user = auth()->user();
if (!auth()->can('admin_user_worklog')) {
throw_redirect(user_link($user->id));
}
$request = request();
$action = $request->input('action');
if (!$request->has('action')) {
throw_redirect(user_link($user->id));
}
switch ($action) {
case 'add':
return user_worklog_add_controller();
case 'edit':
return user_worklog_edit_controller();
case 'delete':
return user_worklog_delete_controller();
}
return ['', ''];
}

View File

@ -2,16 +2,38 @@
/**
* Returns messages from session and removes them from the stack
*
* @param bool $includeMessagesFromNewProcedure
* If set, the messages from the new procedure are also included.
* The output will be similar to how it would be with messages.twig.
* @see \Engelsystem\Controllers\HasUserNotifications
* @return string
*/
function msg()
function msg(bool $includeMessagesFromNewProcedure = false)
{
$session = session();
$message = $session->get('msg', '');
$session->set('msg', '');
if ($includeMessagesFromNewProcedure) {
foreach (session()->get('errors', []) as $msg) {
$message .= error(__($msg), true);
}
foreach (session()->get('warnings', []) as $msg) {
$message .= warning(__($msg), true);
}
foreach (session()->get('information', []) as $msg) {
$message .= info(__($msg), true);
}
foreach (session()->get('messages', []) as $msg) {
$message .= success(__($msg), true);
}
foreach (['errors', 'warnings', 'information', 'messages'] as $type) {
session()->remove($type);
}
}
return $message;
}

View File

@ -39,7 +39,6 @@ $includeFiles = [
__DIR__ . '/../includes/view/UserDriverLicenses_view.php',
__DIR__ . '/../includes/view/UserHintsRenderer.php',
__DIR__ . '/../includes/view/User_view.php',
__DIR__ . '/../includes/view/UserWorkLog_view.php',
__DIR__ . '/../includes/controller/angeltypes_controller.php',
__DIR__ . '/../includes/controller/event_config_controller.php',
@ -51,7 +50,6 @@ $includeFiles = [
__DIR__ . '/../includes/controller/users_controller.php',
__DIR__ . '/../includes/controller/user_angeltypes_controller.php',
__DIR__ . '/../includes/controller/user_driver_licenses_controller.php',
__DIR__ . '/../includes/controller/user_worklog_controller.php',
__DIR__ . '/../includes/helper/legacy_helper.php',
__DIR__ . '/../includes/helper/message_helper.php',

View File

@ -21,75 +21,3 @@ function UserWorkLogsForUser($userId, Carbon $sinceTime = null)
return $worklogs->get();
}
/**
* Delete a work log entry.
*
* @param Worklog $worklog
* @return int
*/
function UserWorkLog_delete(Worklog $worklog)
{
$result = $worklog->delete();
engelsystem_log(sprintf(
'Delete work log for %s, %s hours, %s',
User_Nick_render($worklog->user, true),
$worklog->hours,
$worklog->comment
));
return $result;
}
/**
* Create a new work log entry
*
* @param Worklog $worklog
* @return bool
*/
function UserWorkLog_create(Worklog $worklog)
{
$user = auth()->user();
$worklog->creator()->associate($user);
$result = $worklog->save();
engelsystem_log(sprintf(
'Added work log entry for %s, %s hours, %s',
User_Nick_render($worklog->user, true),
$worklog->hours,
$worklog->comment
));
return $result;
}
/**
* New user work log entry
*
* @param int $userId
* @return Worklog
*/
function UserWorkLog_new($userId)
{
/** @var Carbon $buildup */
$buildup = config('buildup_start');
/** @var Carbon $event */
$event = config('event_start');
$work_date = Carbon::today();
if (!empty($buildup) && (empty($event) || $event->lessThan(Carbon::now()))) {
$work_date = $buildup;
}
$work_date
->setHour(0)
->setMinute(0)
->setSecond(0);
$worklog = new Worklog();
$worklog->user_id = $userId;
$worklog->worked_at = $work_date;
return $worklog;
}

View File

@ -1,104 +0,0 @@
<?php
use Engelsystem\Models\User\User;
use Engelsystem\Models\Worklog;
/**
* Delete work log entry.
*
* @param User $user
* @return string
*/
function UserWorkLog_delete_view(User $user)
{
return page_with_title(UserWorkLog_delete_title(), [
info(sprintf(
__('Do you want to delete the worklog entry for %s?'),
User_Nick_render($user)
), true),
form([
buttons([
button(user_link($user->id), icon('x-lg') . __('cancel')),
form_submit('submit', icon('check-lg') . __('delete'), 'btn-danger', false),
]),
]),
]);
}
/**
* Title for work log delete.
*/
function UserWorkLog_delete_title()
{
return __('Delete work log entry');
}
/**
* Render edit table.
*
* @param User $user
* @param Worklog $worklog
* @return string
*/
function UserWorkLog_edit_form(User $user, Worklog $worklog)
{
return form([
form_info(__('User'), User_Nick_render($user)),
form_date('work_timestamp', __('Work date'), $worklog->worked_at->timestamp, null, time()),
form_text('work_hours', __('Work hours'), $worklog->hours),
form_text('comment', __('Comment'), $worklog->comment, false, 200),
form_submit('submit', __('Save'))
]);
}
/**
* Form for edit a user work log entry.
*
* @param User $user
* @param Worklog $worklog
* @return string
*/
function UserWorkLog_edit_view(User $user, Worklog $worklog)
{
return page_with_title(UserWorkLog_edit_title(), [
buttons([
button(user_link($user->id), __('back'))
]),
msg(),
UserWorkLog_edit_form($user, $worklog)
]);
}
/**
* Form for adding a user work log entry.
*
* @param User $user
* @param Worklog $worklog
* @return string
*/
function UserWorkLog_add_view(User $user, Worklog $worklog)
{
return page_with_title(UserWorkLog_add_title(), [
buttons([
button(user_link($user->id), __('back'))
]),
msg(),
UserWorkLog_edit_form($user, $worklog)
]);
}
/**
* Title text for editing work log entry.
*/
function UserWorkLog_edit_title()
{
return __('Edit work log entry');
}
/**
* Title text for adding work log entry.
*/
function UserWorkLog_add_title()
{
return __('Add work log entry');
}

View File

@ -398,12 +398,12 @@ function User_view_worklog(Worklog $worklog, $admin_user_worklog_privilege)
if ($admin_user_worklog_privilege) {
$actions = table_buttons([
button(
user_worklog_edit_link($worklog),
url('/admin/user/' . $worklog->user->id . '/worklog/' . $worklog->id),
icon('pencil-square') . __('edit'),
'btn-sm'
),
button(
user_worklog_delete_link($worklog),
url('/admin/user/' . $worklog->user->id . '/worklog/' . $worklog->id . '/delete'),
icon('trash') . __('delete'),
'btn-sm'
)
@ -500,7 +500,7 @@ function User_view(
. htmlspecialchars($user_source->name)
. (config('enable_user_name') ? ' <small>' . $user_name . '</small>' : ''),
[
msg(),
msg(true),
div('row', [
div('col-md-12', [
buttons([
@ -532,8 +532,8 @@ function User_view(
)
: '',
$admin_user_worklog_privilege ? button(
user_worklog_add_link($user_source),
icon('list') . __('Add work log')
url('/admin/user/' . $user_source->id . '/worklog'),
icon('list') . __('worklog.add')
) : '',
$its_me ? button(
page_link_to('settings/profile'),

View File

@ -200,3 +200,12 @@ msgstr "Benutzer erfolgreich bearbeitet."
msgid "message.delete.success"
msgstr "Nachricht erfolgreich gelöscht."
msgid "worklog.add.success"
msgstr "Arbeitseinsatz erfolgreich angelegt."
msgid "worklog.edit.success"
msgstr "Arbeitseinsatz erfolgreich bearbeitet."
msgid "worklog.delete.success"
msgstr "Arbeitseinsatz erfolgreich gelöscht."

View File

@ -233,7 +233,7 @@ msgstr "Passwort wiederholen"
#: includes/view/ShiftEntry_view.php:118 includes/view/ShiftEntry_view.php:141
#: includes/view/ShiftEntry_view.php:207 includes/view/ShiftTypes_view.php:64
#: includes/view/UserDriverLicenses_view.php:54
#: includes/view/UserWorkLog_view.php:49 includes/view/User_view.php:84
#: includes/view/User_view.php:84
#: includes/view/User_view.php:93 includes/view/User_view.php:98
#: includes/view/User_view.php:103 includes/view/User_view.php:154
msgid "Save"
@ -330,7 +330,7 @@ msgstr "bearbeiten"
#: includes/view/ShiftEntry_view.php:28 includes/view/ShiftEntry_view.php:57
#: includes/view/ShiftTypes_view.php:28 includes/view/ShiftTypes_view.php:96
#: includes/view/ShiftTypes_view.php:128 includes/view/Shifts_view.php:156
#: includes/view/UserWorkLog_view.php:21 includes/view/User_view.php:501
#: includes/view/User_view.php:501
msgid "delete"
msgstr "löschen"
@ -762,30 +762,6 @@ msgstr "Deine Führerschein-Infos wurden gelöscht."
msgid "Edit %s driving license information"
msgstr "Bearbeite die Führerschein-Infos von %s"
#: includes/controller/user_worklog_controller.php:22
msgid "Work log entry deleted."
msgstr "Arbeitseinsatz gelöscht."
#: includes/controller/user_worklog_controller.php:52
msgid "Work log entry updated."
msgstr "Arbeitseinsatz geändert."
#: includes/controller/user_worklog_controller.php:81
msgid "Please enter work date."
msgstr "Bitte Einsatzdatum angeben."
#: includes/controller/user_worklog_controller.php:87
msgid "Please enter work hours in format ##[.##]"
msgstr "Bitte Stunden im Format ##[.##] eingeben."
#: includes/controller/user_worklog_controller.php:93
msgid "Please enter a comment."
msgstr "Bitte Kommentar angeben."
#: includes/controller/user_worklog_controller.php:123
msgid "Work log entry created."
msgstr "Arbeitseinsatz angelegt."
#: includes/controller/users_controller.php:64
msgid "You cannot delete yourself."
msgstr "Du kannst Dich nicht selber löschen."
@ -945,7 +921,6 @@ msgstr "Engel wurden markiert."
#: includes/pages/admin_active.php:98 includes/pages/admin_rooms.php:155
#: includes/pages/admin_rooms.php:198 includes/pages/admin_shifts.php:333
#: includes/view/UserAngelTypes_view.php:147
#: includes/view/UserWorkLog_view.php:64 includes/view/UserWorkLog_view.php:82
#: includes/view/User_view.php:121 includes/view/User_view.php:145
msgid "back"
msgstr "zurück"
@ -1967,7 +1942,6 @@ msgstr "Möchtest Du den Engeltypen %s löschen?"
#: includes/view/UserAngelTypes_view.php:98
#: includes/view/UserAngelTypes_view.php:122
#: includes/view/UserAngelTypes_view.php:175
#: includes/view/UserWorkLog_view.php:20
msgid "cancel"
msgstr "abbrechen"
@ -2280,7 +2254,6 @@ msgstr "Möchtest du den folgenden User für die Schicht eintragen?"
#: includes/view/ShiftEntry_view.php:92 includes/view/ShiftEntry_view.php:117
#: includes/view/UserAngelTypes_view.php:153
#: includes/view/UserWorkLog_view.php:45
msgid "User"
msgstr "Benutzer"
@ -2471,35 +2444,14 @@ msgstr "7,5t LKW"
msgid "Truck 12t"
msgstr "12t LKW"
#: includes/view/UserWorkLog_view.php:15
#, php-format
msgid "Do you want to delete the worklog entry for %s?"
msgstr "Möchtest du den Arbeitseinsatz von %s wirklich löschen?"
#: includes/view/UserWorkLog_view.php:32
msgid "Delete work log entry"
msgstr "Arbeitseinsatz gelöscht."
#: includes/view/UserWorkLog_view.php:46
msgid "Work date"
msgstr "Einsatzdatum"
#: includes/view/UserWorkLog_view.php:47
msgid "Work hours"
msgstr "Arbeitsstunden"
#: includes/view/UserWorkLog_view.php:48 includes/view/User_view.php:572
#: includes/view/User_view.php:572
msgid "Comment"
msgstr "Kommentar"
#: includes/view/UserWorkLog_view.php:94
msgid "Edit work log entry"
msgstr "Arbeitseinsatz bearbeiten"
#: includes/view/UserWorkLog_view.php:102
msgid "Add work log entry"
msgstr "Arbeitseinsatz hinzufügen"
msgid "Pronoun"
msgstr "Pronomen"
@ -2649,10 +2601,6 @@ msgstr "Führerschein"
msgid "Vouchers"
msgstr "Gutscheine"
#: includes/view/User_view.php:612
msgid "Add work log"
msgstr "Neuer Arbeitseinsatz"
#: includes/view/User_view.php:620
msgid "iCal Export"
msgstr "iCal Export"
@ -2806,6 +2754,9 @@ msgstr "Löschen"
msgid "form.updated"
msgstr "Aktualisiert"
msgid "form.cancel"
msgstr "Abbrechen"
msgid "schedule.import"
msgstr "Programm importieren"
@ -3125,3 +3076,24 @@ msgstr "Engel"
msgid "date"
msgstr "Datum"
msgid "worklog.add"
msgstr "Arbeitseinsatz hinzufügen"
msgid "worklog.edit"
msgstr "Arbeitseinsatz bearbeiten"
msgid "worklog.date"
msgstr "Einsatzdatum"
msgid "worklog.hours"
msgstr "Arbeitsstunden"
msgid "worklog.comment"
msgstr "Kommentar"
msgid "worklog.delete"
msgstr "Arbeitseinsatz löschen"
msgid "worklog.delete.info"
msgstr "Möchtest du den Arbeitseinsatz von %s wirklich löschen?"

View File

@ -199,3 +199,12 @@ msgstr "User edited successfully."
msgid "message.delete.success"
msgstr "Message successfully deleted."
msgid "worklog.add.success"
msgstr "Work log successfully added."
msgid "worklog.edit.success"
msgstr "Work log successfully updated."
msgid "worklog.delete.success"
msgstr "Work log successfully deleted."

View File

@ -76,6 +76,9 @@ msgstr "Delete"
msgid "form.updated"
msgstr "Updated"
msgid "form.cancel"
msgstr "Cancel"
msgid "schedule.import"
msgstr "Import schedule"
@ -397,3 +400,24 @@ msgstr "Angel"
msgid "date"
msgstr "Date"
msgid "worklog.add"
msgstr "Add work log"
msgid "worklog.edit"
msgstr "Edit work log"
msgid "worklog.date"
msgstr "Work date"
msgid "worklog.hours"
msgstr "Work hours"
msgid "worklog.comment"
msgstr "Comment"
msgid "worklog.delete"
msgstr "Delete work log"
msgid "worklog.delete.info"
msgstr "Do you really want to delete the work log for %s?"

View File

@ -0,0 +1,21 @@
{% extends "layouts/app.twig" %}
{% import 'macros/base.twig' as m %}
{% import 'macros/form.twig' as f %}
{% block title %}{{ __('worklog.delete') }}{% endblock %}
{% block content %}
<div class="container">
<h1>{{ block('title') }}</h1>
<form method="post">
{{ csrf() }}
<div class="row">
<div class="col-md-12">
{{ m.alert(__('worklog.delete.info', [m.user(user)]), 'danger', true) }}
{{ m.button(__('form.cancel'), url('/users?action=view&user_id=' ~ user.id)) }}
{{ f.submit(__('form.delete'), {'btn_type': 'danger'}) }}
</div>
</div>
</form>
</div>
{% endblock %}

View File

@ -0,0 +1,49 @@
{% extends "layouts/app.twig" %}
{% import 'macros/base.twig' as m %}
{% import 'macros/form.twig' as f %}
{% block title %}{{ __(is_edit ? 'worklog.edit' : 'worklog.add') }}{% endblock %}
{% block content %}
<div class="container">
<h1>{{ block('title') }}</h1>
{% include 'layouts/parts/messages.twig' %}
<form method="post">
{{ csrf() }}
<div class="row g-2">
<div class="col-12">
{{ m.button(__('back'), url('/users?action=view&user_id=' ~ user.id)) }}
</div>
<div class="col-12">
<div>
<label class="form-label">{{ __('User') }}</label>
</div>
{{ m.user(user, {'pronoun': true}) }}
</div>
<div class="col-12">
{{ f.input(
'work_date',
__('worklog.date'),
'date',
{'value': work_date.format('Y-m-d'), 'required': true}
) }}
{{ f.input(
'work_hours',
__('worklog.hours'),
'number',
{'value': work_hours, 'required': true, 'step': '0.01', 'min': 0}
) }}
{{ f.input(
'comment',
__('worklog.comment'),
'text',
{'value': comment, 'required': true, 'max_length': 200}
) }}
{{ f.submit(__('form.save')) }}
</div>
</div>
</form>
</div>
{% endblock %}

View File

@ -20,6 +20,7 @@
{%- if opt.max_length is defined %} maxlength="{{ opt.max_length }}"{% endif %}
{%- if opt.min is defined %} min="{{ opt.min }}"{% endif %}
{%- if opt.max is defined %} max="{{ opt.max }}"{% endif %}
{%- if opt.step is defined %} step="{{ opt.step }}"{% endif %}
{%- if opt.required|default(false) %}
required
{%- endif -%}

View File

@ -0,0 +1,210 @@
<?php
namespace Engelsystem\Controllers\Admin;
use Carbon\Carbon;
use Engelsystem\Config\Config;
use Engelsystem\Controllers\BaseController;
use Engelsystem\Controllers\HasUserNotifications;
use Engelsystem\Helpers\Authenticator;
use Engelsystem\Http\Exceptions\HttpNotFound;
use Engelsystem\Http\Redirector;
use Engelsystem\Http\Request;
use Engelsystem\Http\Response;
use Engelsystem\Models\User\User;
use Engelsystem\Models\Worklog;
use Psr\Log\LoggerInterface;
class UserWorkLogController extends BaseController
{
use HasUserNotifications;
/** @var Authenticator */
protected $auth;
/** @var Config */
protected $config;
/** @var LoggerInterface */
protected $log;
/** @var Worklog */
protected $worklog;
/** @var Redirector */
protected $redirect;
/** @var Response */
protected $response;
/** @var User */
protected $user;
/** @var array */
protected $permissions = [
'admin_user_worklog',
];
/**
* @param Authenticator $auth
* @param Config $config
* @param LoggerInterface $log
* @param Worklog $worklog
* @param Redirector $redirector
* @param Response $response
* @param User $user
*/
public function __construct(
Authenticator $auth,
Config $config,
LoggerInterface $log,
Worklog $worklog,
Redirector $redirector,
Response $response,
User $user
) {
$this->auth = $auth;
$this->config = $config;
$this->log = $log;
$this->worklog = $worklog;
$this->redirect = $redirector;
$this->response = $response;
$this->user = $user;
}
/**
* @param Request $request
* @return Response
*/
public function editWorklog(Request $request): Response
{
$user_id = $request->getAttribute('id');
$user = $this->user->findOrFail($user_id);
$worklog_id = $request->getAttribute('worklog_id');
if (isset($worklog_id)) {
$worklog = $this->worklog->findOrFail($worklog_id);
if ($worklog->user->id != $user_id) {
throw new HttpNotFound();
}
return $this->showEditWorklog($user, $worklog->worked_at, $worklog->hours, $worklog->comment, true);
} else {
return $this->showEditWorklog($user, $this->getWorkDateSuggestion());
}
}
/**
* @param Request $request
* @return Response
*/
public function saveWorklog(Request $request): Response
{
$user_id = $request->getAttribute('id');
$user = $this->user->findOrFail($user_id);
$data = $this->validate($request, [
'work_date' => 'required|date:Y-m-d',
'work_hours' => 'float|min:0',
'comment' => 'required|max:200',
]);
$worklog_id = $request->getAttribute('worklog_id');
if (isset($worklog_id)) {
$worklog = $this->worklog->findOrFail($worklog_id);
if ($worklog->user->id != $user_id) {
throw new HttpNotFound();
}
} else {
$worklog = new Worklog();
$worklog->user()->associate($user);
$worklog->creator()->associate($this->auth->user());
}
$worklog->worked_at = $data['work_date'];
$worklog->hours = $data['work_hours'];
$worklog->comment = $data['comment'];
$worklog->save();
$this->addNotification(isset($worklog_id) ? 'worklog.edit.success' : 'worklog.add.success');
return $this->redirect->to('/users?action=view&user_id=' . $user_id);
// TODO Once User_view.php gets removed, change this to withView + getNotifications
}
/**
* @param Request $request
* @return Response
*/
public function showDeleteWorklog(Request $request): Response
{
$user_id = $request->getAttribute('id');
$user = $this->user->findOrFail($user_id);
$worklog_id = $request->getAttribute('worklog_id');
$worklog = $this->worklog->findOrFail($worklog_id);
if ($worklog->user->id != $user_id) {
throw new HttpNotFound();
}
return $this->response->withView(
'admin/user/delete-worklog.twig',
[ 'user' => $user ]
);
}
/**
* @param Request $request
* @return Response
*/
public function deleteWorklog(Request $request): Response
{
$user_id = $request->getAttribute('id');
$worklog_id = $request->getAttribute('worklog_id');
$worklog = $this->worklog->findOrFail($worklog_id);
if ($worklog->user->id != $user_id) {
throw new HttpNotFound();
}
$worklog->delete();
$this->addNotification('worklog.delete.success');
return $this->redirect->to('/users?action=view&user_id=' . $user_id);
// TODO Once User_view.php gets removed, change this to withView + getNotifications
}
private function showEditWorklog(
User $user,
Carbon $work_date,
float $work_hours = 0,
string $comment = '',
bool $is_edit = false
): Response {
return $this->response->withView(
'admin/user/edit-worklog.twig',
[
'user' => $user,
'work_date' => $work_date,
'work_hours' => $work_hours,
'comment' => $comment,
'is_edit' => $is_edit,
]
);
}
/**
* @return Carbon
*/
private function getWorkDateSuggestion(): Carbon
{
$buildup_start = config('buildup_start');
$event_start = config('event_start');
$work_date_suggestion = Carbon::today();
if (!empty($buildup_start) && (empty($event_start) || $event_start->lessThan(Carbon::now()))) {
$work_date_suggestion = $buildup_start->startOfDay();
}
return $work_date_suggestion;
}
}

View File

@ -19,6 +19,7 @@ class Validator
protected $mapping = [
'accepted' => 'TrueVal',
'int' => 'IntVal',
'float' => 'FloatVal',
'required' => 'NotEmpty',
];

View File

@ -26,7 +26,6 @@ class LegacyMiddleware implements MiddlewareInterface
'shifts_json_export',
'users',
'user_driver_licenses',
'user_worklog',
'admin_shifts_history',
];
@ -139,8 +138,6 @@ class LegacyMiddleware implements MiddlewareInterface
$title = shifts_title();
$content = user_shifts();
return [$title, $content];
case 'user_worklog':
return user_worklog_controller();
case 'register':
$title = register_title();
$content = guest_register();

View File

@ -0,0 +1,394 @@
<?php
namespace Engelsystem\Test\Unit\Controllers\Admin;
use Carbon\Carbon;
use Engelsystem\Controllers\Admin\UserWorkLogController;
use Engelsystem\Helpers\Authenticator;
use Engelsystem\Http\Exceptions\HttpNotFound;
use Engelsystem\Http\Exceptions\ValidationException;
use Engelsystem\Http\Redirector;
use Engelsystem\Http\UrlGenerator;
use Engelsystem\Http\Validation\Validator;
use Engelsystem\Models\User\User;
use Engelsystem\Models\Worklog;
use Engelsystem\Test\Unit\Controllers\ControllerTest;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use PHPUnit\Framework\MockObject\MockObject;
class UserWorkLogControllerTest extends ControllerTest
{
/** @var Authenticator|MockObject */
protected $auth;
/** @var Redirector|MockObject */
protected $redirect;
/** @var User */
protected $user;
/** @var UserWorkLogController */
protected $controller;
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::editWorklog
*/
public function testShowAddWorklogWithUnknownUserIdThrows()
{
$request = $this->request->withAttribute('id', 1234);
$this->expectException(ModelNotFoundException::class);
$this->controller->editWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::editWorklog
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::__construct
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::showEditWorklog
*/
public function testShowAddWorklog()
{
$request = $this->request->withAttribute('id', $this->user->id);
$this->response->expects($this->once())
->method('withView')
->willReturnCallback(function (string $view, array $data) {
$this->assertEquals('admin/user/edit-worklog.twig', $view);
$this->assertEquals($this->user->id, $data['user']->id);
$this->assertEquals(Carbon::today(), $data['work_date']);
$this->assertEquals(0, $data['work_hours']);
$this->assertEquals('', $data['comment']);
$this->assertFalse($data['is_edit']);
return $this->response;
});
$this->controller->editWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::editWorklog
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::getWorkDateSuggestion
*
* @dataProvider buildupConfigsAndWorkDates
*/
public function testShowAddWorklogWithSuggestedWorkDate($buildup_start, $event_start, $suggested_work_date)
{
$request = $this->request->withAttribute('id', $this->user->id);
config(['buildup_start' => $buildup_start]);
config(['event_start' => $event_start]);
$this->response->expects($this->once())
->method('withView')
->willReturnCallback(function (string $view, array $data) use ($suggested_work_date) {
$this->assertEquals($suggested_work_date, $data['work_date']);
return $this->response;
});
$this->controller->editWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::editWorklog
*/
public function testShowEditWorklogWithWorkLogNotAssociatedToUserThrows()
{
/** @var User $user2 */
$user2 = User::factory()->create();
/** @var Worklog $worklog */
$worklog = Worklog::factory(['user_id' => $user2->id])->create();
$request = $this->request
->withAttribute('id', $this->user->id)
->withAttribute('worklog_id', $worklog->id);
$this->expectException(HttpNotFound::class);
$this->controller->editWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::editWorklog
*/
public function testShowEditWorklog()
{
/** @var Worklog $worklog */
$worklog = Worklog::factory([
'user_id' => $this->user->id,
'worked_at' => new Carbon('2022-01-01'),
'hours' => 3.14,
'comment' => 'a comment'
])->create();
$request = $this->request
->withAttribute('id', $this->user->id)
->withAttribute('worklog_id', $worklog->id);
$this->response->expects($this->once())
->method('withView')
->willReturnCallback(function (string $view, array $data) {
$this->assertEquals($this->user->id, $data['user']->id);
$this->assertEquals(new Carbon('2022-01-01'), $data['work_date']);
$this->assertEquals(3.14, $data['work_hours']);
$this->assertEquals('a comment', $data['comment']);
$this->assertTrue($data['is_edit']);
return $this->response;
});
$this->controller->editWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::saveWorklog
*/
public function testSaveWorklogWithUnkownUserIdThrows()
{
$request = $this->request->withAttribute('id', 1234)->withParsedBody([]);
$this->expectException(ModelNotFoundException::class);
$this->controller->saveWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::saveWorklog
*
* @dataProvider invalidSaveWorkLogParams
*/
public function testSaveWorklogWithInvalidParamsThrows($body)
{
$request = $this->request->withAttribute('id', $this->user->id)->withParsedBody($body);
$this->expectException(ValidationException::class);
$this->controller->saveWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::saveWorklog
*/
public function testSaveNewWorklog()
{
$work_date = Carbon::today();
$work_hours = 3.14;
$comment = str_repeat('X', 200);
$body = ['work_date' => $work_date, 'work_hours' => $work_hours, 'comment' => $comment];
$request = $this->request->withAttribute('id', $this->user->id)->withParsedBody($body);
$this->setExpects($this->auth, 'user', null, $this->user, $this->any());
$this->redirect->expects($this->once())
->method('to')
->with('/users?action=view&user_id=' . $this->user->id)
->willReturn($this->response);
$this->controller->saveWorklog($request);
$this->assertHasNotification('worklog.add.success');
$this->assertEquals(1, $this->user->worklogs->count());
$new_worklog = $this->user->worklogs[0];
$this->assertEquals($this->user->id, $new_worklog->user->id);
$this->assertEquals($work_date, $new_worklog->worked_at);
$this->assertEquals($work_hours, $new_worklog->hours);
$this->assertEquals($comment, $new_worklog->comment);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::saveWorklog
*/
public function testOverwriteWorklogWithUnknownWorkLogIdThrows()
{
$body = ['work_date' => Carbon::today(), 'work_hours' => 3.14, 'comment' => 'a comment'];
$request = $this->request
->withAttribute('id', $this->user->id)
->withAttribute('worklog_id', 1234)
->withParsedBody($body);
$this->expectException(ModelNotFoundException::class);
$this->controller->saveWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::saveWorklog
*/
public function testOverwriteWorklogWithWorkLogNotAssociatedToUserThrows()
{
/** @var User $user2 */
$user2 = User::factory()->create();
/** @var Worklog $worklog */
$worklog = Worklog::factory(['user_id' => $user2->id])->create();
$body = ['work_date' => Carbon::today(), 'work_hours' => 3.14, 'comment' => 'a comment'];
$request = $this->request
->withAttribute('id', $this->user->id)
->withAttribute('worklog_id', $worklog->id)
->withParsedBody($body);
$this->expectException(HttpNotFound::class);
$this->controller->saveWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::saveWorklog
*/
public function testOverwriteWorklog()
{
/** @var Worklog $worklog */
$worklog = Worklog::factory(['user_id' => $this->user->id])->create();
$work_date = Carbon::today();
$work_hours = 3.14;
$comment = str_repeat('X', 200);
$body = ['work_date' => $work_date, 'work_hours' => $work_hours, 'comment' => $comment];
$request = $this->request
->withAttribute('id', $this->user->id)
->withAttribute('worklog_id', $worklog->id)
->withParsedBody($body);
$this->setExpects($this->auth, 'user', null, $this->user, $this->any());
$this->redirect->expects($this->once())
->method('to')
->with('/users?action=view&user_id=' . $this->user->id)
->willReturn($this->response);
$this->controller->saveWorklog($request);
$this->assertHasNotification('worklog.edit.success');
$worklog = Worklog::find($worklog->id);
$this->assertEquals($work_date, $worklog->worked_at);
$this->assertEquals($work_hours, $worklog->hours);
$this->assertEquals($comment, $worklog->comment);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::showDeleteWorklog
*/
public function testShowDeleteWorklogWithWorkLogNotAssociatedToUserThrows()
{
/** @var User $user2 */
$user2 = User::factory()->create();
/** @var Worklog $worklog */
$worklog = Worklog::factory(['user_id' => $user2->id])->create();
$request = $this->request
->withAttribute('id', $this->user->id)
->withAttribute('worklog_id', $worklog->id);
$this->expectException(HttpNotFound::class);
$this->controller->showDeleteWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::showDeleteWorklog
*/
public function testShowDeleteWorklog()
{
/** @var Worklog $worklog */
$worklog = Worklog::factory(['user_id' => $this->user->id])->create();
$request = $this->request
->withAttribute('id', $this->user->id)
->withAttribute('worklog_id', $worklog->id);
$this->response->expects($this->once())
->method('withView')
->willReturnCallback(function (string $view, array $data) {
$this->assertEquals($this->user->id, $data['user']->id);
return $this->response;
});
$this->controller->showDeleteWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::deleteWorklog
*/
public function testDeleteWorklogWithUnknownWorkLogIdThrows()
{
$request = $this->request
->withAttribute('id', $this->user->id)
->withAttribute('worklog_id', 1234);
$this->expectException(ModelNotFoundException::class);
$this->controller->deleteWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::deleteWorklog
*/
public function testDeleteWorklogWithWorkLogNotAssociatedToUserThrows()
{
/** @var User $user2 */
$user2 = User::factory()->create();
/** @var Worklog $worklog */
$worklog = Worklog::factory(['user_id' => $user2->id])->create();
$request = $this->request
->withAttribute('id', $this->user->id)
->withAttribute('worklog_id', $worklog->id);
$this->expectException(HttpNotFound::class);
$this->controller->deleteWorklog($request);
}
/**
* @covers \Engelsystem\Controllers\Admin\UserWorkLogController::deleteWorklog
*/
public function testDeleteWorklog()
{
/** @var Worklog $worklog */
$worklog = Worklog::factory(['user_id' => $this->user->id])->create();
$request = $this->request
->withAttribute('id', $this->user->id)
->withAttribute('worklog_id', $worklog->id);
$this->setExpects($this->auth, 'user', null, $this->user, $this->any());
$this->redirect->expects($this->once())
->method('to')
->with('/users?action=view&user_id=' . $this->user->id)
->willReturn($this->response);
$this->controller->deleteWorklog($request);
$this->assertHasNotification('worklog.delete.success');
$worklog = Worklog::find($worklog->id);
$this->assertNull($worklog);
}
/**
* @return array[]
*/
public function invalidSaveWorkLogParams(): array
{
$today = Carbon::today();
return [
// missing work_date
[['work_hours' => 3.14, 'comment' => 'com']],
// missing work_hours
[['work_date' => $today, 'comment' => 'com']],
// missing comment
[['work_date' => $today, 'work_hours' => 3.14]],
// too low work_hours
[['work_date' => $today, 'work_hours' => -.1, 'comment' => 'com']],
// too low work_hours
[['work_date' => $today, 'work_hours' => 3.14, 'comment' => str_repeat('X', 201)]],
];
}
/**
* @return array[]
*/
public function buildupConfigsAndWorkDates(): array
{
$day_before_yesterday = Carbon::today()->subDays(2);
$yesterday = Carbon::yesterday();
$today = Carbon::today();
$tomorrow = Carbon::tomorrow();
// buildup_start, event_start, suggested work date
return [
[null, null, $today],
[$yesterday, null, $yesterday],
[$yesterday, $tomorrow, $today],
[$day_before_yesterday, $yesterday, $day_before_yesterday],
];
}
/**
* Setup environment
*/
public function setUp(): void
{
parent::setUp();
$this->app->bind('http.urlGenerator', UrlGenerator::class);
$this->auth = $this->createMock(Authenticator::class);
$this->app->instance(Authenticator::class, $this->auth);
$this->redirect = $this->createMock(Redirector::class);
$this->app->instance(Redirector::class, $this->redirect);
$this->user = User::factory()->create();
$this->setExpects($this->auth, 'user', null, $this->user, $this->any());
$this->controller = $this->app->make(UserWorkLogController::class);
$this->controller->setValidator(new Validator());
}
}

View File

@ -112,6 +112,14 @@ class ValidatorTest extends TestCase
['foo' => '0'],
['foo' => 'int']
));
$this->assertFalse($val->validate(
['foo' => '0.0'],
['foo' => 'int']
));
$this->assertTrue($val->validate(
['foo' => '0.0'],
['foo' => 'float']
));
$this->assertTrue($val->validate(
['foo' => 'on'],
['foo' => 'accepted']

View File

@ -48,13 +48,13 @@ class LegacyMiddlewareTest extends TestCase
$middleware->expects($this->once())
->method('loadPage')
->with('user_worklog')
->with('users')
->willReturn(['title', 'content']);
$middleware->expects($this->exactly(2))
->method('renderPage')
->withConsecutive(
['user_worklog', 'title', 'content'],
['users', 'title', 'content'],
['404', 'Page not found', 'It\'s not available!']
)
->willReturn($response);
@ -82,7 +82,7 @@ class LegacyMiddlewareTest extends TestCase
$defaultRequest->query = $parameters;
$defaultRequest->expects($this->once())
->method('path')
->willReturn('user-worklog');
->willReturn('users');
$parameters->expects($this->exactly(2))
->method('get')