Recreated shift type admin backend

This commit is contained in:
Igor Scheller 2023-10-25 02:42:11 +02:00 committed by msquare
parent bf83e6a300
commit 0b165bc24c
17 changed files with 530 additions and 338 deletions

View File

@ -162,6 +162,18 @@ $route->addGroup(
} }
); );
// Shift types
$route->addGroup(
'/shifttypes',
function (RouteCollector $route): void {
$route->get('', 'Admin\\ShiftTypesController@index');
$route->post('', 'Admin\\ShiftTypesController@delete');
$route->get('/{shift_type_id:\d+}', 'Admin\\ShiftTypesController@view');
$route->get('/edit[/{shift_type_id:\d+}]', 'Admin\\ShiftTypesController@edit');
$route->post('/edit[/{shift_type_id:\d+}]', 'Admin\\ShiftTypesController@save');
}
);
// Questions // Questions
$route->addGroup( $route->addGroup(
'/questions', '/questions',

View File

@ -1,163 +0,0 @@
<?php
use Engelsystem\Models\Shifts\ShiftType;
/**
* @param ShiftType $shifttype
* @return string
*/
function shifttype_link(ShiftType $shifttype)
{
return url('/shifttypes', ['action' => 'view', 'shifttype_id' => $shifttype->id]);
}
/**
* Delete a shifttype.
*
* @return array
*/
function shifttype_delete_controller()
{
$request = request();
if (!$request->has('shifttype_id')) {
throw_redirect(url('/shifttypes'));
}
$shifttype = ShiftType::findOrFail($request->input('shifttype_id'));
if ($request->hasPostData('delete')) {
engelsystem_log('Deleted shifttype ' . $shifttype->name);
success(sprintf(__('Shifttype %s deleted.'), $shifttype->name));
$shifttype->delete();
throw_redirect(url('/shifttypes'));
}
return [
sprintf(__('Delete shifttype %s'), $shifttype->name),
ShiftType_delete_view($shifttype),
];
}
/**
* Edit or create shift type.
*
* @return array
*/
function shifttype_edit_controller()
{
$shifttype_id = null;
$name = '';
$description = '';
$request = request();
if ($request->has('shifttype_id')) {
$shifttype = ShiftType::findOrFail($request->input('shifttype_id'));
$shifttype_id = $shifttype->id;
$name = $shifttype->name;
$description = $shifttype->description;
}
if ($request->hasPostData('submit')) {
$valid = true;
if ($request->has('name') && $request->input('name') != '') {
$name = strip_request_item('name');
} else {
$valid = false;
error(__('Please enter a name.'));
}
if ($request->has('description')) {
$description = strip_request_item_nl('description');
}
if ($valid) {
$shiftType = ShiftType::findOrNew($shifttype_id);
$shiftType->name = $name;
$shiftType->description = $description;
$shiftType->save();
if ($shifttype_id) {
engelsystem_log('Updated shifttype ' . $name);
success(__('Updated shifttype.'));
} else {
$shifttype_id = $shiftType->id;
engelsystem_log('Created shifttype ' . $name);
success(__('Created shifttype.'));
}
throw_redirect(url('/shifttypes', ['action' => 'view', 'shifttype_id' => $shifttype_id]));
}
}
return [
shifttypes_title(),
ShiftType_edit_view($name, $description, $shifttype_id),
];
}
/**
* @return array
*/
function shifttype_controller()
{
$request = request();
if (!$request->has('shifttype_id')) {
throw_redirect(url('/shifttypes'));
}
$shifttype = ShiftType::findOrFail($request->input('shifttype_id'));
return [
$shifttype->name,
ShiftType_view($shifttype),
];
}
/**
* List all shift types.
*
* @return array
*/
function shifttypes_list_controller()
{
$shifttypes = ShiftType::all()->sortBy('name', SORT_NATURAL | SORT_FLAG_CASE);
return [
shifttypes_title(),
ShiftTypes_list_view($shifttypes),
];
}
/**
* Text for shift type related links.
*
* @return string
*/
function shifttypes_title()
{
return __('Shifttypes');
}
/**
* Route shift type actions
*
* @return array
*/
function shifttypes_controller()
{
$request = request();
$action = 'list';
if ($request->has('action')) {
$action = $request->input('action');
}
return match ($action) {
'view' => shifttype_controller(),
'edit' => shifttype_edit_controller(),
'delete' => shifttype_delete_controller(),
'list' => shifttypes_list_controller(),
default => shifttypes_list_controller(),
};
}

View File

@ -31,7 +31,6 @@ $includeFiles = [
__DIR__ . '/../includes/view/ShiftsFilterRenderer.php', __DIR__ . '/../includes/view/ShiftsFilterRenderer.php',
__DIR__ . '/../includes/view/Shifts_view.php', __DIR__ . '/../includes/view/Shifts_view.php',
__DIR__ . '/../includes/view/ShiftEntry_view.php', __DIR__ . '/../includes/view/ShiftEntry_view.php',
__DIR__ . '/../includes/view/ShiftTypes_view.php',
__DIR__ . '/../includes/view/UserAngelTypes_view.php', __DIR__ . '/../includes/view/UserAngelTypes_view.php',
__DIR__ . '/../includes/view/UserHintsRenderer.php', __DIR__ . '/../includes/view/UserHintsRenderer.php',
__DIR__ . '/../includes/view/User_view.php', __DIR__ . '/../includes/view/User_view.php',
@ -42,7 +41,6 @@ $includeFiles = [
__DIR__ . '/../includes/controller/locations_controller.php', __DIR__ . '/../includes/controller/locations_controller.php',
__DIR__ . '/../includes/controller/shift_entries_controller.php', __DIR__ . '/../includes/controller/shift_entries_controller.php',
__DIR__ . '/../includes/controller/shifts_controller.php', __DIR__ . '/../includes/controller/shifts_controller.php',
__DIR__ . '/../includes/controller/shifttypes_controller.php',
__DIR__ . '/../includes/controller/users_controller.php', __DIR__ . '/../includes/controller/users_controller.php',
__DIR__ . '/../includes/controller/user_angeltypes_controller.php', __DIR__ . '/../includes/controller/user_angeltypes_controller.php',

View File

@ -328,7 +328,7 @@ function admin_shifts()
. '<br>' . '<br>'
. location_name_render(Location::find($shift['location_id'])), . location_name_render(Location::find($shift['location_id'])),
'title' => 'title' =>
ShiftType_name_render(ShiftType::find($shifttype_id)) ShiftType::find($shifttype_id)->name
. ($shift['title'] ? '<br />' . $shift['title'] : ''), . ($shift['title'] ? '<br />' . $shift['title'] : ''),
'needed_angels' => '', 'needed_angels' => '',
]; ];

View File

@ -83,7 +83,7 @@ function make_navigation()
'users' => ['All Angels', 'admin_user'], 'users' => ['All Angels', 'admin_user'],
'admin_free' => 'Free angels', 'admin_free' => 'Free angels',
'admin/questions' => ['Answer questions', 'question.edit'], 'admin/questions' => ['Answer questions', 'question.edit'],
'shifttypes' => 'Shifttypes', 'admin/shifttypes' => ['shifttype.shifttypes', 'shifttypes'],
'admin_shifts' => 'Create shifts', 'admin_shifts' => 'Create shifts',
'admin/locations' => ['location.locations', 'admin_locations'], 'admin/locations' => ['location.locations', 'admin_locations'],
'admin_groups' => 'Grouprights', 'admin_groups' => 'Grouprights',

View File

@ -1,140 +0,0 @@
<?php
use Engelsystem\Models\Shifts\ShiftType;
use Illuminate\Support\Collection;
/**
* @param ShiftType $shifttype
* @return string
*/
function ShiftType_name_render(ShiftType $shifttype)
{
if (auth()->can('shifttypes')) {
return '<a href="' . shifttype_link($shifttype) . '">' . $shifttype->name . '</a>';
}
return $shifttype->name;
}
/**
* @param ShiftType $shifttype
* @return string
*/
function ShiftType_delete_view(ShiftType $shifttype)
{
return page_with_title(sprintf(__('Delete shifttype %s'), $shifttype->name), [
info(sprintf(__('Do you want to delete shifttype %s?'), $shifttype->name), true),
form([
buttons([
button(url('/shifttypes'), icon('x-lg') . __('form.cancel')),
form_submit(
'delete',
icon('trash') . __('delete'),
'btn-danger',
false
),
]),
]),
], true);
}
/**
* @param string $name
* @param string $description
* @param int $shifttype_id
* @return string
*/
function ShiftType_edit_view($name, $description, $shifttype_id)
{
return page_with_title(
$shifttype_id
? (button(
url('/shifttypes', ['action' => 'view', 'shifttype_id' => $shifttype_id]),
icon('chevron-left'),
'btn-sm'
) . ' ' . __('Edit shifttype'))
: (button(url('/shifttypes'), icon('chevron-left'), 'btn-sm') . ' ' . __('Create shifttype')),
[
msg(),
buttons([
button(url('/shifttypes'), shifttypes_title(), 'back'),
]),
form([
form_text('name', __('general.name'), $name),
form_textarea('description', __('general.description'), $description),
form_info('', __('Please use markdown for the description.')),
form_submit('submit', __('form.save')),
]),
],
true
);
}
/**
* @param ShiftType $shifttype
* @return string
*/
function ShiftType_view(ShiftType $shifttype)
{
$parsedown = new Parsedown();
$title = $shifttype->name;
$link = button(url('/shifttypes'), icon('chevron-left'), 'btn-sm');
return page_with_title($link . ' ' . $title, [
msg(),
buttons([
button(
url('/shifttypes', ['action' => 'edit', 'shifttype_id' => $shifttype->id]),
icon('pencil') . __('edit')
),
button(
url('/shifttypes', ['action' => 'delete', 'shifttype_id' => $shifttype->id]),
icon('trash') . __('delete'),
),
]),
heading(__('general.description'), 2),
$parsedown->parse($shifttype->description),
], true);
}
/**
* @param ShiftType[]|array[]|Collection $shifttypes
* @return string
*/
function ShiftTypes_list_view($shifttypes)
{
foreach ($shifttypes as $shifttype) {
$shifttype->name = '<a href="'
. url('/shifttypes', ['action' => 'view', 'shifttype_id' => $shifttype->id])
. '">'
. $shifttype->name
. '</a>';
$shifttype->actions = table_buttons([
button(
url(
'/shifttypes',
['action' => 'edit', 'shifttype_id' => $shifttype->id]
),
icon('pencil') . __('edit'),
'btn-sm'
),
button(
url('/shifttypes', ['action' => 'delete', 'shifttype_id' => $shifttype->id]),
icon('trash') . __('delete'),
'btn-sm'
),
]);
}
$link = button(url('/shifttypes', ['action' => 'edit']), icon('plus-lg'), 'add');
return page_with_title(
shifttypes_title() . ' ' . $link,
[
msg(),
table([
'name' => __('general.name'),
'actions' => '',
], $shifttypes),
],
true,
);
}

View File

@ -175,7 +175,7 @@ function Shift_view(
$buttons = [ $buttons = [
$shift_admin ? button(shift_edit_link($shift), icon('pencil') . __('edit')) : '', $shift_admin ? button(shift_edit_link($shift), icon('pencil') . __('edit')) : '',
$shift_admin ? button(shift_delete_link($shift), icon('trash') . __('delete')) : '', $shift_admin ? button(shift_delete_link($shift), icon('trash') . __('delete')) : '',
$admin_shifttypes ? button(shifttype_link($shifttype), $shifttype->name) : '', $admin_shifttypes ? button(url('/admin/shifttypes/' . $shifttype->id), $shifttype->name) : '',
$admin_locations ? button(location_link($location), icon('pin-map-fill') . $location->name) : '', $admin_locations ? button(location_link($location), icon('pin-map-fill') . $location->name) : '',
]; ];
} }

View File

@ -272,6 +272,12 @@ msgstr "Ort erfolgreich bearbeitet."
msgid "location.delete.success" msgid "location.delete.success"
msgstr "Ort erfolgreich gelöscht." msgstr "Ort erfolgreich gelöscht."
msgid "shifttype.edit.success"
msgstr "Schichttyp erfolgreich bearbeitet."
msgid "shifttype.delete.success"
msgstr "Schichttyp erfolgreich gelöscht."
msgid "validation.name.exists" msgid "validation.name.exists"
msgstr "Der Name wird bereits verwendet." msgstr "Der Name wird bereits verwendet."

View File

@ -323,24 +323,6 @@ msgstr "Möchtest Du die Schicht %s von %s bis %s löschen?"
msgid "Shift could not be found." msgid "Shift could not be found."
msgstr "Schicht konnte nicht gefunden werden." msgstr "Schicht konnte nicht gefunden werden."
msgid "Shifttype %s deleted."
msgstr "Schichttyp %s gelöscht."
msgid "Delete shifttype %s"
msgstr "Lösche Schichttyp %s"
msgid "Please enter a name."
msgstr "Gib bitte einen Namen an."
msgid "Updated shifttype."
msgstr "Schichttyp geändert."
msgid "Created shifttype."
msgstr "Schichttyp erstellt."
msgid "Shifttypes"
msgstr "Schichttypen"
msgid "There is %d unconfirmed angeltype." msgid "There is %d unconfirmed angeltype."
msgid_plural "There are %d unconfirmed angeltypes." msgid_plural "There are %d unconfirmed angeltypes."
msgstr[0] "Es gibt %d nicht freigeschalteten Engeltypen!" msgstr[0] "Es gibt %d nicht freigeschalteten Engeltypen!"
@ -1127,15 +1109,6 @@ msgstr "Titel:"
msgid "Type:" msgid "Type:"
msgstr "Typ:" msgstr "Typ:"
msgid "Do you want to delete shifttype %s?"
msgstr "Möchtest Du den Schichttypen %s löschen?"
msgid "Edit shifttype"
msgstr "Schichttyp bearbeiten"
msgid "Create shifttype"
msgstr "Schichttyp erstellen"
msgid "Location" msgid "Location"
msgstr "Ort" msgstr "Ort"
@ -1960,6 +1933,18 @@ msgstr "Ort bearbeiten"
msgid "location.delete.title" msgid "location.delete.title"
msgstr "Ort \"%s\" löschen" msgstr "Ort \"%s\" löschen"
msgid "shifttype.shifttypes"
msgstr "Schichttypen"
msgid "shifttype.edit.title"
msgstr "Schichttyp bearbeiten"
msgid "shifttype.create.title"
msgstr "Schichttyp erstellen"
msgid "shifttype.delete.title"
msgstr "Schichttyp \"%s\" löschen"
msgid "event.day" msgid "event.day"
msgstr "Tag %1$d" msgstr "Tag %1$d"

View File

@ -271,6 +271,12 @@ msgstr "Location edited successfully."
msgid "location.delete.success" msgid "location.delete.success"
msgstr "Location successfully deleted." msgstr "Location successfully deleted."
msgid "shifttype.edit.success"
msgstr "Shift type edited successfully."
msgid "shifttype.delete.success"
msgstr "Shift type successfully deleted."
msgid "validation.name.exists" msgid "validation.name.exists"
msgstr "The name is already used." msgstr "The name is already used."

View File

@ -616,6 +616,18 @@ msgstr "Edit location"
msgid "location.delete.title" msgid "location.delete.title"
msgstr "Delete location \"%s\"" msgstr "Delete location \"%s\""
msgid "shifttype.shifttypes"
msgstr "Shift types"
msgid "shifttype.edit.title"
msgstr "Edit shift type"
msgid "shifttype.create.title"
msgstr "Create shift type"
msgid "shifttype.delete.title"
msgstr "Delete shift type \"%s\""
msgid "event.day" msgid "event.day"
msgstr "Day %1$d" msgstr "Day %1$d"

View File

@ -0,0 +1,38 @@
{% extends 'admin/shifttypes/index.twig' %}
{% import 'macros/base.twig' as m %}
{% import 'macros/form.twig' as f %}
{% block title %}{{ shifttype ? __('shifttype.edit.title') : __('shifttype.create.title') }}{% endblock %}
{% block row_content %}
<form method="post">
{{ csrf() }}
{{ f.hidden('id', shifttype ? shifttype.id : '') }}
<div class="row">
<div class="col-lg-6">
{{ f.input('name', __('general.name'), {
'required': true,
'required_icon': true,
'value': f.formData('shifttype', shifttype ? shifttype.name : ''),
}) }}
{{ f.textarea('description', __('general.description'), {
'value': f.formData('description', shifttype ? shifttype.description : ''),
'rows': 5,
'info': __('form.markdown')
}) }}
</div>
</div>
<div class="col-md-12">
<div class="btn-group">
{{ f.submit(__('form.save'), {'icon_left': 'save'}) }}
{% if shifttype %}
{{ f.delete(__('form.delete'), {'confirm_title': __('shifttype.delete.title', [shifttype.name|e])}) }}
{% endif %}
</div>
</div>
</form>
{% endblock %}

View File

@ -0,0 +1,66 @@
{% extends 'layouts/app.twig' %}
{% import 'macros/base.twig' as m %}
{% import 'macros/form.twig' as f %}
{% block title %}{{ __('shifttype.shifttypes') }}{% endblock %}
{% block content %}
<div class="container">
<h1>
{% if not is_index|default(false) %}
{{ m.button(m.icon('chevron-left'), url('/admin/shifttypes'), 'secondary', 'sm') }}
{% endif %}
{{ block('title') }}
{% if is_index|default(false) %}
{{ m.button(m.icon('plus-lg'), url('/admin/shifttypes/edit'), 'secondary') }}
{% endif %}
</h1>
{% include 'layouts/parts/messages.twig' %}
<div class="row">
{% block row_content %}
<div class="col-md-12">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>{{ __('general.name') }}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for shifttype in shifttypes %}
<tr>
<td>
<a href="{{ url('/admin/shifttypes/' ~ shifttype.id) }}">{{ shifttype.name }}</a>
</td>
<td>
<div class="d-flex ms-auto">
{{ m.button(m.icon('pencil'), url('admin/shifttypes/edit/' ~ shifttype.id), null, 'sm', __('form.edit')) }}
<form method="post" class="ps-1">
{{ csrf() }}
{{ f.hidden('id', shifttype.id) }}
{{ f.delete(null, {'size': 'sm', 'confirm_title': __('shifttype.delete.title', [shifttype.name|e])}) }}
</form>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends 'admin/shifttypes/index.twig' %}
{% import 'macros/base.twig' as m %}
{% import 'macros/form.twig' as f %}
{% block title %}{{ shifttype.name }}{% endblock %}
{% block row_content %}
<div class="col-md-12">
{{ shifttype.description|md }}
</div>
{% endblock %}

