Commit a8bdaa51 authored by Jacob Priddy's avatar Jacob Priddy 👌
Browse files

Update group

parent 767417a6
......@@ -46,26 +46,21 @@ abstract class ApiController extends Controller
{
return response()->json(
array_merge(
$data,
[
$data, [
'status' => 'success',
'code' => $this->status,
'code' => $this->status,
]
),
$this->status
), $this->status
);
}
public function respondWithMessage(string $message): JsonResponse
{
return response()->json(
[
'message' => $message,
'status' => 'success',
'code' => $this->status,
],
$this->status
);
return response()->json([
'message' => $message,
'status' => 'success',
'code' => $this->status,
], $this->status);
}
/**
......@@ -74,13 +69,10 @@ abstract class ApiController extends Controller
*/
public function respondWithError(string $message): JsonResponse
{
return response()->json(
[
'status' => 'error',
'code' => $this->status,
'message' => $message,
],
$this->status
);
return response()->json([
'status' => 'error',
'code' => $this->status,
'message' => $message,
], $this->status);
}
}
......@@ -5,6 +5,8 @@ namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Source\Authorization\Permissions;
use Source\Exceptions\DeleteFailedException;
use Source\UseCases\Groups\UpdateGroup\APIPresenter as UpdateGroupAPIPresenter;
use Source\UseCases\Groups\UpdateGroup\UpdateGroupUseCase;
use Source\UseCases\Groups\GetGroup\APIPresenter as GetGroupAPIPresenter;
use Source\UseCases\Groups\GetGroup\GetGroupUseCase;
use Source\UseCases\Groups\DeleteGroup\DeleteGroupUseCase;
......@@ -96,4 +98,32 @@ class GroupsController extends ApiController
return $this->respondWithData($presenter->getViewModel());
}
/**
* @param \Source\UseCases\Groups\UpdateGroup\UpdateGroupUseCase $useCase
* @param string $groupId
* @return \Illuminate\Http\JsonResponse
* @throws \Illuminate\Validation\ValidationException
* @throws \Source\Exceptions\AuthorizationException
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function update(UpdateGroupUseCase $useCase, string $groupId): JsonResponse
{
$this->authorizer->protectAll([Permissions::MANAGE_GROUPS]);
$this->validate($this->request, [
'title' => 'required|string|max:255',
'description' => 'required|string',
]);
$presenter = new UpdateGroupAPIPresenter();
$useCase->update($groupId, $this->request->all(), $presenter);
if ($presenter->hasError()) {
return $this->respondWithError($presenter->getViewModel()['message']);
}
return $this->respondWithData($presenter->getViewModel());
}
}
......@@ -96,24 +96,25 @@ class UsersController extends ApiController
{
$this->authorizer->protectAll([Permissions::MANAGE_USERS]);
$this->validate(
$this->request,
[
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'display_name' => 'required|string|max:255',
'emplid' => 'nullable|string|max:7|min:6',
'email' => 'required|email|max:255',
'password' => 'nullable|string|max:255',
'doorcode' => 'nullable|string|numeric|digits_between:4,255',
'expires_at' => 'nullable|string|date|max:255',
]
);
$this->validate($this->request, [
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'display_name' => 'required|string|max:255',
'emplid' => 'nullable|string|max:7|min:6',
'email' => 'required|email|max:255',
'password' => 'nullable|string|max:255',
'doorcode' => 'nullable|string|numeric|digits_between:4,255',
'expires_at' => 'nullable|string|date|max:255',
]);
$presenter = new UpdateUserAPIPresenter();
$updateUser->update($userId, $this->request->all(), $presenter);
if ($presenter->hasError()) {
return $this->respondWithError($presenter->getViewModel()['message']);
}
return $this->respondWithData($presenter->getViewModel());
}
......
......@@ -18,6 +18,7 @@ use Source\UseCases\Users\UpdateUser\UpdateUserUseCaseServiceProvider;
use Source\UseCases\Users\GetAllUsers\GetAllUsersUseCaseServiceProvider;
use Source\UseCases\Groups\CreateGroup\CreateGroupUseCaseServiceProvider;
use Source\UseCases\Groups\DeleteGroup\DeleteGroupUseCaseServiceProvider;
use Source\UseCases\Groups\UpdateGroup\UpdateGroupUseCaseServiceProvider;
use Source\UseCases\Token\Authenticate\AuthenticateUseCaseServiceProvider;
use Source\UseCases\Groups\GetAllGroups\GetAllGroupsUseCaseServiceProvider;
use Source\UseCases\Doors\Authenticate\AuthenticateUseCaseServiceProvider as DoorAuthenticateUseCaseServiceProvider;
......@@ -53,6 +54,7 @@ class AppServiceProvider extends ServiceProvider
GetGroupUseCaseServiceProvider::class,
CreateGroupUseCaseServiceProvider::class,
DeleteGroupUseCaseServiceProvider::class,
UpdateGroupUseCaseServiceProvider::class,
GetAllGroupsUseCaseServiceProvider::class,
// Doors
......
<?php
namespace Source\UseCases\Groups\UpdateGroup;
use Source\UseCases\BasePresenter;
class APIPresenter extends BasePresenter implements Presenter
{
protected array $viewModel = [];
protected bool $error = false;
/** @inheritDoc */
public function present(ResponseModel $responseModel): void
{
$this->error = $responseModel->hasError();
if ($responseModel->hasError()) {
$this->viewModel['message'] = $responseModel->getError();
} else {
$this->viewModel['group'] = $this->formatGroup($responseModel->getGroup());
}
}
public function hasError(): bool
{
return $this->error;
}
/** @inheritDoc */
public function getViewModel(): array
{
return $this->viewModel;
}
}
<?php
namespace Source\UseCases\Groups\UpdateGroup;
interface Presenter
{
/**
* @param ResponseModel $responseModel
* @return void
*/
public function present(ResponseModel $responseModel): void;
/**
* @return array
*/
public function getViewModel(): array;
}
<?php
namespace Source\UseCases\Groups\UpdateGroup;
use Source\Entities\Group;
class ResponseModel
{
/**
* @var string
*/
protected string $error = '';
/**
* @var \Source\Entities\Group|null
*/
protected ?Group $group = null;
/**
* @return bool
*/
public function hasError(): bool
{
return $this->error;
}
/**
* @return string
*/
public function getError(): string
{
return $this->error;
}
/**
* @param string $error
*/
public function setError(string $error): void
{
$this->error = $error;
}
/**
* @return \Source\Entities\Group
*/
public function getGroup(): Group
{
return $this->group;
}
/**
* @param \Source\Entities\Group $group
*/
public function setGroup(Group $group): void
{
$this->group = $group;
}
}
<?php
namespace Source\UseCases\Groups\UpdateGroup;
use Source\Entities\Group;
use Source\Gateways\Groups\GroupsRepository;
use Source\Exceptions\EntityNotFoundException;
class UpdateGroup implements UpdateGroupUseCase
{
/**
* @var \Source\Gateways\Groups\GroupsRepository
*/
protected GroupsRepository $groups;
/**
* @param \Source\Gateways\Groups\GroupsRepository $groups
*/
public function __construct(GroupsRepository $groups)
{
$this->groups = $groups;
}
/**
* @inheritDoc
*/
public function update(string $groupId, array $attributes, Presenter $presenter): void
{
$group = $this->groups->get($groupId);
if (!$group) {
throw new EntityNotFoundException();
}
$newGroup = new Group(
$group->getId(),
$attributes['title'],
$attributes['description']
);
$response = new ResponseModel();
$returnedGroup = $this->groups->update($group->getId(), $newGroup);
if (!$returnedGroup) {
$response->setError('Unable to update group.');
} else {
$response->setGroup($returnedGroup);
}
$presenter->present($response);
}
}
<?php
namespace Source\UseCases\Groups\UpdateGroup;
interface UpdateGroupUseCase
{
/**
* Required attributes:
* title
* description
*
* @param string $groupId
* @param array $attributes
* @param \Source\UseCases\Groups\UpdateGroup\Presenter $presenter
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function update(string $groupId, array $attributes, Presenter $presenter): void;
}
<?php
namespace Source\UseCases\Groups\UpdateGroup;
use Source\Gateways\Groups\GroupsRepository;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
/**
* Service provider must be registered in AppServiceProvider
*/
class UpdateGroupUseCaseServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->bind(UpdateGroupUseCase::class, static function (Application $app) {
return new UpdateGroup($app->make(GroupsRepository::class));
});
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot(): void
{
}
/**
* @return array
*/
public function provides()
{
return [UpdateGroupUseCase::class];
}
}
......@@ -8,10 +8,12 @@ class APIPresenter extends BasePresenter implements Presenter
{
protected array $viewModel = [];
protected bool $error = false;
/** @inheritDoc */
public function present(ResponseModel $responseModel): void
{
$this->viewModel['error'] = $responseModel->hasError();
$this->error = $responseModel->hasError();
if ($responseModel->hasError()) {
$this->viewModel['message'] = $responseModel->getError();
} else {
......@@ -19,6 +21,14 @@ class APIPresenter extends BasePresenter implements Presenter
}
}
/**
* @return bool
*/
public function hasError(): bool
{
return $this->error;
}
/** @inheritDoc */
public function getViewModel(): array
{
......
......@@ -8,17 +8,23 @@ use Source\Gateways\Groups\GroupsRepository;
class InMemoryGroupsRepositoryStub implements GroupsRepository
{
protected ?Group $user;
protected ?Group $group;
public function setGroupToReturnOnGet(Group $group): void
{
$this->group = $group;
}
/**
* @param string $userId
* @param string $groupId
* @return Group|null
*/
public function get(string $userId): ?Group
public function get(string $groupId): ?Group
{
if ($this->user) {
return $this->user;
if ($this->group) {
return $this->group;
}
return null;
}
......@@ -31,38 +37,38 @@ class InMemoryGroupsRepositoryStub implements GroupsRepository
}
/**
* @param Group $user
* @param Group $group
* @return Group|null
*/
public function create(Group $user): ?Group
public function create(Group $group): ?Group
{
return null;
}
/**
* @param string $userId
* @param Group $user
* @param string $groupId
* @param Group $group
* @return Group|null
*/
public function update(string $userId, Group $user): ?Group
public function update(string $groupId, Group $group): ?Group
{
return null;
}
/**
* @param string $userId
* @param string $groupId
* @return bool
*/
public function delete(string $userId): bool
public function delete(string $groupId): bool
{
return false;
}
/**
* @param string $userId
* @param string $groupId
* @return bool
*/
public function exists(string $userId): bool
public function exists(string $groupId): bool
{
return true;
}
......
<?php
namespace Tests\Feature\Api\Groups;
use Source\Entities\Group;
use Source\Gateways\Groups\GroupsRepository;
use Source\Exceptions\EntityNotFoundException;
use Illuminate\Foundation\Testing\TestResponse;
use Tests\Feature\AuthenticatesWithApplicationTestCase;
class UpdateGroupApiTest extends AuthenticatesWithApplicationTestCase
{
/**
* @var \Illuminate\Foundation\Testing\TestResponse
*/
protected TestResponse $response;
/**
* @var mixed|\Source\Gateways\Groups\GroupsRepository
*/
protected GroupsRepository $groups;
public function setUp(): void
{
parent::setUp();
$this->groups = $this->app->make(GroupsRepository::class);
}
/**
* @param string $groupId
* @param array $data
*/
protected function handleTest(string $groupId, array $data): void
{
$this->response = $this->putJson('/groups/' . $groupId,
array_merge(['api_token' => $this->authToken], $data)
);
}
/**
* @test
*/
public function it_denies_unauthorized(): void
{
$this->handleTest('radlfj', []);
$this->response->assertStatus(401);
}
/**
* @test
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function it_protects_the_route(): void
{
$this->authorize(false);
$this->handleTest('group', []);
$this->response->assertStatus(403);
}
public function invalidGroupProvider(): array
{
$group = new Group(0, 'first', 'last');
return [
// Missing one of the required
[
[
'title' => 'title',
],
['description' => ['The description field is required.']],
],
[
[
'description' => 'description',
],
['title' => ['The title field is required.']],
],
];
}
/**
* @test
* @param array $data
* @param array $message
* @dataProvider invalidGroupProvider
* @throws EntityNotFoundException
*/
public function it_tests_the_validation_rules(array $data, array $message): void
{
$this->authenticate();
$this->handleTest('69', $data);
$this->response->assertJsonFragment($message);
}
/**
* @test
* @throws EntityNotFoundException
*/
public function it_updates_a_group(): void
{