diff --git a/resources/views/admin/user/edit-shirt.twig b/resources/views/admin/user/edit-shirt.twig index 37705b01..ab3da7a0 100644 --- a/resources/views/admin/user/edit-shirt.twig +++ b/resources/views/admin/user/edit-shirt.twig @@ -20,6 +20,9 @@
{{ f.select('shirt_size', __('user.shirt_size'), config('tshirt_sizes'), { 'selected': userdata.personalData.shirt_size, + 'required': true, + 'required_icon': true, + 'default_option': __('Please select...'), }) }}
{% endif %} diff --git a/resources/views/pages/settings/profile.twig b/resources/views/pages/settings/profile.twig index 83f7b470..b6db1a70 100644 --- a/resources/views/pages/settings/profile.twig +++ b/resources/views/pages/settings/profile.twig @@ -143,6 +143,7 @@ 'selected': user.personalData.shirt_size, 'required': true, 'required_icon': true, + 'default_option': __('Please select...'), }) }} {% endif %} diff --git a/src/Controllers/Admin/UserShirtController.php b/src/Controllers/Admin/UserShirtController.php index 807a607f..d213b0bc 100644 --- a/src/Controllers/Admin/UserShirtController.php +++ b/src/Controllers/Admin/UserShirtController.php @@ -58,13 +58,13 @@ class UserShirtController extends BaseController $user = $this->user->findOrFail($userId); $data = $this->validate($request, [ - 'shirt_size' => $shirtEnabled ? 'required' : 'optional', + 'shirt_size' => ($shirtEnabled ? 'required' : 'optional') . '|shirt_size', 'arrived' => 'optional|checked', 'active' => 'optional|checked', 'got_shirt' => 'optional|checked', ]); - if ($shirtEnabled && isset($this->config->get('tshirt_sizes')[$data['shirt_size']])) { + if ($shirtEnabled) { $user->personalData->shirt_size = $data['shirt_size']; $user->personalData->save(); } diff --git a/src/Controllers/SettingsController.php b/src/Controllers/SettingsController.php index 6e1ec4e7..3c9dd5bb 100644 --- a/src/Controllers/SettingsController.php +++ b/src/Controllers/SettingsController.php @@ -296,7 +296,7 @@ class SettingsController extends BaseController $rules['planned_departure_date'] = 'optional|date:Y-m-d'; } if ($goodie_tshirt) { - $rules['shirt_size'] = 'required'; + $rules['shirt_size'] = 'required|shirt_size'; } return $rules; } diff --git a/src/Http/Validation/Rules/ShirtSize.php b/src/Http/Validation/Rules/ShirtSize.php new file mode 100644 index 00000000..325045b5 --- /dev/null +++ b/src/Http/Validation/Rules/ShirtSize.php @@ -0,0 +1,18 @@ +create(); $auth - ->expects($this->exactly(6)) + ->expects($this->exactly(5)) ->method('can') ->with('admin_arrive') - ->willReturnOnConsecutiveCalls(true, true, true, false, false, true); - $this->setExpects($redirector, 'back', null, $this->response, $this->exactly(6)); + ->willReturnOnConsecutiveCalls(true, true, false, false, true); + $this->setExpects($redirector, 'back', null, $this->response, $this->exactly(5)); $controller = new UserShirtController( $auth, @@ -131,7 +133,12 @@ class UserShirtControllerTest extends ControllerTest 'shirt_size' => 'L', ]); - $controller->saveShirt($request); + try { + $controller->saveShirt($request); + self::fail('Expected exception was not raised'); + } catch (ValidationException $e) { + // ignore + } $user = User::find(1); $this->assertEquals('S', $user->personalData->shirt_size); @@ -142,6 +149,8 @@ class UserShirtControllerTest extends ControllerTest 'arrived' => '1', ]); + $user->state->arrived = false; + $user->state->save(); $this->assertFalse($user->state->arrived); $controller->saveShirt($request); $user = User::find(1); diff --git a/tests/Unit/Http/Validation/Rules/ShirtSizeTest.php b/tests/Unit/Http/Validation/Rules/ShirtSizeTest.php new file mode 100644 index 00000000..9186d31d --- /dev/null +++ b/tests/Unit/Http/Validation/Rules/ShirtSizeTest.php @@ -0,0 +1,49 @@ +createAndSetUpAppWithConfig([]); + $app->get('config')->set('tshirt_sizes', [ + 'S' => 'Small Straight-Cut', + 'M' => 'Medium Straight-Cut', + ]); + $this->subject = new ShirtSize(); + } + + /** + * @return array + */ + public function provideTestValidateData(): array + { + $data = [ + 'empty string' => ['', false], + 'null' => [null, false], + '0' => [0, false], + '"S" (known value)' => ['S', true], + '"M" (known value)' => ['M', true], + '"L" (unknown value)' => ['L', false], + ]; + + return $data; + } + + /** + * @covers \Engelsystem\Http\Validation\Rules\ShirtSize::__construct + * @dataProvider provideTestValidateData + */ + public function testValidate(mixed $value, bool $expectedValid): void + { + self::assertSame($expectedValid, $this->subject->validate($value)); + } +} diff --git a/tests/Unit/Http/Validation/Rules/UsernameTest.php b/tests/Unit/Http/Validation/Rules/UsernameTest.php index 47b9f84b..705d9745 100644 --- a/tests/Unit/Http/Validation/Rules/UsernameTest.php +++ b/tests/Unit/Http/Validation/Rules/UsernameTest.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace Engelsystem\Test\Unit\Http\Validation\Rules; -use Engelsystem\Application; use Engelsystem\Config\Config; use Engelsystem\Http\Validation\Rules\Username; use Engelsystem\Test\Unit\ServiceProviderTest; @@ -20,11 +19,8 @@ class UsernameTest extends ServiceProviderTest { $this->subject = new Username(); - $app = $this->getApp([]); - $this->config = new Config([]); - $app->instance('config', $this->config); - $app->get('config'); - Application::setInstance($app); + $app = $this->createAndSetUpAppWithConfig([]); + $this->config = $app->get('config'); // load "username_regex" from the default config $defaultConfig = include __DIR__ . '/../../../../../config/config.default.php'; diff --git a/tests/Unit/ServiceProviderTest.php b/tests/Unit/ServiceProviderTest.php index cd9c5afe..8af9ab79 100644 --- a/tests/Unit/ServiceProviderTest.php +++ b/tests/Unit/ServiceProviderTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Engelsystem\Test\Unit; use Engelsystem\Application; +use Engelsystem\Config\Config; use PHPUnit\Framework\MockObject\MockObject; abstract class ServiceProviderTest extends TestCase @@ -15,4 +16,18 @@ abstract class ServiceProviderTest extends TestCase ->onlyMethods($methods) ->getMock(); } + + /** + * Creates an Application instance with a Config set as 'config'. + * Also sets up the instance as global Application instance. + * + * @param string[] $methods Names of the methods to mock + */ + protected function createAndSetUpAppWithConfig(array $methods = ['make', 'instance']): Application|MockObject + { + $app = $this->getApp($methods); + $app->instance('config', new Config([])); + Application::setInstance($app); + return $app; + } }