View File

@ -0,0 +1,141 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Controllers\Admin;
use Engelsystem\Controllers\BaseController;
use Engelsystem\Controllers\HasUserNotifications;
use Engelsystem\Http\Exceptions\ValidationException;
use Engelsystem\Http\Redirector;
use Engelsystem\Http\Request;
use Engelsystem\Http\Response;
use Engelsystem\Http\Validation\Validator;
use Engelsystem\Models\Shifts\ShiftType;
use Psr\Log\LoggerInterface;
class ShiftTypesController extends BaseController
{
use HasUserNotifications;
/** @var array<string> */
protected array $permissions = [
'shifttypes',
];
public function __construct(
protected LoggerInterface $log,
protected ShiftType $shiftType,
protected Redirector $redirect,
protected Response $response
) {
}
public function index(): Response
{
$shiftTypes = $this->shiftType
->get()
->sortBy('name', SORT_NATURAL | SORT_FLAG_CASE);
return $this->response->withView(
'admin/shifttypes/index',
['shifttypes' => $shiftTypes, 'is_index' => true]
);
}
public function edit(Request $request): Response
{
$shiftTypeId = (int) $request->getAttribute('shift_type_id');
$shiftType = $this->shiftType->find($shiftTypeId);
return $this->response->withView(
'admin/shifttypes/edit',
['shifttype' => $shiftType]
);
}
public function view(Request $request): Response
{
$shiftTypeId = (int) $request->getAttribute('shift_type_id');
$shiftType = $this->shiftType->findOrFail($shiftTypeId);
return $this->response->withView(
'admin/shifttypes/view',
['shifttype' => $shiftType]
);
}
public function save(Request $request): Response
{
$shiftTypeId = (int) $request->getAttribute('shift_type_id');
/** @var ShiftType $shiftType */
$shiftType = $this->shiftType->findOrNew($shiftTypeId);
if ($request->request->has('delete')) {
return $this->delete($request);
}
$data = $this->validate(
$request,
[
'name' => 'required',
'description' => 'required|optional',
]
);
if (ShiftType::whereName($data['name'])->where('id', '!=', $shiftType->id)->exists()) {
throw new ValidationException((new Validator())->addErrors(['name' => ['validation.name.exists']]));
}
$shiftType->name = $data['name'];
$shiftType->description = $data['description'];
$shiftType->save();
$this->log->info(
'Updated shift type "{name}": {description}',
[
'name' => $shiftType->name,
'description' => $shiftType->description,
]
);
$this->addNotification('shifttype.edit.success');
return $this->redirect->to('/admin/shifttypes');
}
public function delete(Request $request): Response
{
$data = $this->validate($request, [
'id' => 'required|int',
'delete' => 'checked',
]);
$shiftType = $this->shiftType->findOrFail($data['id']);
$shifts = $shiftType->shifts;
foreach ($shifts as $shift) {
foreach ($shift->shiftEntries as $entry) {
event('shift.entry.deleting', [
'user' => $entry->user,
'start' => $shift->start,
'end' => $shift->end,
'name' => $shift->shiftType->name,
'title' => $shift->title,
'type' => $entry->angelType->name,
'location' => $shift->location,
'freeloaded' => $entry->freeloaded,
]);
}
}
$shiftType->delete();
$this->log->info('Deleted shift type {name}', ['name' => $shiftType->name]);
$this->addNotification('shifttype.delete.success');
return $this->redirect->to('/admin/shifttypes');
}
}

