Commit 8c585b35 authored by Jacob Priddy's avatar Jacob Priddy 👌

OH BOY THERES A LOT IN THIS ONE

First off, refactor service providers to be less maintinance
Change up schedules to have a pivot table so they can be reused
Uhh, that's it for now I think....
parent 2d50f56f
......@@ -31,7 +31,7 @@ class GenerateGatewayServiceProvider extends BaseGatewayFileGenerator
*
* @return string
*/
protected function getStub()
protected function getStub(): string
{
return __DIR__ . '/stubs/Provider.stub';
}
......@@ -42,7 +42,7 @@ class GenerateGatewayServiceProvider extends BaseGatewayFileGenerator
* @param string $name
* @return string
*/
protected function getPath($name)
protected function getPath($name): string
{
$fullName = $this->getNameInput();
......
......@@ -31,7 +31,7 @@ class GenerateUseCaseServiceProvider extends BaseUseCaseFileGenerator
*
* @return string
*/
protected function getStub()
protected function getStub(): string
{
return __DIR__ . '/stubs/Provider.stub';
}
......@@ -42,7 +42,7 @@ class GenerateUseCaseServiceProvider extends BaseUseCaseFileGenerator
* @param string $name
* @return string
*/
protected function getPath($name)
protected function getPath($name): string
{
$fullName = $this->getNameInput();
......
......@@ -4,7 +4,6 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Group extends Model
......@@ -25,23 +24,22 @@ class Group extends Model
return $this->belongsToMany(Door::class);
}
public function schedules(): HasMany
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function schedules(): BelongsToMany
{
return $this->hasMany(Schedule::class);
return $this->belongsToMany(Schedule::class);
}
public static function boot()
public static function boot(): void
{
parent::boot();
static::deleting(static function (Group $group) {
$group->users()->detach();
$group->doors()->detach();
/** @var \App\Schedule $schedule */
foreach ($group->schedules() as $schedule) {
$schedule->delete();
}
$group->schedules()->detach();
});
}
}
......@@ -36,7 +36,6 @@ class SchedulesController extends ApiController
*
* @authenticated
* @bodyParam duration integer required The duration in seconds that the event lasts for. Example: 120
* @bodyParam group_id integer required The group to apply the schedule for. Example: 8
* @bodyParam type integer required The type of schedule. Example: 0
* @bodyParam rset string required The RFC 5545 compliant string representing the set. Example: RRULE:FREQ=MINUTELY
* @bodyParam description string required The administrative description for the schedule. Example: Documentation
......@@ -53,7 +52,6 @@ class SchedulesController extends ApiController
$this->validate($this->request, [
'duration' => 'required|integer',
'group_id' => 'required|integer',
'type' => 'required|integer',
'rset' => 'required|string',
'description' => 'required|string|max:1024',
......@@ -96,7 +94,7 @@ class SchedulesController extends ApiController
/**
* Filter Schedules
*
* This endpoint searches/filters schedules in the system by start, end, type, or group_id. If no query is provided
* This endpoint searches/filters schedules in the system by start, end, or type. If no query is provided
* a paginated list of all schedules are returned.
*
* @authenticated
......@@ -104,7 +102,6 @@ class SchedulesController extends ApiController
* @queryParam start Filters schedules active after this datetime. Example: 1900-06-04 19:23:55
* @queryParam end Filters schedules active before this datetime. Example: 2900-06-04
* @queryParam type The type to filter on. Example: 0
* @queryParam group_id The group id to filter on. Example: 7
*
* @param \Source\UseCases\Schedules\SchedulesGet\SchedulesGetUseCase $schedulesBetween
* @return \Illuminate\Http\JsonResponse
......@@ -121,13 +118,11 @@ class SchedulesController extends ApiController
'start' => 'nullable|date',
'end' => 'nullable|date',
'type' => 'nullable|integer',
'group_id' => 'nullable|integer',
]);
$presenter = new SchedulesGetApiPresenter();
$schedulesBetween->filter(
$this->request->input('group_id'),
$this->request->input('type'),
$this->request->input('start'),
$this->request->input('end'),
......@@ -146,7 +141,6 @@ class SchedulesController extends ApiController
* @authenticated
* @urlParam scheduleId required The schedule to update. Example: 1
* @bodyParam duration integer The duration in seconds that the event lasts for. Example: 120
* @bodyParam group_id integer The group to apply the schedule for. Example: 8
* @bodyParam type integer The type of schedule. Example: 0
* @bodyParam rset string The RFC 5545 compliant string representing the set. Example: RRULE:FREQ=MINUTELY
* @bodyParam description string The administrative description for the schedule. Example: Documentation
......@@ -164,7 +158,6 @@ class SchedulesController extends ApiController
$this->validate($this->request, [
'duration' => 'nullable|integer',
'group_id' => 'nullable|integer',
'type' => 'nullable|integer',
'rset' => 'nullable|string',
'description' => 'nullable|string|max:1024',
......@@ -197,6 +190,7 @@ class SchedulesController extends ApiController
* @throws \Illuminate\Validation\ValidationException
* @throws \Source\Exceptions\AuthorizationException
* @throws \Source\Exceptions\EntityNotFoundException
* @throws \Exception
*/
public function events(ScheduleEventsUseCase $scheduleEvents): JsonResponse
{
......
......@@ -2,7 +2,6 @@
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
......@@ -25,7 +24,7 @@ class EventServiceProvider extends ServiceProvider
*
* @return void
*/
public function boot()
public function boot(): void
{
parent::boot();
......
......@@ -16,19 +16,12 @@ class RouteServiceProvider extends ServiceProvider
*/
protected $namespace = 'App\Http\Controllers';
/**
* The path to the "home" route for your application.
*
* @var string
*/
public const HOME = '/';
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
public function boot(): void
{
parent::boot();
}
......@@ -38,7 +31,7 @@ class RouteServiceProvider extends ServiceProvider
*
* @return void
*/
public function map()
public function map(): void
{
$this->mapDoorRoutes();
......
......@@ -4,17 +4,26 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Schedule extends Model
{
protected $dates = ['start', 'end'];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function group(): BelongsTo
public function groups(): BelongsToMany
{
return $this->belongsTo(Group::class);
return $this->belongsToMany(Group::class);
}
public static function boot(): void
{
parent::boot();
static::deleting(static function (Schedule $schedule) {
$schedule->groups()->detach();
});
}
}
......@@ -206,6 +206,7 @@ return [
Source\Gateways\Filesystem\FilesystemRepositoryServiceProvider::class,
Source\Gateways\Statistics\StatisticsRepositoryServiceProvider::class,
Source\Gateways\DoorSchedule\DoorScheduleRepositoryServiceProvider::class,
Source\Gateways\GroupSchedule\GroupScheduleRepositoryServiceProvider::class,
Source\Gateways\RecurrenceSet\RecurrenceSetRepositoryServiceProvider::class,
/*
......
......@@ -15,7 +15,6 @@ class CreateSchedulesTable extends Migration
{
Schema::create('schedules', static function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('group_id');
/*
* 0 -> door open mode schedule
* 1 -> user group schedule
......@@ -28,7 +27,6 @@ class CreateSchedulesTable extends Migration
$table->unsignedBigInteger('duration');
$table->string('description');
$table->timestamps();
$table->foreign('group_id')->references('id')->on('groups');
});
}
......
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateGroupScheduleTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up(): void
{
Schema::create('group_schedule', static function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('group_id');
$table->foreign('group_id')->references('id')->on('groups');
$table->unsignedBigInteger('schedule_id');
$table->foreign('schedule_id')->references('id')->on('schedules');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down(): void
{
Schema::dropIfExists('group_schedule');
}
}
......@@ -48,7 +48,6 @@ class Schedule
public function __construct(
int $id,
int $groupId,
int $type,
string $rset,
int $duration,
......@@ -62,7 +61,6 @@ class Schedule
throw new InvalidArgumentException('Type not valid schedule type.');
}
$this->id = $id;
$this->groupId = $groupId;
$this->type = $type;
$this->rset = $rset;
$this->duration = $duration;
......@@ -81,14 +79,6 @@ class Schedule
return $this->id;
}
/**
* @return int
*/
public function getGroupId(): int
{
return $this->groupId;
}
/**
* @return int
*/
......
......@@ -17,25 +17,25 @@ class AttemptsRepositoryServiceProvider extends ServiceProvider implements Defer
*
* @return void
*/
public function register()
public function register(): void
{
$this->app->singleton(AttemptsRepository::class, static function (Application $app) {
if (config('app.env') === 'memory') {
return new LocalAttemptsRepository();
return $app->make(LocalAttemptsRepository::class);
}
if (config('app.env') === 'testing') {
return new InMemoryAttemptsRepository();
return $app->make(InMemoryAttemptsRepository::class);
}
return new DatabaseAttemptsRepository();
return $app->make(DatabaseAttemptsRepository::class);
});
}
/**
* @return array
*/
public function provides()
public function provides(): array
{
return [AttemptsRepository::class];
}
......
......@@ -4,11 +4,7 @@
namespace Source\Gateways\DoorGroup;
use Illuminate\Support\ServiceProvider;
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;
/**
......@@ -21,31 +17,25 @@ class DoorGroupRepositoryServiceProvider extends ServiceProvider implements Defe
*
* @return void
*/
public function register()
public function register(): void
{
$this->app->singleton(DoorGroupRepository::class, static function (Application $app) {
if (config('app.env') === 'memory') {
return new LocalDoorGroupRepository(
new LocalDoorsRepository(),
new LocalGroupsRepository()
);
return $app->make(LocalDoorGroupRepository::class);
}
if (config('app.env') === 'testing') {
return new InMemoryDoorGroupRepository(
$app->make(DoorsRepository::class),
$app->make(GroupsRepository::class)
);
return $app->make(InMemoryDoorGroupRepository::class);
}
return new DatabaseDoorGroupRepository();
return $app->make(DatabaseDoorGroupRepository::class);
});
}
/**
* @return array
*/
public function provides()
public function provides(): array
{
return [DoorGroupRepository::class];
}
......
......@@ -22,11 +22,10 @@ class DatabaseDoorScheduleRepository implements DoorScheduleRepository
$this->db = $db;
}
protected function createScheduleFromObject($schedule): Schedule
public static function createScheduleFromObject($schedule): Schedule
{
return new Schedule(
$schedule->id,
$schedule->group_id,
$schedule->type,
$schedule->rset,
$schedule->duration,
......@@ -45,9 +44,10 @@ class DatabaseDoorScheduleRepository implements DoorScheduleRepository
{
$type = Schedule::TYPE_OPEN_MODE;
$query = <<<QUERY
select S.id, S.group_id, S.type, S.rset, S.start, S.end, S.duration, S.description, S.created_at, S.updated_at
select S.id, S.type, S.rset, S.start, S.end, S.duration, S.description, S.created_at, S.updated_at
FROM schedules as S
INNER JOIN door_group AS DG ON DG.group_id = S.group_id AND DG.door_id = :DOOR_ID
INNER JOIN door_group AS DG ON DG.door_id = :DOOR_ID
INNER JOIN group_schedule AS GS on S.id = GS.schedule_id AND GS.group_id = DG.group_id
WHERE S.type = :TYPE AND ((CURRENT_DATE BETWEEN S.start AND S.end) OR (CURRENT_DATE > S.start AND S.end IS NULL))
QUERY;
......@@ -67,9 +67,10 @@ QUERY;
public function getSchedulesForDoorBetween(string $doorId, Carbon $begin, Carbon $end, int $type = Schedule::TYPE_OPEN_MODE): array
{
$query = <<<QUERY
select S.id, S.group_id, S.type, S.rset, S.start, S.end, S.duration, S.description, S.created_at, S.updated_at
select S.id, S.type, S.rset, S.start, S.end, S.duration, S.description, S.created_at, S.updated_at
FROM schedules as S
INNER JOIN door_group AS DG ON DG.group_id = S.group_id AND DG.door_id = :DOOR_ID
INNER JOIN door_group AS DG ON DG.door_id = :DOOR_ID
INNER JOIN group_schedule AS GS on S.id = GS.schedule_id AND GS.group_id = DG.group_id
WHERE S.type = :TYPE AND (((:BEGIN, :END) OVERLAPS (s.start, S.end))
OR (S.start < :END AND S.end IS NULL))
QUERY;
......@@ -92,10 +93,11 @@ QUERY;
public function getSchedulesForDoorAndUserBetween(string $doorId, string $userId, Carbon $begin, Carbon $end): array
{
$query = <<<QUERY
select S.id, S.group_id, S.type, S.rset, S.start, S.end, S.duration, S.description, S.created_at, S.updated_at
select S.id, S.type, S.rset, S.start, S.end, S.duration, S.description, S.created_at, S.updated_at
FROM schedules as S
INNER JOIN door_group AS DG ON DG.group_id = S.group_id AND DG.door_id = :DOOR_ID
INNER JOIN group_user as GU ON GU.group_id = S.group_id AND GU.user_id = :USER_ID
INNER JOIN group_schedule AS GS ON GS.schedule_id = S.id
INNER JOIN door_group AS DG ON DG.group_id = GS.group_id AND DG.door_id = :DOOR_ID
INNER JOIN group_user as GU ON GU.group_id = GS.group_id AND GU.user_id = :USER_ID
WHERE S.type = :TYPE AND (((:BEGIN, :END) OVERLAPS (s.start, S.end))
OR (S.start < :END AND S.end IS NULL))
QUERY;
......@@ -108,8 +110,6 @@ QUERY;
':END' => $end,
]);
return array_map(function ($schedule) {
return $this->createScheduleFromObject($schedule);
}, $schedules);
return array_map(fn ($schedule): Schedule => self::createScheduleFromObject($schedule), $schedules);
}
}
......@@ -4,11 +4,7 @@
namespace Source\Gateways\DoorSchedule;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\DatabaseManager;
use Source\Gateways\Doors\DoorsRepository;
use Illuminate\Contracts\Foundation\Application;
use Source\Gateways\DoorGroup\DoorGroupRepository;
use Source\Gateways\Schedules\SchedulesRepository;
use Illuminate\Contracts\Support\DeferrableProvider;
/**
......@@ -21,32 +17,25 @@ class DoorScheduleRepositoryServiceProvider extends ServiceProvider implements D
*
* @return void
*/
public function register()
public function register(): void
{
$this->app->singleton(DoorScheduleRepository::class, static function (Application $app) {
if (config('app.env') === 'memory') {
return new LocalDoorScheduleRepository(
$app->make(DoorsRepository::class),
$app->make(DoorGroupRepository::class),
$app->make(SchedulesRepository::class)
);
return $app->make(LocalDoorScheduleRepository::class);
}
if (config('app.env') === 'testing') {
return new InMemoryDoorScheduleRepository();
return $app->make(InMemoryDoorScheduleRepository::class);
}
/** @var DatabaseManager $manager */
$manager = $app->make(DatabaseManager::class);
return new DatabaseDoorScheduleRepository($manager->connection('doorcode'));
return $app->make(DatabaseDoorScheduleRepository::class);
});
}
/**
* @return array
*/
public function provides()
public function provides(): array
{
return [DoorScheduleRepository::class];
}
......
......@@ -31,7 +31,9 @@ class InMemoryDoorScheduleRepository implements DoorScheduleRepository
return [];
}
return $this->doorScheduleMap[$doorId];
$now = Carbon::now();
return array_filter($this->doorScheduleMap[$doorId], fn (Schedule $schedule): bool => $schedule->isActiveForDate($now));
}
/**
......
......@@ -6,11 +6,11 @@ namespace Source\Gateways\DoorSchedule;
use Source\Gateways\Doors\DoorsRepository;
use Source\Exceptions\EntityNotFoundException;
use Source\Gateways\DoorGroup\DoorGroupRepository;
use Source\Gateways\Schedules\SchedulesRepository;
use Source\Gateways\GroupSchedule\GroupScheduleRepository;
class LocalDoorScheduleRepository extends InMemoryDoorScheduleRepository
{
public function __construct(DoorsRepository $doors, DoorGroupRepository $doorGroups, SchedulesRepository $schedules)
public function __construct(DoorsRepository $doors, DoorGroupRepository $doorGroups, GroupScheduleRepository $schedules)
{
/*
* So we need to connect the schedules up to the doors here.
......@@ -21,7 +21,7 @@ class LocalDoorScheduleRepository extends InMemoryDoorScheduleRepository
try {
foreach ($doors->search() as $door) {
foreach ($doorGroups->getGroupsForDoor($door->getId()) as $group) {
foreach ($schedules->filter($group->getId()) as $schedule) {
foreach ($schedules->getSchedulesForGroup($group->getId()) as $schedule) {
$this->attachScheduleToDoor($door->getId(), $schedule);
}
}
......
......@@ -4,12 +4,7 @@
namespace Source\Gateways\DoorUser;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\DatabaseManager;
use Source\Gateways\Doors\DoorsRepository;
use Source\Gateways\Users\UsersRepository;
use Illuminate\Contracts\Foundation\Application;