Commit 446b906b authored by Jacob Priddy's avatar Jacob Priddy 👌
Browse files

Merge branch '6-create-get-groups-for-user-route' into 'master'

Resolve "create get groups for user route"

Closes #6

See merge request kretschmar/doorcode!15
parents 05ee55b8 22f5ae90
Pipeline #2418 passed with stages
in 1 minute and 52 seconds
......@@ -11,6 +11,7 @@ use Source\UseCases\Users\CreateUser\CreateUserUseCase;
use Source\UseCases\Users\DeleteUser\DeleteUserUseCase;
use Source\UseCases\Users\UpdateUser\UpdateUserUseCase;
use Source\UseCases\Users\GetAllUsers\GetAllUsersUseCase;
use Source\UseCases\GroupUser\GetUserGroups\GetUserGroupsUseCase;
use Source\UseCases\GroupUser\AddUserToGroup\AddUserToGroupUseCase;
use Source\UseCases\Users\GetUser\APIPresenter as GetUserAPIPresenter;
use Source\UseCases\Users\GetAllUsers\APIPresenter as AllUsersAPIPresenter;
......@@ -18,6 +19,7 @@ use Source\UseCases\Users\CreateUser\APIPresenter as CreateUserAPIPresenter;
use Source\UseCases\Users\DeleteUser\APIPresenter as DeleteUserAPIPresenter;
use Source\UseCases\Users\UpdateUser\APIPresenter as UpdateUserAPIPresenter;
use Source\UseCases\GroupUser\RemoveUserFromGroup\RemoveUserFromGroupUseCase;
use Source\UseCases\GroupUser\GetUserGroups\APIPresenter as GetUserGroupsAPIPresenter;
use Source\UseCases\GroupUser\AddUserToGroup\APIPresenter as AddUserToGroupAPIPresenter;
use Source\UseCases\GroupUser\RemoveUserFromGroup\APIPresenter as RemoveUserFromGroupAPIPresenter;
......@@ -182,4 +184,22 @@ class UsersController extends ApiController
return $this->respondWithMessage($presenter->getViewModel()['message']);
}
/**
* @param \Source\UseCases\GroupUser\GetUserGroups\GetUserGroupsUseCase $useCase
* @param string $userId
* @return \Illuminate\Http\JsonResponse
* @throws \Source\Exceptions\AuthorizationException
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function getGroupsForUser(GetUserGroupsUseCase $useCase, string $userId): JsonResponse
{
$this->authorizer->protectAll([Permissions::MANAGE_USERS]);
$presenter = new GetUserGroupsAPIPresenter();
$useCase->getGroupsForUser($userId, $presenter);
return $this->respondWithData($presenter->getViewModel());
}
}
......@@ -21,6 +21,7 @@ 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\GroupUser\GetUserGroups\GetUserGroupsUseCaseServiceProvider;
use Source\UseCases\GroupUser\AddUserToGroup\AddUserToGroupUseCaseServiceProvider;
use Source\UseCases\GroupUser\RemoveUserFromGroup\RemoveUserFromGroupUseCaseServiceProvider;
use Source\UseCases\Doors\Authenticate\AuthenticateUseCaseServiceProvider as DoorAuthenticateUseCaseServiceProvider;
......@@ -60,6 +61,7 @@ class AppServiceProvider extends ServiceProvider
GetAllGroupsUseCaseServiceProvider::class,
// GroupUser
GetUserGroupsUseCaseServiceProvider::class,
AddUserToGroupUseCaseServiceProvider::class,
RemoveUserFromGroupUseCaseServiceProvider::class,
......
......@@ -30,6 +30,8 @@ Route::group(['middleware' => 'auth:api'], static function () {
Route::put('{userId}', [UsersController::class, 'update']);
Route::delete('{userId}', [UsersController::class, 'delete']);
Route::get('{userId}/groups', [UsersController::class, 'getGroupsForUser']);
Route::post('{userId}/group/{groupId}', [UsersController::class, 'addUserToGroup']);
Route::delete('{userId}/group/{groupId}', [UsersController::class, 'removeUserFromGroup']);
});
......
......@@ -5,6 +5,7 @@ namespace Source\Gateways\GroupUser;
use Source\Gateways\Users\UsersRepository;
use Source\Gateways\Groups\GroupsRepository;
use Source\Exceptions\EntityNotFoundException;
class InMemoryGroupUserRepository implements GroupUserRepository
{
......@@ -36,6 +37,10 @@ class InMemoryGroupUserRepository implements GroupUserRepository
*/
public function getGroupsForUser(string $userId): array
{
if (!$this->users->exists($userId)) {
throw new EntityNotFoundException();
}
if (!isset($this->groupMap[$userId])) {
return [];
}
......
......@@ -65,9 +65,9 @@ abstract class BasePresenter
'display_name' => $user->getDisplayName(),
'emplid' => $user->getEmplid(),
'email' => $user->getEmail(),
'expires_at' => $this->formatDate($user->getExpiresAt()),
'created_at' => $this->formatDate($user->getCreatedAt()),
'updated_at' => $this->formatDate($user->getUpdatedAt()),
'expires_at' => $this->formatDateTime($user->getExpiresAt()),
'created_at' => $this->formatDateTime($user->getCreatedAt()),
'updated_at' => $this->formatDateTime($user->getUpdatedAt()),
];
}
......
<?php
namespace Source\UseCases\GroupUser\GetUserGroups;
use Source\Entities\Group;
use Source\UseCases\BasePresenter;
class APIPresenter extends BasePresenter implements Presenter
{
protected array $viewModel = [];
/** @inheritDoc */
public function present(ResponseModel $responseModel): void
{
$this->viewModel['groups'] = array_map(static function (Group $group) {
return [
'id' => $group->getId(),
'title' => $group->getTitle(),
'description' => $group->getDescription(),
];
}, $responseModel->getGroups());
}
/** @inheritDoc */
public function getViewModel(): array
{
return $this->viewModel;
}
}
<?php
namespace Source\UseCases\GroupUser\GetUserGroups;
use Source\Gateways\GroupUser\GroupUserRepository;
class GetUserGroups implements GetUserGroupsUseCase
{
/**
* @var \Source\Gateways\GroupUser\GroupUserRepository
*/
protected GroupUserRepository $repository;
public function __construct(GroupUserRepository $repository)
{
$this->repository = $repository;
}
/**
* @inheritDoc
*/
public function getGroupsForUser(string $userId, Presenter $presenter): void
{
$groups = $this->repository->getGroupsForUser($userId);
$response = new ResponseModel($groups);
$presenter->present($response);
}
}
<?php
namespace Source\UseCases\GroupUser\GetUserGroups;
interface GetUserGroupsUseCase
{
/**
* @param string $userId
* @param \Source\UseCases\GroupUser\GetUserGroups\Presenter $presenter
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function getGroupsForUser(string $userId, Presenter $presenter): void;
}
<?php
namespace Source\UseCases\GroupUser\GetUserGroups;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Foundation\Application;
use Source\Gateways\GroupUser\GroupUserRepository;
use Illuminate\Contracts\Support\DeferrableProvider;
/**
* Service provider must be registered in AppServiceProvider
*/
class GetUserGroupsUseCaseServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->bind(GetUserGroupsUseCase::class, static function (Application $app) {
return new GetUserGroups($app->make(GroupUserRepository::class));
});
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot(): void
{
}
/**
* @return array
*/
public function provides()
{
return [GetUserGroupsUseCase::class];
}
}
<?php
namespace Source\UseCases\GroupUser\GetUserGroups;
interface Presenter
{
/**
* @param ResponseModel $responseModel
* @return void
*/
public function present(ResponseModel $responseModel): void;
/**
* @return array
*/
public function getViewModel(): array;
}
<?php
namespace Source\UseCases\GroupUser\GetUserGroups;
class ResponseModel
{
/**
* @var \Source\Entities\Group[]
*/
protected array $groups;
public function __construct(array $groups)
{
$this->groups = $groups;
}
/**
* @return \Source\Entities\Group[]
*/
public function getGroups(): array
{
return $this->groups;
}
}
<?php
namespace Tests\Feature\Api\Users;
use Source\Entities\User;
use Source\Entities\Group;
use Source\Gateways\Groups\GroupsRepository;
use Illuminate\Foundation\Testing\TestResponse;
use Source\Gateways\GroupUser\GroupUserRepository;
use Tests\Feature\AuthenticatesWithApplicationTestCase;
class GetGroupsForUserApiTest extends AuthenticatesWithApplicationTestCase
{
protected TestResponse $response;
protected GroupsRepository $groups;
protected GroupUserRepository $repository;
public function setUp(): void
{
parent::setUp();
$this->groups = $this->app->make(GroupsRepository::class);
$this->repository = $this->app->make(GroupUserRepository::class);
}
public function handleTest(string $userId): void
{
$this->response = $this->getJson("/users/$userId/groups?api_token={$this->authToken}");
}
/**
* @test
*/
public function it_denies_unauthorized(): void
{
$this->handleTest('uid');
$this->response->assertStatus(401);
}
/**
* @test
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function it_protects_the_route(): void
{
$this->authorize(false);
$this->handleTest('uid');
$this->response->assertStatus(403);
}
/**
* @test
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function it_adds_a_group_to_a_user(): void
{
$this->authenticate();
$user = $this->usersRepository->create(new User(0, '', '', '', '', '', '', ''));
$group = $this->groups->create(new Group(0, '', ''));
$this->repository->addUserToGroup($user->getId(), $group->getId());
$this->handleTest($user->getId());
$this->response->assertStatus(200);
$this->assertCount(1, $this->response->json('groups'));
}
}
<?php
namespace Tests\Unit\Source\UseCases\GroupUser\GetUserGroups;
use Source\UseCases\GroupUser\GetUserGroups\Presenter;
use Source\UseCases\GroupUser\GetUserGroups\ResponseModel;
class PresenterStub implements Presenter
{
public ResponseModel $response;
protected bool $presenterCalled = false;
public function present(ResponseModel $responseModel): void
{
$this->presenterCalled = true;
$this->response = $responseModel;
}
public function wasPresenterCalled(): bool
{
return $this->presenterCalled;
}
public function getViewModel(): array
{
return [];
}
}
<?php
namespace Tests\Unit\Source\UseCases\GroupUser\GetUserGroups;
use Source\Entities\Group;
use PHPUnit\Framework\TestCase;
use Source\UseCases\GroupUser\GetUserGroups\APIPresenter;
use Source\UseCases\GroupUser\GetUserGroups\ResponseModel;
class PresenterTest extends TestCase
{
protected APIPresenter $presenter;
protected ResponseModel $model;
protected array $response;
public function setUp(): void
{
parent::setUp();
$this->presenter = new APIPresenter();
}
/**
* @param \Source\Entities\Group[] $groups
*/
public function handleTest(array $groups): void
{
$this->model = new ResponseModel($groups);
$this->presenter->present($this->model);
$this->response = $this->presenter->getViewModel();
}
/**
* @test
*/
public function it_formats_groups_when_empty(): void
{
$this->handleTest([]);
$this->assertEquals(['groups' => []], $this->response);
}
/** @test */
public function it_formats_a_group(): void
{
$groups = [
new Group(1, 't1', 'd1'),
new Group(2, 't2', 'd2'),
];
$this->handleTest($groups);
$this->assertCount(2, $this->response['groups']);
$this->assertEquals([
'groups' => [
[
'id' => 1,
'title' => 't1',
'description' => 'd1',
],
[
'id' => 2,
'title' => 't2',
'description' => 'd2',
],
]], $this->response);
}
}
<?php
namespace Tests\Unit\Source\UseCases\GroupUser\GetUserGroups;
use Source\Entities\User;
use Source\Entities\Group;
use PHPUnit\Framework\TestCase;
use Source\Gateways\Users\UsersRepository;
use Source\Gateways\Groups\GroupsRepository;
use Source\Exceptions\EntityNotFoundException;
use Source\Gateways\GroupUser\GroupUserRepository;
use Source\Gateways\Users\InMemoryUsersRepository;
use Source\Gateways\Groups\InMemoryGroupsRepository;
use Source\Gateways\GroupUser\InMemoryGroupUserRepository;
use Source\UseCases\GroupUser\GetUserGroups\GetUserGroups;
use Source\UseCases\GroupUser\GetUserGroups\ResponseModel;
class UseCaseTest extends TestCase
{
protected ResponseModel $response;
protected PresenterStub $presenter;
protected GroupUserRepository $repository;
protected GetUserGroups $useCase;
protected UsersRepository $users;
protected GroupsRepository $groups;
public function setUp(): void
{
parent::setUp();
$this->users = new InMemoryUsersRepository();
$this->groups = new InMemoryGroupsRepository();
$this->repository = new InMemoryGroupUserRepository($this->users, $this->groups);
$this->useCase = new GetUserGroups($this->repository);
$this->presenter = new PresenterStub();
}
/**
* @param string $userId
* @throws \Source\Exceptions\EntityNotFoundException
*/
protected function handleTest(string $userId): void
{
$this->useCase->getGroupsForUser($userId, $this->presenter);
$this->response = $this->presenter->response;
}
/**
* @test
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function it_cannot_get_groups_for_non_existient_user(): void
{
$this->expectException(EntityNotFoundException::class);
$this->handleTest('asdf');
}
/**
* @test
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function it_gets_groups_for_a_user(): void
{
$user = $this->users->create(new User(
0,
'',
'',
'',
'',
'',
'',
''
));
$group = $this->groups->create(new Group(
0,
'',
''
));
$this->repository->addUserToGroup($user->getId(), $group->getId());
$this->handleTest($user->getId());
$this->assertEquals([$group], $this->response->getGroups());
}
}
......@@ -60,7 +60,7 @@ class PresenterTest extends TestCase
'display_name' => 'display',
'emplid' => 'emplid',
'email' => 'email',
'expires_at' => 'Feb 2, 2020',
'expires_at' => '2020-02-02T00:00:00+00:00',
'created_at' => null,
'updated_at' => null,
],
......
......@@ -61,7 +61,7 @@ class PresenterTest extends TestCase
'display_name' => 'display',
'emplid' => 'emplid',
'email' => 'email',
'expires_at' => 'Feb 2, 2020',
'expires_at' => '2020-02-02T00:00:00+00:00',
'created_at' => null,
'updated_at' => null,
],
......
......@@ -61,7 +61,7 @@ class PresenterTest extends TestCase
'display_name' => 'display',
'emplid' => 'emplid',
'email' => 'email',
'expires_at' => 'Feb 2, 2020',
'expires_at' => '2020-02-02T00:00:00+00:00',
'created_at' => null,
'updated_at' => null,
],
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment