From c75dd862ade0fc7b0f863c5af8421276aee3ebf9 Mon Sep 17 00:00:00 2001 From: dakriy Date: Tue, 7 Apr 2020 12:20:44 -0700 Subject: [PATCH] Add door group database relations and remove get users and get doors off of usergroup gateway as it is repeated code --- src/web/backend/app/Door.php | 21 +++- src/web/backend/app/Group.php | 9 ++ .../app/Providers/AppServiceProvider.php | 2 + .../src/Authorization/ApiAuthorizer.php | 26 +++- .../AuthorizerServiceProvider.php | 9 +- .../DoorGroup/DatabaseDoorGroupRepository.php | 89 ++++++++++++++ .../DoorGroup/DoorGroupRepository.php | 35 ++++++ .../DoorGroupRepositoryServiceProvider.php | 61 ++++++++++ .../DoorGroup/InMemoryDoorGroupRepository.php | 112 ++++++++++++++++++ .../DoorGroup/LocalDoorGroupRepository.php | 30 +++++ .../Doors/DatabaseDoorsRepository.php | 8 ++ .../src/Gateways/Doors/DoorsRepository.php | 8 ++ .../Doors/InMemoryDoorsRepository.php | 8 ++ .../Gateways/Doors/LocalDoorsRepository.php | 33 +++++- .../GroupUser/DatabaseGroupUserRepository.php | 24 ---- .../GroupUser/GroupUserRepository.php | 12 -- .../GroupUser/InMemoryGroupUserRepository.php | 16 --- .../GroupUser/LocalGroupUserRepository.php | 18 +-- .../tests/Database/GroupUserDatabaseTest.php | 12 -- 19 files changed, 451 insertions(+), 82 deletions(-) create mode 100644 src/web/backend/src/Gateways/DoorGroup/DatabaseDoorGroupRepository.php create mode 100644 src/web/backend/src/Gateways/DoorGroup/DoorGroupRepository.php create mode 100644 src/web/backend/src/Gateways/DoorGroup/DoorGroupRepositoryServiceProvider.php create mode 100644 src/web/backend/src/Gateways/DoorGroup/InMemoryDoorGroupRepository.php create mode 100644 src/web/backend/src/Gateways/DoorGroup/LocalDoorGroupRepository.php diff --git a/src/web/backend/app/Door.php b/src/web/backend/app/Door.php index a613e599..65c0d7c1 100644 --- a/src/web/backend/app/Door.php +++ b/src/web/backend/app/Door.php @@ -3,10 +3,27 @@ namespace App; use Illuminate\Foundation\Auth\User as Authenticatable; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; class Door extends Authenticatable { - protected $fillable = ['id', 'name', 'location', 'created_at', 'updated_at']; + protected $fillable = ['*']; - protected $guarded = []; + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + */ + public function groups(): BelongsToMany + { + return $this->belongsToMany(Group::class); + } + + public static function boot() + { + parent::boot(); + + static::deleting(static function (Door $door) { + // Detach all groups + $door->groups()->detach(); + }); + } } diff --git a/src/web/backend/app/Group.php b/src/web/backend/app/Group.php index 4a95a2a2..11a2dd6d 100644 --- a/src/web/backend/app/Group.php +++ b/src/web/backend/app/Group.php @@ -16,12 +16,21 @@ class Group extends Model return $this->belongsToMany(User::class); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + */ + public function doors(): BelongsToMany + { + return $this->belongsToMany(Door::class); + } + public static function boot() { parent::boot(); static::deleting(static function (Group $group) { $group->users()->detach(); + $group->doors()->detach(); }); } } diff --git a/src/web/backend/app/Providers/AppServiceProvider.php b/src/web/backend/app/Providers/AppServiceProvider.php index 957c3a72..ecf6df95 100644 --- a/src/web/backend/app/Providers/AppServiceProvider.php +++ b/src/web/backend/app/Providers/AppServiceProvider.php @@ -12,6 +12,7 @@ use Source\Gateways\Tokens\TokensRepositoryServiceProvider; use Source\UseCases\Doors\GetDoor\GetDoorUseCaseServiceProvider; use Source\UseCases\Users\GetUser\GetUserUseCaseServiceProvider; use Source\Gateways\GroupUser\GroupUserRepositoryServiceProvider; +use Source\Gateways\DoorGroup\DoorGroupRepositoryServiceProvider; use Source\UseCases\Groups\GetGroup\GetGroupUseCaseServiceProvider; use Source\UseCases\Doors\CreateDoor\CreateDoorUseCaseServiceProvider; use Source\UseCases\Doors\DeleteDoor\DeleteDoorUseCaseServiceProvider; @@ -46,6 +47,7 @@ class AppServiceProvider extends ServiceProvider DoorsRepositoryServiceProvider::class, TokensRepositoryServiceProvider::class, GroupsRepositoryServiceProvider::class, + DoorGroupRepositoryServiceProvider::class, GroupUserRepositoryServiceProvider::class, ]; diff --git a/src/web/backend/src/Authorization/ApiAuthorizer.php b/src/web/backend/src/Authorization/ApiAuthorizer.php index 75a0007c..5746dd6c 100644 --- a/src/web/backend/src/Authorization/ApiAuthorizer.php +++ b/src/web/backend/src/Authorization/ApiAuthorizer.php @@ -4,6 +4,8 @@ namespace Source\Authorization; use Illuminate\Contracts\Auth\Guard; +use Source\Gateways\Users\UsersRepository; +use Source\Gateways\Groups\GroupsRepository; use Source\Exceptions\AuthorizationException; use Source\Exceptions\EntityNotFoundException; use Source\Gateways\GroupUser\GroupUserRepository; @@ -20,9 +22,25 @@ class ApiAuthorizer implements Authorizer */ protected GroupUserRepository $groupUserRepository; - public function __construct(Guard $guard, GroupUserRepository $groupUserRepository) - { + /** + * @var \Source\Gateways\Groups\GroupsRepository + */ + protected GroupsRepository $groups; + + /** + * @var \Source\Gateways\Users\UsersRepository + */ + protected UsersRepository $users; + + public function __construct( + Guard $guard, + UsersRepository $users, + GroupsRepository $groups, + GroupUserRepository $groupUserRepository + ) { + $this->users = $users; $this->guard = $guard; + $this->groups = $groups; $this->groupUserRepository = $groupUserRepository; } @@ -139,7 +157,7 @@ class ApiAuthorizer implements Authorizer */ public function protectAdminRights(string $userId, ?string $groupId = null): void { - $user = $this->groupUserRepository->getUser($userId); + $user = $this->users->get($userId); if (!$user) { throw new EntityNotFoundException('User not found.'); @@ -153,7 +171,7 @@ class ApiAuthorizer implements Authorizer } if ($groupId) { - $group = $this->groupUserRepository->getGroup($groupId); + $group = $this->groups->get($groupId); if (!$group) { throw new EntityNotFoundException('Group not found.'); } diff --git a/src/web/backend/src/Authorization/AuthorizerServiceProvider.php b/src/web/backend/src/Authorization/AuthorizerServiceProvider.php index a1d7f0bf..b104ef26 100644 --- a/src/web/backend/src/Authorization/AuthorizerServiceProvider.php +++ b/src/web/backend/src/Authorization/AuthorizerServiceProvider.php @@ -6,6 +6,8 @@ namespace Source\Authorization; use App\Guards\ApiGuard; use Illuminate\Foundation\Application; use Illuminate\Support\ServiceProvider; +use Source\Gateways\Users\UsersRepository; +use Source\Gateways\Groups\GroupsRepository; use Source\Gateways\GroupUser\GroupUserRepository; use Illuminate\Contracts\Support\DeferrableProvider; @@ -22,7 +24,12 @@ class AuthorizerServiceProvider extends ServiceProvider implements DeferrablePro public function register() { $this->app->singleton(Authorizer::class, static function (Application $app) { - return new ApiAuthorizer($app->make(ApiGuard::class), $app->make(GroupUserRepository::class)); + return new ApiAuthorizer( + $app->make(ApiGuard::class), + $app->make(UsersRepository::class), + $app->make(GroupsRepository::class), + $app->make(GroupUserRepository::class) + ); }); } diff --git a/src/web/backend/src/Gateways/DoorGroup/DatabaseDoorGroupRepository.php b/src/web/backend/src/Gateways/DoorGroup/DatabaseDoorGroupRepository.php new file mode 100644 index 00000000..0405c92e --- /dev/null +++ b/src/web/backend/src/Gateways/DoorGroup/DatabaseDoorGroupRepository.php @@ -0,0 +1,89 @@ +groups()->get()->values()->all()); + } + + /** + * @inheritDoc + */ + public function getDoorsForGroup(string $groupId): array + { + /** @var Group|null $group */ + $group = Group::find((int)$groupId); + + if (!$group) { + throw new EntityNotFoundException(); + } + + return array_map(static function (Door $door) { + return DatabaseDoorsRepository::makeDoorFromDb($door); + }, $group->doors()->get()->values()->all()); + } + + /** + * @inheritDoc + */ + public function addDoorToGroup(string $doorId, string $groupId): void + { + /** @var Door|null $door */ + $door = Door::find((int)$doorId); + /** @var Group|null $group */ + $group = Group::find((int)$groupId); + + if (!$door) { + throw new EntityNotFoundException('Door not found.'); + } + + if (!$group) { + throw new EntityNotFoundException('Group not found.'); + } + + $door->groups()->attach($groupId); + } + + /** + * @inheritDoc + */ + public function removeDoorFromGroup(string $doorId, string $groupId): void + { + /** @var Door|null $door */ + $door = Door::find((int)$doorId); + /** @var Group|null $group */ + $group = Group::find((int)$groupId); + + if (!$door) { + throw new EntityNotFoundException('Door not found.'); + } + + if (!$group) { + throw new EntityNotFoundException('Group not found.'); + } + + $door->groups()->detach($groupId); + } +} diff --git a/src/web/backend/src/Gateways/DoorGroup/DoorGroupRepository.php b/src/web/backend/src/Gateways/DoorGroup/DoorGroupRepository.php new file mode 100644 index 00000000..d3c638e5 --- /dev/null +++ b/src/web/backend/src/Gateways/DoorGroup/DoorGroupRepository.php @@ -0,0 +1,35 @@ +app->singleton(DoorGroupRepository::class, static function (Application $app) { + if (env('APP_ENV') === 'memory') { + return new LocalDoorGroupRepository( + new LocalDoorsRepository(), + new LocalGroupsRepository() + ); + } + + if(env('APP_ENV') === 'testing') { + return new InMemoryDoorGroupRepository( + $app->make(DoorsRepository::class), + $app->make(GroupsRepository::class) + ); + } + + return new DatabaseDoorGroupRepository(); + }); + } + + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot(): void + { + } + + /** + * @return array + */ + public function provides() + { + return [DoorGroupRepository::class]; + } +} diff --git a/src/web/backend/src/Gateways/DoorGroup/InMemoryDoorGroupRepository.php b/src/web/backend/src/Gateways/DoorGroup/InMemoryDoorGroupRepository.php new file mode 100644 index 00000000..4c86035b --- /dev/null +++ b/src/web/backend/src/Gateways/DoorGroup/InMemoryDoorGroupRepository.php @@ -0,0 +1,112 @@ +doors = $doors; + $this->groups = $groups; + } + + /** + * @inheritDoc + */ + public function getGroupsForDoor(string $doorId): array + { + if (!$this->doors->exists($doorId)) { + throw new EntityNotFoundException(); + } + + if (!isset($this->doorMap[$doorId])) { + return []; + } + + $groups = []; + + foreach ($this->doorMap[$doorId] as $groupId) { + if ($group = $this->groups->get($groupId)) { + $groups[] = $group; + } + } + + return $groups; + } + + /** + * @inheritDoc + */ + public function getDoorsForGroup(string $groupId): array + { + if (!$this->groups->get($groupId)) { + throw new EntityNotFoundException(); + } + + $doors = []; + + foreach ($this->doorMap as $doorId => $groupArray) { + foreach ($groupArray as $searchGroup) { + if (($groupId === $searchGroup) && ($door = $this->doors->get($doorId)) !== null) { + $doors[] = $door; + } + } + } + + return $doors; + } + + /** + * @inheritDoc + */ + public function addDoorToGroup(string $doorId, string $groupId): void + { + if (isset($this->doorMap[$doorId])) { + $this->doorMap[$doorId][] = $groupId; + + return; + } + + // It wasn't found, add it ourselves. + $this->doorMap[$doorId] = [$groupId]; + } + + /** + * @inheritDoc + */ + public function removeDoorFromGroup(string $doorId, string $groupId): void + { + if (isset($this->doorMap[$doorId])) { + $this->doorMap[$doorId] = array_filter( + $this->doorMap[$doorId], + static function (string $searchGroup) use ($groupId) { + return $searchGroup !== $groupId; + } + ); + } + } +} diff --git a/src/web/backend/src/Gateways/DoorGroup/LocalDoorGroupRepository.php b/src/web/backend/src/Gateways/DoorGroup/LocalDoorGroupRepository.php new file mode 100644 index 00000000..c7ea1eed --- /dev/null +++ b/src/web/backend/src/Gateways/DoorGroup/LocalDoorGroupRepository.php @@ -0,0 +1,30 @@ +addDoorToGroup( + $doors::getAmazonDoor()->getId(), + $groups::getEngineeringLabAccessGroup()->getId() + ); + + $this->addDoorToGroup( + $doors::getTheBatCave()->getId(), + $groups::getComputerScienceMajorGroup()->getId() + ); + } +} diff --git a/src/web/backend/src/Gateways/Doors/DatabaseDoorsRepository.php b/src/web/backend/src/Gateways/Doors/DatabaseDoorsRepository.php index 899de83e..23001075 100644 --- a/src/web/backend/src/Gateways/Doors/DatabaseDoorsRepository.php +++ b/src/web/backend/src/Gateways/Doors/DatabaseDoorsRepository.php @@ -123,4 +123,12 @@ class DatabaseDoorsRepository implements DoorsRepository { return \App\Door::destroy((int)$doorId); } + + /** + * @inheritDoc + */ + public function exists(string $doorId): bool + { + return (bool)$this->get($doorId); + } } diff --git a/src/web/backend/src/Gateways/Doors/DoorsRepository.php b/src/web/backend/src/Gateways/Doors/DoorsRepository.php index e0bb83e1..a869729a 100644 --- a/src/web/backend/src/Gateways/Doors/DoorsRepository.php +++ b/src/web/backend/src/Gateways/Doors/DoorsRepository.php @@ -60,4 +60,12 @@ interface DoorsRepository * @return bool */ public function delete(string $doorId): bool; + + /** + * Checks a door for existence. + * + * @param string $doorId + * @return bool + */ + public function exists(string $doorId): bool; } diff --git a/src/web/backend/src/Gateways/Doors/InMemoryDoorsRepository.php b/src/web/backend/src/Gateways/Doors/InMemoryDoorsRepository.php index 69b4d9ca..4051875f 100644 --- a/src/web/backend/src/Gateways/Doors/InMemoryDoorsRepository.php +++ b/src/web/backend/src/Gateways/Doors/InMemoryDoorsRepository.php @@ -105,4 +105,12 @@ class InMemoryDoorsRepository implements DoorsRepository return true; } + + /** + * @inheritDoc + */ + public function exists(string $doorId): bool + { + return (bool)$this->get($doorId); + } } diff --git a/src/web/backend/src/Gateways/Doors/LocalDoorsRepository.php b/src/web/backend/src/Gateways/Doors/LocalDoorsRepository.php index 1eaf4dd6..36b7d7eb 100644 --- a/src/web/backend/src/Gateways/Doors/LocalDoorsRepository.php +++ b/src/web/backend/src/Gateways/Doors/LocalDoorsRepository.php @@ -9,9 +9,38 @@ use Source\Entities\HashedSearchable; class LocalDoorsRepository extends InMemoryDoorsRepository { public function __construct() + { + $this->doors[] = static::getAmazonDoor(); + $this->doors[] = static::getTheBatCave(); + } + + /** + * @return \Source\Entities\Door + */ + public static function getAmazonDoor(): Door { $salt = config('app.key'); - $this->doors[] = new Door(1, 'The Amazon', 'chicken izta door', HashedSearchable::hash($salt, 'door_1_api_token')); - $this->doors[] = new Door(2, 'Bat Cave', 'Bruce\' lair', HashedSearchable::hash($salt, 'door_2_api_token')); + + return new Door( + 1, + 'The Amazon', + 'chicken izta door', + HashedSearchable::hash($salt, 'door_1_api_token') + ); + } + + /** + * @return \Source\Entities\Door + */ + public static function getTheBatCave(): Door + { + $salt = config('app.key'); + + return new Door( + 2, + 'Bat Cave', + 'Bruce\' lair', + HashedSearchable::hash($salt, 'door_2_api_token') + ); } } diff --git a/src/web/backend/src/Gateways/GroupUser/DatabaseGroupUserRepository.php b/src/web/backend/src/Gateways/GroupUser/DatabaseGroupUserRepository.php index 516f322e..b3b2d384 100644 --- a/src/web/backend/src/Gateways/GroupUser/DatabaseGroupUserRepository.php +++ b/src/web/backend/src/Gateways/GroupUser/DatabaseGroupUserRepository.php @@ -86,28 +86,4 @@ class DatabaseGroupUserRepository implements GroupUserRepository $user->groups()->detach($groupId); } - - /** - * @inheritDoc - */ - public function getGroup(string $groupId): ?\Source\Entities\Group - { - if ($g = Group::find((int)$groupId)) { - return DatabaseGroupsRepository::makeGroupFromDbGroup($g); - } - - return null; - } - - /** - * @inheritDoc - */ - public function getUser(string $userId): ?\Source\Entities\User - { - if ($user = User::find((int)$userId)) { - return DatabaseUsersRepository::makeUserFromDbUser($user); - } - - return null; - } } diff --git a/src/web/backend/src/Gateways/GroupUser/GroupUserRepository.php b/src/web/backend/src/Gateways/GroupUser/GroupUserRepository.php index f031eb67..3192cc21 100644 --- a/src/web/backend/src/Gateways/GroupUser/GroupUserRepository.php +++ b/src/web/backend/src/Gateways/GroupUser/GroupUserRepository.php @@ -35,16 +35,4 @@ interface GroupUserRepository * @throws \Source\Exceptions\EntityNotFoundException */ public function removeUserFromGroup(string $userId, string $groupId): void; - - /** - * @param string $groupId - * @return \Source\Entities\Group|null - */ - public function getGroup(string $groupId): ?Group; - - /** - * @param string $userId - * @return \Source\Entities\User|null - */ - public function getUser(string $userId): ?User; } diff --git a/src/web/backend/src/Gateways/GroupUser/InMemoryGroupUserRepository.php b/src/web/backend/src/Gateways/GroupUser/InMemoryGroupUserRepository.php index 45c843e0..b335832e 100644 --- a/src/web/backend/src/Gateways/GroupUser/InMemoryGroupUserRepository.php +++ b/src/web/backend/src/Gateways/GroupUser/InMemoryGroupUserRepository.php @@ -113,20 +113,4 @@ class InMemoryGroupUserRepository implements GroupUserRepository ); } } - - /** - * @inheritDoc - */ - public function getGroup(string $groupId): ?Group - { - return $this->groups->get($groupId); - } - - /** - * @inheritDoc - */ - public function getUser(string $userId): ?User - { - return $this->users->get($userId); - } } diff --git a/src/web/backend/src/Gateways/GroupUser/LocalGroupUserRepository.php b/src/web/backend/src/Gateways/GroupUser/LocalGroupUserRepository.php index 55014cdc..20be5f30 100644 --- a/src/web/backend/src/Gateways/GroupUser/LocalGroupUserRepository.php +++ b/src/web/backend/src/Gateways/GroupUser/LocalGroupUserRepository.php @@ -17,20 +17,20 @@ class LocalGroupUserRepository extends InMemoryGroupUserRepository { parent::__construct($users, $groups); - $this->addUserToGroup(LocalUsersRepository::getAdminUser()->getId(), LocalGroupsRepository::getAdminGroup()->getId()); + $this->addUserToGroup($users::getAdminUser()->getId(), $groups::getAdminGroup()->getId()); - $this->addUserToGroup(LocalUsersRepository::getSemiPrivilegedUser()->getId(), LocalGroupsRepository::getManageUsersGroup()->getId()); - $this->addUserToGroup(LocalUsersRepository::getSemiPrivilegedUser()->getId(), LocalGroupsRepository::getManageDoorsGroup()->getId()); - $this->addUserToGroup(LocalUsersRepository::getSemiPrivilegedUser()->getId(), LocalGroupsRepository::getCodeQueryGroup()->getId()); - $this->addUserToGroup(LocalUsersRepository::getSemiPrivilegedUser()->getId(), LocalGroupsRepository::getManageGroupsGroup()->getId()); + $this->addUserToGroup($users::getSemiPrivilegedUser()->getId(), $groups::getManageUsersGroup()->getId()); + $this->addUserToGroup($users::getSemiPrivilegedUser()->getId(), $groups::getManageDoorsGroup()->getId()); + $this->addUserToGroup($users::getSemiPrivilegedUser()->getId(), $groups::getCodeQueryGroup()->getId()); + $this->addUserToGroup($users::getSemiPrivilegedUser()->getId(), $groups::getManageGroupsGroup()->getId()); $this->addUserToGroup( - LocalUsersRepository::getComputerScienceStudent()->getId(), - LocalGroupsRepository::getComputerScienceMajorGroup()->getId() + $users::getComputerScienceStudent()->getId(), + $groups::getComputerScienceMajorGroup()->getId() ); $this->addUserToGroup( - LocalUsersRepository::getEngineeringLabAccessStudent()->getId(), - LocalGroupsRepository::getEngineeringLabAccessGroup()->getId() + $users::getEngineeringLabAccessStudent()->getId(), + $groups::getEngineeringLabAccessGroup()->getId() ); } } diff --git a/src/web/backend/tests/Database/GroupUserDatabaseTest.php b/src/web/backend/tests/Database/GroupUserDatabaseTest.php index f8a79497..9631fd16 100644 --- a/src/web/backend/tests/Database/GroupUserDatabaseTest.php +++ b/src/web/backend/tests/Database/GroupUserDatabaseTest.php @@ -131,16 +131,4 @@ class GroupUserDatabaseTest extends DatabaseTestCase $this->assertCount(1, $this->groupUsers->getUsersForGroup('1')); } - - /** - * @test - */ - public function it_can_get_users_and_groups(): void - { - $this->assertNull($this->groupUsers->getUser('asdf')); - $this->assertNull($this->groupUsers->getGroup('asdf')); - - $this->assertNotNull($this->groupUsers->getUser('1')); - $this->assertNotNull($this->groupUsers->getGroup('1')); - } } -- GitLab