View File

@ -88,9 +88,6 @@ class LegacyMiddleware implements MiddlewareInterface
return users_controller(); return users_controller();
case 'user_angeltypes': case 'user_angeltypes':
return user_angeltypes_controller(); return user_angeltypes_controller();
case 'shifttypes':
list($title, $content) = shifttypes_controller();
return [$title, $content];
case 'admin_event_config': case 'admin_event_config':
list($title, $content) = event_config_edit_controller(); list($title, $content) = event_config_edit_controller();
return [$title, $content]; return [$title, $content];

View File

@ -0,0 +1,223 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Test\Unit\Controllers\Admin;
use Engelsystem\Controllers\Admin\ShiftTypesController;
use Engelsystem\Events\EventDispatcher;
use Engelsystem\Helpers\Carbon;
use Engelsystem\Http\Exceptions\ValidationException;
use Engelsystem\Http\Redirector;
use Engelsystem\Http\Request;
use Engelsystem\Http\Validation\Validator;
use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\Shifts\ShiftType;
use Engelsystem\Models\Shifts\Shift;
use Engelsystem\Models\User\User;
use Engelsystem\Test\Unit\Controllers\ControllerTest;
use PHPUnit\Framework\MockObject\MockObject;
class ShiftTypeControllerTest extends ControllerTest
{
protected Redirector|MockObject $redirect;
/**
* @covers \Engelsystem\Controllers\Admin\ShiftTypesController::__construct
* @covers \Engelsystem\Controllers\Admin\ShiftTypesController::index
*/
public function testIndex(): void
{
/** @var ShiftTypesController $controller */
$controller = $this->app->make(ShiftTypesController::class);
ShiftType::factory(5)->create();
$this->response->expects($this->once())
->method('withView')
->willReturnCallback(function (string $view, array $data) {
$this->assertEquals('admin/shifttypes/index', $view);
$this->assertTrue($data['is_index'] ?? false);
$this->assertCount(5, $data['shifttypes'] ?? []);
return $this->response;
});
$controller->index();
}
/**
* @covers \Engelsystem\Controllers\Admin\ShiftTypesController::view
*/
public function testView(): void
{
/** @var ShiftTypesController $controller */
$controller = $this->app->make(ShiftTypesController::class);
$shiftType = ShiftType::factory()->create();
$this->response->expects($this->once())
->method('withView')
->willReturnCallback(function (string $view, array $data) use ($shiftType) {
$this->assertEquals('admin/shifttypes/view', $view);
$this->assertArrayHasKey('shifttype', $data);
$this->assertEquals($shiftType->id, $data['shifttype']['id']);
return $this->response;
});
$controller->view(new Request([], [], ['shift_type_id' => $shiftType->id]));
}
/**
* @covers \Engelsystem\Controllers\Admin\ShiftTypesController::edit
*/
public function testEdit(): void
{
/** @var ShiftTypesController $controller */
$controller = $this->app->make(ShiftTypesController::class);
/** @var ShiftType $shifttype */
$shifttype = ShiftType::factory()->create();
$this->response->expects($this->once())
->method('withView')
->willReturnCallback(function (string $view, array $data) use ($shifttype) {
$this->assertEquals('admin/shifttypes/edit', $view);
$this->assertEquals($shifttype->id, $data['shifttype']?->id);
$this->assertNotEmpty($data['shifttype']?->name);
$this->assertNotEmpty($data['shifttype']?->description);
return $this->response;
});
$this->request = $this->request->withAttribute('shift_type_id', 1);
$controller->edit($this->request);
}
/**
* @covers \Engelsystem\Controllers\Admin\ShiftTypesController::edit
*/
public function testEditNew(): void
{
/** @var ShiftTypesController $controller */
$controller = $this->app->make(ShiftTypesController::class);
$this->response->expects($this->once())
->method('withView')
->willReturnCallback(function (string $view, array $data) {
$this->assertEquals('admin/shifttypes/edit', $view);
$this->assertArrayHasKey('shifttype', $data);
$this->assertNull($data['shifttype']);
return $this->response;
});
$controller->edit($this->request);
}
/**
* @covers \Engelsystem\Controllers\Admin\ShiftTypesController::save
*/
public function testSave(): void
{
/** @var ShiftTypesController $controller */
$controller = $this->app->make(ShiftTypesController::class);
$controller->setValidator(new Validator());
$this->setExpects($this->redirect, 'to', ['/admin/shifttypes']);
$this->request = $this->request->withParsedBody([
'name' => 'Test shift type',
'description' => 'Something',
]);
$controller->save($this->request);
$this->assertTrue($this->log->hasInfoThatContains('Updated shift type'));
$this->assertHasNotification('shifttype.edit.success');
$this->assertCount(1, ShiftType::whereName('Test shift type')->get());
}
/**
* @covers \Engelsystem\Controllers\Admin\ShiftTypesController::save
*/
public function testSaveUniqueName(): void
{
/** @var ShiftTypesController $controller */
$controller = $this->app->make(ShiftTypesController::class);
$controller->setValidator(new Validator());
ShiftType::factory()->create(['name' => 'Test shift type']);
$this->request = $this->request->withParsedBody([
'name' => 'Test shift type',
]);
$this->expectException(ValidationException::class);
$controller->save($this->request);
}
/**
* @covers \Engelsystem\Controllers\Admin\ShiftTypesController::save
* @covers \Engelsystem\Controllers\Admin\ShiftTypesController::delete
*/
public function testSaveDelete(): void
{
/** @var ShiftTypesController $controller */
$controller = $this->app->make(ShiftTypesController::class);
$controller->setValidator(new Validator());
/** @var ShiftType $shifttype */
$shifttype = ShiftType::factory()->create();
$this->request = $this->request->withParsedBody([
'id' => '1',
'delete' => '1',
]);
$controller->save($this->request);
$this->assertEmpty(ShiftType::find($shifttype->id));
}
/**
* @covers \Engelsystem\Controllers\Admin\ShiftTypesController::delete
*/
public function testDelete(): void
{
/** @var EventDispatcher|MockObject $dispatcher */
$dispatcher = $this->createMock(EventDispatcher::class);
$this->app->instance('events.dispatcher', $dispatcher);
/** @var ShiftTypesController $controller */
$controller = $this->app->make(ShiftTypesController::class);
$controller->setValidator(new Validator());
/** @var ShiftType $shifttype */
$shifttype = ShiftType::factory()->create();
/** @var Shift $shift */
$shift = Shift::factory()->create(['shift_type_id' => $shifttype->id, 'start' => Carbon::create()->subHour()]);
/** @var User $user */
$user = User::factory()->create(['name' => 'foo', 'email' => 'lorem@ipsum']);
/** @var ShiftEntry $shiftEntry */
ShiftEntry::factory()->create(['shift_id' => $shift->id, 'user_id' => $user->id]);
$this->setExpects($this->redirect, 'to', ['/admin/shifttypes'], $this->response);
$dispatcher->expects($this->once())
->method('dispatch')
->willReturnCallback(function (string $event, array $data) use ($shifttype, $user) {
$this->assertEquals('shift.entry.deleting', $event);
$this->assertEquals($shifttype->name, $data['name']);
$this->assertEquals($user->id, $data['user']->id);
return [];
});
$this->request = $this->request->withParsedBody(['id' => 1, 'delete' => '1']);
$controller->delete($this->request);
$this->assertNull(ShiftType::find($shifttype->id));
$this->assertTrue($this->log->hasInfoThatContains('Deleted shift type'));
$this->assertHasNotification('shifttype.delete.success');
}
public function setUp(): void
{
parent::setUp();
$this->redirect = $this->createMock(Redirector::class);
$this->app->instance(Redirector::class, $this->redirect);
}
}