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

Overlaps refactor for pagination

parent 344ee8f8
......@@ -11,8 +11,7 @@ use Source\UseCases\Overrides\ApiPresenter;
use Source\UseCases\Overrides\OverrideGet\OverrideGetUseCase;
use Source\UseCases\Overrides\OverrideCreate\OverrideCreateUseCase;
use Source\UseCases\Overrides\OverrideUpdate\OverrideUpdateUseCase;
use Source\UseCases\Overrides\OverridesForDoor\OverridesForDoorUseCase;
use Source\UseCases\Overrides\OverridesForDateRange\OverridesForDateRangeUseCase;
use Source\UseCases\Overrides\OverridesGet\OverridesGetUseCase;
use Source\UseCases\Overrides\OverrideCreate\ApiPresenter as OverrideCreateApiPresenter;
class OverridesController extends ApiController
......@@ -94,48 +93,39 @@ class OverridesController extends ApiController
}
/**
* @param string $doorId
* @param \Source\UseCases\Overrides\OverridesForDoor\OverridesForDoorUseCase $overridesForDoor
* @return \Illuminate\Http\JsonResponse
* @throws \Source\Exceptions\AuthorizationException
* @throws \Source\Exceptions\EntityNotFoundException
*/
public function forDoor(string $doorId, OverridesForDoorUseCase $overridesForDoor): JsonResponse
{
$this->authorizer->protect(Permissions::LOGS_READ);
$presenter = new ApiPresenter();
$overridesForDoor->getOverridesForDoor($doorId, $presenter);
return $this->respondWithData($presenter->getViewModel());
}
/**
* @param \Source\UseCases\Overrides\OverridesForDateRange\OverridesForDateRangeUseCase $overridesInDateRange
* @param \Source\UseCases\Overrides\OverridesGet\OverridesGetUseCase $overridesInDateRange
* @return \Illuminate\Http\JsonResponse
* @throws \Illuminate\Validation\ValidationException
* @throws \Source\Exceptions\AuthorizationException
* @throws \Source\Exceptions\EntityNotFoundException
* @throws \Exception
*/
public function index(OverridesForDateRangeUseCase $overridesInDateRange): JsonResponse
public function index(OverridesGetUseCase $overridesInDateRange): JsonResponse
{
$this->authorizer->protect(Permissions::LOGS_READ);
$this->validate($this->request, [
'start' => 'required|date|before:end',
'end' => 'required|date|after:start',
'start' => 'date',
'end' => 'date',
'door_id' => 'integer',
'user_id' => 'integer',
]);
$presenter = new ApiPresenter();
$overridesInDateRange->getOverridesForDateRange(
$overridesInDateRange->filter(
$this->request->input('door_id'),
$this->request->input('user_id'),
$this->request->input('start'),
$this->request->input('end'),
$presenter
);
return $this->respondWithData($presenter->getViewModel());
return $this->respondWithData($presenter->getViewModel([
'start' => $this->request->input('start'),
'end' => $this->request->input('end'),
'door_id' => $this->request->input('door_id'),
'user_id' => $this->request->input('user_id'),
]));
}
}
......@@ -48,6 +48,7 @@ use Source\UseCases\Overrides\OverrideGet\OverrideGetUseCaseServiceProvider;
use Source\UseCases\Schedules\ScheduleGet\ScheduleGetUseCaseServiceProvider;
use Source\UseCases\Door\StatusResponse\StatusResponseUseCaseServiceProvider;
use Source\UseCases\Schedules\SchedulesGet\SchedulesGetUseCaseServiceProvider;
use Source\UseCases\Overrides\OverridesGet\OverridesGetUseCaseServiceProvider;
use Source\UseCases\DoorGroup\GetDoorGroups\GetDoorGroupsUseCaseServiceProvider;
use Source\UseCases\DoorGroup\GetGroupDoors\GetGroupDoorsUseCaseServiceProvider;
use Source\UseCases\GroupUser\GetGroupUsers\GetGroupUsersUseCaseServiceProvider;
......@@ -61,11 +62,9 @@ use Source\UseCases\Overrides\OverrideUpdate\OverrideUpdateUseCaseServiceProvide
use Source\UseCases\Schedules\ScheduleCreate\ScheduleCreateUseCaseServiceProvider;
use Source\UseCases\Schedules\ScheduleUpdate\ScheduleUpdateUseCaseServiceProvider;
use Source\UseCases\Doors\GenerateDoorToken\GenerateDoorTokenUseCaseServiceProvider;
use Source\UseCases\Overrides\OverridesForDoor\OverridesForDoorUseCaseServiceProvider;
use Source\UseCases\DoorGroup\RemoveDoorFromGroup\RemoveDoorFromGroupUseCaseServiceProvider;
use Source\UseCases\GroupSchedule\SchedulesForGroup\SchedulesForGroupUseCaseServiceProvider;
use Source\UseCases\GroupUser\RemoveUserFromGroup\RemoveUserFromGroupUseCaseServiceProvider;
use Source\UseCases\Overrides\OverridesForDateRange\OverridesForDateRangeUseCaseServiceProvider;
use Source\UseCases\GroupSchedule\ActiveSchedulesForGroup\ActiveSchedulesForGroupUseCaseServiceProvider;
use Source\UseCases\Door\Authenticate\AuthenticateUseCaseServiceProvider as DoorAuthenticateUseCaseServiceProvider;
use Source\UseCases\Users\Authenticate\AuthenticateUseCaseServiceProvider as UserAuthenticateUseCaseServiceProvider;
......@@ -136,10 +135,10 @@ class AppServiceProvider extends ServiceProvider
// Doors
GetDoorUseCaseServiceProvider::class,
GetDoorsUseCaseServiceProvider::class,
CreateDoorUseCaseServiceProvider::class,
DeleteDoorUseCaseServiceProvider::class,
UpdateDoorUseCaseServiceProvider::class,
GetDoorsUseCaseServiceProvider::class,
UserAuthenticateUseCaseServiceProvider::class,
GenerateDoorTokenUseCaseServiceProvider::class,
......@@ -170,10 +169,9 @@ class AppServiceProvider extends ServiceProvider
// Overrides
OverrideGetUseCaseServiceProvider::class,
OverridesGetUseCaseServiceProvider::class,
OverrideCreateUseCaseServiceProvider::class,
OverrideUpdateUseCaseServiceProvider::class,
OverridesForDoorUseCaseServiceProvider::class,
OverridesForDateRangeUseCaseServiceProvider::class,
// Commands
CommandServiceProvider::class,
......
......@@ -72,8 +72,6 @@ Route::group(['middleware' => 'auth:api'], static function () {
Route::get('{doorId}/groups', [DoorsController::class, 'getGroupsForDoor']);
Route::post('{doorId}/group/{groupId}', [DoorsController::class, 'addDoorToGroup']);
Route::delete('{doorId}/group/{groupId}', [DoorsController::class, 'removeDoorFromGroup']);
Route::get('{doorId}/overrides', [OverridesController::class, 'forDoor']);
});
Route::group([
......
......@@ -148,12 +148,25 @@ class Override
return $this->getDoorId() === (int)$doorId;
}
/**
* @param string $userId
* @return bool
*/
public function hasUserIdOf(string $userId): bool
{
return $this->getUserId() === (int)$userId;
}
/**
* @param \Carbon\Carbon $date
* @return bool
*/
public function isActiveForDate(Carbon $date): bool
public function isActiveForDate(?Carbon $date): bool
{
if (!$date) {
return false;
}
if ($this->getEnd()) {
return $date->isBetween($this->getStart(), $this->getEnd());
}
......
......@@ -64,38 +64,29 @@ class DatabaseOverridesRepository implements OverridesRepository
/**
* @inheritDoc
*/
public function overrideHistoryForDoor(string $doorId): array
public function filterHistory(?string $doorId, ?string $userId, ?Carbon $begin, ?Carbon $end): array
{
$overrides = \App\Override::query()
->where('door_id', $this->castToInt($doorId))
->orderByDesc('created_at')
->get()->values()->all();
$query = \App\Override::query()->orderByDesc('created_at');
return array_map(static function (\App\Override $override) {
return self::toOverride($override);
}, $overrides);
}
if ($doorId) {
$query->where('door_id', $this->castToInt($doorId));
}
/**
* @inheritDoc
*/
public function overrideHistoryBetween(Carbon $begin, Carbon $end): array
{
$query = <<<QUERY
select A.id, A.reason, A.user_id, A.door_id, A.type, A.start, A.end, A.created_at, A.updated_at
from overrides as A
WHERE ((:BEGIN, :END) OVERLAPS (A.start, A.end))
ORDER BY A.created_at DESC
QUERY;
if ($userId) {
$query->where('user_id', $this->castToInt($userId));
}
$overrides = $this->db->select($query, [
':BEGIN' => $begin,
':END' => $end,
]);
if ($begin && $end) {
$query->whereRaw('((:BEGIN, :END) OVERLAPS ("start", "end"))', [':BEGIN' => $begin, ':END' => $end]);
} elseif ($begin) {
$query->where('start', '>', $begin);
} elseif ($end) {
$query->where('end', '<', $end);
}
return array_map(function ($override) {
return $this->toOverrideFromRaw($override);
}, $overrides);
return array_map(static function (\App\Override $override) {
return self::toOverride($override);
}, $query->get()->values()->all());
}
/**
......
......@@ -16,20 +16,24 @@ class InMemoryOverridesRepository implements OverridesRepository
/**
* @inheritDoc
*/
public function overrideHistoryForDoor(string $doorId): array
public function filterHistory(?string $doorId, ?string $userId, ?Carbon $begin, ?Carbon $end): array
{
return array_filter($this->overrides, static function (Override $override) use ($doorId) {
return $override->hasDoorIdOf($doorId);
});
}
return array_filter($this->overrides, static function (Override $override) use ($begin, $end, $doorId, $userId) {
$include = true;
/**
* @inheritDoc
*/
public function overrideHistoryBetween(Carbon $begin, Carbon $end): array
{
return array_filter($this->overrides, static function (Override $override) use ($begin, $end) {
return $override->isActiveForDate($begin) || $override->isActiveForDate($end);
if ($begin || $end) {
$include = $include && ($override->isActiveForDate($begin) || $override->isActiveForDate($end));
}
if ($doorId) {
$include = $include && $override->hasDoorIdOf($doorId);
}
if ($userId) {
$include = $include && $override->hasUserIdOf($userId);
}
return $include;
});
}
......
......@@ -9,17 +9,15 @@ use Source\Entities\Override;
interface OverridesRepository
{
/**
* @param string $doorId
* @return \Source\Entities\Override[]
*/
public function overrideHistoryForDoor(string $doorId): array;
/**
* @param \Carbon\Carbon $begin
* @param \Carbon\Carbon $end
* Filters override history
*
* @param string|null $doorId
* @param string|null $userId
* @param \Carbon\Carbon|null $begin
* @param \Carbon\Carbon|null $end
* @return \Source\Entities\Override[]
*/
public function overrideHistoryBetween(Carbon $begin, Carbon $end): array;
public function filterHistory(?string $doorId, ?string $userId, ?Carbon $begin, ?Carbon $end): array;
/**
* Gets active override during date (if any). Returns null otherwise.
......
......@@ -21,8 +21,8 @@ class ApiPresenter extends BasePresenter implements Presenter
}
/** @inheritDoc */
public function getViewModel(): array
public function getViewModel(array $appends = []): array
{
return $this->paginate($this->overrides);
return $this->paginate($this->overrides, $appends);
}
}
<?php
namespace Source\UseCases\Overrides\OverridesForDateRange;
use Source\UseCases\Overrides\Presenter;
interface OverridesForDateRangeUseCase
{
/**
* Gets all overrides within a range
*
* @param string $start
* @param string $end
* @param \Source\UseCases\Overrides\Presenter $presenter
* @throws \Exception
*/
public function getOverridesForDateRange(string $start, string $end, Presenter $presenter): void;
}
<?php
namespace Source\UseCases\Overrides\OverridesForDateRange;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Foundation\Application;
use Source\Gateways\Overrides\OverridesRepository;
use Illuminate\Contracts\Support\DeferrableProvider;
/**
* Service provider must be registered in AppServiceProvider
*/
class OverridesForDateRangeUseCaseServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->bind(OverridesForDateRangeUseCase::class, static function (Application $app) {
return new OverridesForDateRange($app->make(OverridesRepository::class));
});
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot(): void
{
}
/**
* @return array
*/
public function provides()
{
return [OverridesForDateRangeUseCase::class];
}
}
<?php
namespace Source\UseCases\Overrides\OverridesForDoor;
use Source\UseCases\Overrides\Presenter;
use Source\UseCases\Overrides\ResponseModel;
use Source\Gateways\Overrides\OverridesRepository;
class OverridesForDoor implements OverridesForDoorUseCase
{
/**
* @var \Source\Gateways\Overrides\OverridesRepository
*/
protected OverridesRepository $overrides;
public function __construct(OverridesRepository $overrides)
{
$this->overrides = $overrides;
}
/**
* @inheritDoc
*/
public function getOverridesForDoor(string $doorId, Presenter $presenter): void
{
$overrides = $this->overrides->overrideHistoryForDoor($doorId);
$response = new ResponseModel();
foreach ($overrides as $override) {
$response->addOverride($override);
}
$presenter->present($response);
}
}
<?php
namespace Source\UseCases\Overrides\OverridesForDoor;
use Source\UseCases\Overrides\Presenter;
interface OverridesForDoorUseCase
{
/**
* Gets all overrides that ever occurred on a door
*
* @param string $doorId
* @param \Source\UseCases\Overrides\Presenter $presenter
*/
public function getOverridesForDoor(string $doorId, Presenter $presenter): void;
}
<?php
namespace Source\UseCases\Overrides\OverridesForDateRange;
namespace Source\UseCases\Overrides\OverridesGet;
use Carbon\Carbon;
use Source\Sanitize\CastsTo;
use Source\UseCases\Overrides\Presenter;
use Source\UseCases\Overrides\ResponseModel;
use Source\Gateways\Overrides\OverridesRepository;
class OverridesForDateRange implements OverridesForDateRangeUseCase
class OverridesGet implements OverridesGetUseCase
{
use CastsTo;
/**
* @var \Source\Gateways\Overrides\OverridesRepository
*/
......@@ -22,9 +24,14 @@ class OverridesForDateRange implements OverridesForDateRangeUseCase
/**
* @inheritDoc
*/
public function getOverridesForDateRange(string $start, string $end, Presenter $presenter): void
public function filter(?string $doorId, ?string $userId, ?string $start, ?string $end, Presenter $presenter): void
{
$overrides = $this->overrides->overrideHistoryBetween(new Carbon($start), new Carbon($end));
$overrides = $this->overrides->filterHistory(
$doorId,
$userId,
$this->liberalCastToCarbon($start),
$this->liberalCastToCarbon($end)
);
$response = new ResponseModel();
......
<?php
namespace Source\UseCases\Overrides\OverridesGet;
use Source\UseCases\Overrides\Presenter;
interface OverridesGetUseCase
{
/**
* Gets all overrides within the specified parameters
*
* @param string|null $doorId
* @param string|null $userId
* @param string|null $start
* @param string|null $end
* @param \Source\UseCases\Overrides\Presenter $presenter
* @throws \Exception
*/
public function filter(?string $doorId, ?string $userId, ?string $start, ?string $end, Presenter $presenter): void;
}
<?php
namespace Source\UseCases\Overrides\OverridesForDoor;
namespace Source\UseCases\Overrides\OverridesGet;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Foundation\Application;
......@@ -11,7 +11,7 @@ use Illuminate\Contracts\Support\DeferrableProvider;
/**
* Service provider must be registered in AppServiceProvider
*/
class OverridesForDoorUseCaseServiceProvider extends ServiceProvider implements DeferrableProvider
class OverridesGetUseCaseServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Register any application services.
......@@ -20,8 +20,8 @@ class OverridesForDoorUseCaseServiceProvider extends ServiceProvider implements
*/
public function register()
{
$this->app->bind(OverridesForDoorUseCase::class, static function (Application $app) {
return new OverridesForDoor($app->make(OverridesRepository::class));
$this->app->bind(OverridesGetUseCase::class, static function (Application $app) {
return new OverridesGet($app->make(OverridesRepository::class));
});
}
......@@ -39,6 +39,6 @@ class OverridesForDoorUseCaseServiceProvider extends ServiceProvider implements
*/
public function provides()
{
return [OverridesForDoorUseCase::class];
return [OverridesGetUseCase::class];
}
}
......@@ -11,7 +11,8 @@ interface Presenter
public function present(ResponseModel $responseModel): void;
/**
* @param array $appends
* @return array
*/
public function getViewModel(): array;
public function getViewModel(array $appends = []): array;
}
......@@ -95,8 +95,8 @@ class OverrideDatabaseTest extends DatabaseTestCase
Carbon::now()->addHour()
));
$this->assertCount(1, $this->repository->overrideHistoryForDoor($d1->getId()));
$this->assertCount(1, $this->repository->overrideHistoryBetween(Carbon::now()->addMinute(), Carbon::now()->addMinutes(2)));
$this->assertCount(1, $this->repository->filterHistory($d1->getId(), null, null, null));
$this->assertCount(1, $this->repository->filterHistory(null, null, Carbon::now()->addMinute(), Carbon::now()->addMinutes(2)));
}
/**
......
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