Added shirt edit view
parent
5667fc2326
commit
5c90a1ef37
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
|
||||
class AddShirtEditPermissions extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (!$this->schema->hasTable('GroupPrivileges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('Privileges')
|
||||
->insert(['name' => 'user.edit.shirt', 'desc' => 'Edit user shirts']);
|
||||
|
||||
$shiftCoordinator = -40;
|
||||
$shirtManager = -30;
|
||||
|
||||
$userEditShirt = $db->table('Privileges')
|
||||
->where('name', 'user.edit.shirt')
|
||||
->get(['id'])->first();
|
||||
$adminArrive = $db->table('Privileges')
|
||||
->where('name', 'admin_arrive')
|
||||
->get(['id'])->first();
|
||||
|
||||
$db->table('GroupPrivileges')
|
||||
->insertOrIgnore([
|
||||
['group_id' => $shiftCoordinator, 'privilege_id' => $userEditShirt->id],
|
||||
['group_id' => $shirtManager, 'privilege_id' => $userEditShirt->id],
|
||||
['group_id' => $shirtManager, 'privilege_id' => $adminArrive->id],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
if (!$this->schema->hasTable('GroupPrivileges')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db = $this->schema->getConnection();
|
||||
$db->table('Privileges')
|
||||
->where(['name' => 'user.edit.shirt'])
|
||||
->delete();
|
||||
|
||||
$shirtManager = -30;
|
||||
$adminArrive = $db->table('Privileges')
|
||||
->where('name', 'admin_arrive')
|
||||
->get(['id'])->first();
|
||||
|
||||
$db->table('GroupPrivileges')
|
||||
->where(['group_id' => $shirtManager, 'privilege_id' => $adminArrive->id])
|
||||
->delete();
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
{% extends "layouts/app.twig" %}
|
||||
{% import 'macros/base.twig' as m %}
|
||||
{% import 'macros/form.twig' as f %}
|
||||
|
||||
{% block title %}{{ __('user.edit.shirt') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<h1>{{ block('title') }}</h1>
|
||||
|
||||
{% include 'layouts/parts/messages.twig' %}
|
||||
|
||||
<form method="post">
|
||||
{{ csrf() }}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
{{ f.select('shirt_size', config('tshirt_sizes'), __('user.shirt_size'), userdata.personalData.shirt_size) }}
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
{% if has_permission_to('admin_arrive') %}
|
||||
{{ f.switch('arrived', __('user.arrived'), userdata.state.arrived) }}
|
||||
{% endif %}
|
||||
|
||||
{% if userdata.state.force_active %}
|
||||
{{ f.switch('force_active', __('user.force_active'), true, {'disabled': true}) }}
|
||||
{% endif %}
|
||||
|
||||
{{ f.switch('active', __('user.active'), userdata.state.active) }}
|
||||
|
||||
{{ f.switch('got_shirt', __('user.got_shirt'), userdata.state.got_shirt) }}
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
{{ f.submit(__('form.save')) }}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Controllers\Admin;
|
||||
|
||||
use Engelsystem\Config\Config;
|
||||
use Engelsystem\Controllers\BaseController;
|
||||
use Engelsystem\Controllers\HasUserNotifications;
|
||||
use Engelsystem\Helpers\Authenticator;
|
||||
use Engelsystem\Http\Redirector;
|
||||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class UserShirtController extends BaseController
|
||||
{
|
||||
use HasUserNotifications;
|
||||
|
||||
/** @var Authenticator */
|
||||
protected $auth;
|
||||
|
||||
/** @var Config */
|
||||
protected $config;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
protected $log;
|
||||
|
||||
/** @var Redirector */
|
||||
protected $redirect;
|
||||
|
||||
/** @var Response */
|
||||
protected $response;
|
||||
|
||||
/** @var User */
|
||||
protected $user;
|
||||
|
||||
/** @var array */
|
||||
protected $permissions = [
|
||||
'editShirt' => 'user.edit.shirt',
|
||||
'saveShirt' => 'user.edit.shirt',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param Authenticator $auth
|
||||
* @param Config $config
|
||||
* @param LoggerInterface $log
|
||||
* @param Redirector $redirector
|
||||
* @param Response $response
|
||||
* @param User $user
|
||||
*/
|
||||
public function __construct(
|
||||
Authenticator $auth,
|
||||
Config $config,
|
||||
LoggerInterface $log,
|
||||
Redirector $redirector,
|
||||
Response $response,
|
||||
User $user
|
||||
) {
|
||||
$this->auth = $auth;
|
||||
$this->config = $config;
|
||||
$this->log = $log;
|
||||
$this->redirect = $redirector;
|
||||
$this->response = $response;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function editShirt(Request $request): Response
|
||||
{
|
||||
$id = $request->getAttribute('id');
|
||||
$user = $this->user->findOrFail($id);
|
||||
|
||||
return $this->response->withView(
|
||||
'admin/user/edit-shirt.twig',
|
||||
['userdata' => $user] + $this->getNotifications()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function saveShirt(Request $request): Response
|
||||
{
|
||||
$id = $request->getAttribute('id');
|
||||
/** @var User $user */
|
||||
$user = $this->user->findOrFail($id);
|
||||
|
||||
$data = $this->validate($request, [
|
||||
'shirt_size' => 'required',
|
||||
'arrived' => 'optional|checked',
|
||||
'active' => 'optional|checked',
|
||||
'got_shirt' => 'optional|checked',
|
||||
]);
|
||||
|
||||
if (isset($this->config->get('tshirt_sizes')[$data['shirt_size']])) {
|
||||
$user->personalData->shirt_size = $data['shirt_size'];
|
||||
$user->personalData->save();
|
||||
}
|
||||
|
||||
if ($this->auth->can('admin_arrive')) {
|
||||
$user->state->arrived = (bool)$data['arrived'];
|
||||
}
|
||||
|
||||
$user->state->active = (bool)$data['active'];
|
||||
$user->state->got_shirt = (bool)$data['got_shirt'];
|
||||
$user->state->save();
|
||||
|
||||
$this->log->info(
|
||||
'Updated user shirt state "{user}" ({id}): {size}, arrived: {arrived}, got shirt: {got_shirt}',
|
||||
[
|
||||
'id' => $user->id,
|
||||
'user' => $user->name,
|
||||
'size' => $user->personalData->shirt_size,
|
||||
'arrived' => $user->state->arrived,
|
||||
'got_shirt' => $user->state->got_shirt
|
||||
]
|
||||
);
|
||||
|
||||
$this->addNotification('user.edit.success');
|
||||
|
||||
return $this->redirect->back();
|
||||
}
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Controllers\Admin;
|
||||
|
||||
use Engelsystem\Controllers\Admin\UserShirtController;
|
||||
use Engelsystem\Helpers\Authenticator;
|
||||
use Engelsystem\Http\Redirector;
|
||||
use Engelsystem\Http\Validation\Validator;
|
||||
use Engelsystem\Models\User\PersonalData;
|
||||
use Engelsystem\Models\User\State;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Test\Unit\Controllers\ControllerTest;
|
||||
use Engelsystem\Test\Unit\HasDatabase;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class UserShirtControllerTest extends ControllerTest
|
||||
{
|
||||
use HasDatabase;
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\Admin\UserShirtController::editShirt
|
||||
* @covers \Engelsystem\Controllers\Admin\UserShirtController::__construct
|
||||
*/
|
||||
public function testIndex()
|
||||
{
|
||||
$request = $this->request->withAttribute('id', 1);
|
||||
/** @var Authenticator|MockObject $auth */
|
||||
$auth = $this->createMock(Authenticator::class);
|
||||
/** @var Redirector|MockObject $redirector */
|
||||
$redirector = $this->createMock(Redirector::class);
|
||||
$user = new User();
|
||||
User::factory()->create();
|
||||
|
||||
$this->setExpects($this->response, 'withView', ['admin/user/edit-shirt.twig'], $this->response);
|
||||
|
||||
$controller = new UserShirtController($auth, $this->config, $this->log, $redirector, $this->response, $user);
|
||||
|
||||
$controller->editShirt($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\Admin\UserShirtController::editShirt
|
||||
*/
|
||||
public function testIndexUserNotFound()
|
||||
{
|
||||
/** @var Authenticator|MockObject $auth */
|
||||
$auth = $this->createMock(Authenticator::class);
|
||||
/** @var Redirector|MockObject $redirector */
|
||||
$redirector = $this->createMock(Redirector::class);
|
||||
$user = new User();
|
||||
|
||||
$controller = new UserShirtController($auth, $this->config, $this->log, $redirector, $this->response, $user);
|
||||
|
||||
$this->expectException(ModelNotFoundException::class);
|
||||
$controller->editShirt($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\Admin\UserShirtController::saveShirt
|
||||
*/
|
||||
public function testSaveShirt()
|
||||
{
|
||||
$request = $this->request
|
||||
->withAttribute('id', 1)
|
||||
->withParsedBody([
|
||||
'shirt_size' => 'S',
|
||||
]);
|
||||
/** @var Authenticator|MockObject $auth */
|
||||
$auth = $this->createMock(Authenticator::class);
|
||||
$this->config->set('tshirt_sizes', ['S' => 'Small']);
|
||||
/** @var Redirector|MockObject $redirector */
|
||||
$redirector = $this->createMock(Redirector::class);
|
||||
User::factory()
|
||||
->has(State::factory())
|
||||
->has(PersonalData::factory())
|
||||
->create();
|
||||
|
||||
$auth
|
||||
->expects($this->exactly(4))
|
||||
->method('can')
|
||||
->with('admin_arrive')
|
||||
->willReturnOnConsecutiveCalls(true, true, true, false);
|
||||
$this->setExpects($redirector, 'back', null, $this->response, $this->exactly(4));
|
||||
|
||||
$controller = new UserShirtController(
|
||||
$auth,
|
||||
$this->config,
|
||||
$this->log,
|
||||
$redirector,
|
||||
$this->response,
|
||||
new User()
|
||||
);
|
||||
$controller->setValidator(new Validator());
|
||||
|
||||
// Set shirt size
|
||||
$controller->saveShirt($request);
|
||||
|
||||
$this->assertHasNotification('user.edit.success');
|
||||
$this->assertTrue($this->log->hasInfoThatContains('Updated user shirt state'));
|
||||
|
||||
$user = User::find(1);
|
||||
$this->assertEquals('S', $user->personalData->shirt_size);
|
||||
$this->assertFalse($user->state->arrived);
|
||||
$this->assertFalse($user->state->active);
|
||||
$this->assertFalse($user->state->got_shirt);
|
||||
|
||||
// Set active, arrived and got_shirt
|
||||
$request = $request
|
||||
->withParsedBody([
|
||||
'shirt_size' => 'S',
|
||||
'arrived' => '1',
|
||||
'active' => '1',
|
||||
'got_shirt' => '1',
|
||||
]);
|
||||
|
||||
$controller->saveShirt($request);
|
||||
|
||||
$user = User::find(1);
|
||||
$this->assertTrue($user->state->active);
|
||||
$this->assertTrue($user->state->arrived);
|
||||
$this->assertTrue($user->state->got_shirt);
|
||||
|
||||
// Shirt size not available
|
||||
$request = $request
|
||||
->withParsedBody([
|
||||
'shirt_size' => 'L',
|
||||
]);
|
||||
|
||||
$controller->saveShirt($request);
|
||||
$user = User::find(1);
|
||||
$this->assertEquals('S', $user->personalData->shirt_size);
|
||||
|
||||
// Not allowed changing arrived
|
||||
$request = $request
|
||||
->withParsedBody([
|
||||
'shirt_size' => 'S',
|
||||
'arrived' => '1',
|
||||
]);
|
||||
|
||||
$this->assertFalse($user->state->arrived);
|
||||
$controller->saveShirt($request);
|
||||
$user = User::find(1);
|
||||
$this->assertFalse($user->state->arrived);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\Admin\UserShirtController::saveShirt
|
||||
*/
|
||||
public function testSaveShirtUserNotFound()
|
||||
{
|
||||
/** @var Authenticator|MockObject $auth */
|
||||
$auth = $this->createMock(Authenticator::class);
|
||||
/** @var Redirector|MockObject $redirector */
|
||||
$redirector = $this->createMock(Redirector::class);
|
||||
$user = new User();
|
||||
|
||||
$controller = new UserShirtController($auth, $this->config, $this->log, $redirector, $this->response, $user);
|
||||
|
||||
$this->expectException(ModelNotFoundException::class);
|
||||
$controller->editShirt($this->request);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue