Commit c75dd862 authored by Jacob Priddy's avatar Jacob Priddy 👌

Add door group database relations and remove get users and get doors off

of usergroup gateway as it is repeated code
parent e7af8026
......@@ -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();
});
}
}
......@@ -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();
});
}
}
......@@ -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,
];
......
......@@ -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.');
}
......
......@@ -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)
);
});
}
......
<?php
namespace Source\Gateways\DoorGroup;
use App\Door;
use App\Group;
use Source\Exceptions\EntityNotFoundException;
use Source\Gateways\Doors\DatabaseDoorsRepository;
use Source\Gateways\Groups\DatabaseGroupsRepository;
class DatabaseDoorGroupRepository implements DoorGroupRepository
{
/**
* @inheritDoc
*/
public function getGroupsForDoor(string $doorId): array
{
/** @var Door|null $door */
$door = Door::find((int)$doorId);
if (!$door) {
throw new EntityNotFoundException();
}
return array_map(static function (Group $group) {
DatabaseGroupsRepository::makeGroupFromDbGroup($group);
}, $door->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);
}
}
<?php
namespace Source\Gateways\DoorGroup;
interface DoorGroupRepository
{
/**
* @param string $doorId
* @return \Source\Entities\Group[]
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function getGroupsForDoor(string $doorId): array;
/**
* @param string $groupId
* @return \Source\Entities\Door[]
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function getDoorsForGroup(string $groupId): array;
/**
* @param string $doorId
* @param string $groupId
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function addDoorToGroup(string $doorId, string $groupId): void;
/**
* @param string $doorId
* @param string $groupId
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function removeDoorFromGroup(string $doorId, string $groupId): void;
}
<?php
namespace Source\Gateways\DoorGroup;
use Source\Gateways\Doors\DoorsRepository;
use Source\Gateways\Groups\GroupsRepository;
use Source\Gateways\Doors\LocalDoorsRepository;
use Illuminate\Contracts\Foundation\Application;
use Source\Gateways\Groups\LocalGroupsRepository;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
/**
* Service provider must be registered in AppServiceProvider
*/
class DoorGroupRepositoryServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->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];
}
}
<?php
namespace Source\Gateways\DoorGroup;
use Source\Gateways\Doors\DoorsRepository;
use Source\Gateways\Groups\GroupsRepository;
use Source\Exceptions\EntityNotFoundException;
class InMemoryDoorGroupRepository implements DoorGroupRepository
{
/**
* @var \Source\Gateways\Doors\DoorsRepository
*/
protected DoorsRepository $doors;
/**
* @var \Source\Gateways\Groups\GroupsRepository
*/
protected GroupsRepository $groups;
/**
* Array of doorId's mapped to an array of groupIds
*
* @var array
*/
protected array $doorMap = [];
public function __construct(
DoorsRepository $doors,
GroupsRepository $groups
) {
$this->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;
}
);
}
}
}
<?php
namespace Source\Gateways\DoorGroup;
use Source\Gateways\Doors\LocalDoorsRepository;
use Source\Gateways\Groups\LocalGroupsRepository;
class LocalDoorGroupRepository extends InMemoryDoorGroupRepository
{
/**
* @param \Source\Gateways\Doors\LocalDoorsRepository $doors
* @param \Source\Gateways\Groups\LocalGroupsRepository $groups
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function __construct(LocalDoorsRepository $doors, LocalGroupsRepository $groups)
{
parent::__construct($doors, $groups);
$this->addDoorToGroup(
$doors::getAmazonDoor()->getId(),
$groups::getEngineeringLabAccessGroup()->getId()
);
$this->addDoorToGroup(
$doors::getTheBatCave()->getId(),
$groups::getComputerScienceMajorGroup()->getId()
);
}
}
......@@ -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);
}
}
......@@ -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;
}
......@@ -105,4 +105,12 @@ class InMemoryDoorsRepository implements DoorsRepository
return true;
}
/**
* @inheritDoc
*/
public function exists(string $doorId): bool
{
return (bool)$this->get($doorId);
}
}
......@@ -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')
);
}
}
......@@ -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;
}
}
......@@ -35,16 +35,4 @@ interface GroupUserRepository
* @throws \Source\Exceptions\EntityNotFoundException