2023-12-16 20:11:41 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace Engelsystem\Controllers;
|
|
|
|
|
|
|
|
use Engelsystem\Helpers\Carbon;
|
|
|
|
use Engelsystem\Http\Redirector;
|
|
|
|
use Engelsystem\Http\Response;
|
|
|
|
use Engelsystem\Helpers\Authenticator;
|
|
|
|
use Engelsystem\Http\UrlGeneratorInterface;
|
|
|
|
use Engelsystem\Models\Shifts\Shift;
|
2023-12-26 12:54:21 +01:00
|
|
|
use Engelsystem\Models\Shifts\ShiftEntry;
|
2023-12-16 20:11:41 +01:00
|
|
|
use Engelsystem\Models\User\User;
|
2023-12-26 12:54:21 +01:00
|
|
|
use Illuminate\Contracts\Database\Query\Builder as QueryBuilder;
|
2023-12-16 20:11:41 +01:00
|
|
|
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
|
|
|
use Illuminate\Database\Eloquent\Collection as DbCollection;
|
|
|
|
use Illuminate\Database\Query\JoinClause;
|
|
|
|
use Illuminate\Support\Collection;
|
|
|
|
use Illuminate\Database\Query\Builder;
|
|
|
|
|
|
|
|
class ShiftsController extends BaseController
|
|
|
|
{
|
|
|
|
use HasUserNotifications;
|
|
|
|
|
|
|
|
/** @var string[] */
|
|
|
|
protected array $permissions = [
|
|
|
|
'user_shifts',
|
|
|
|
];
|
|
|
|
|
|
|
|
public function __construct(
|
|
|
|
protected Authenticator $auth,
|
|
|
|
protected Redirector $redirect,
|
|
|
|
protected UrlGeneratorInterface $url,
|
|
|
|
) {
|
|
|
|
}
|
|
|
|
|
|
|
|
public function random(): Response
|
|
|
|
{
|
|
|
|
$user = $this->auth->user();
|
|
|
|
$nextFreeShifts = $this->getNextFreeShifts($user);
|
|
|
|
|
|
|
|
if ($nextFreeShifts->isEmpty()) {
|
|
|
|
$this->addNotification('notification.shift.no_next_found', NotificationType::WARNING);
|
|
|
|
return $this->redirect->to($this->url->to('/shifts'));
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var Shift $randomShift */
|
|
|
|
$randomShift = $nextFreeShifts
|
|
|
|
->collect()
|
|
|
|
// Prefer soon starting shifts
|
|
|
|
->groupBy('start')
|
|
|
|
->first()
|
|
|
|
// Select one at random
|
|
|
|
->random();
|
|
|
|
|
|
|
|
return $this->redirect->to($this->url->to('/shifts', ['action' => 'view', 'shift_id' => $randomShift->id]));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getNextFreeShifts(User $user): Collection | DbCollection
|
|
|
|
{
|
|
|
|
$angelTypes = $user
|
|
|
|
->userAngelTypes()
|
|
|
|
->select('angel_types.id')
|
|
|
|
->whereNested(function (Builder $query): void {
|
|
|
|
$query
|
|
|
|
->where('angel_types.restricted', false)
|
|
|
|
->orWhereNot('confirm_user_id', false);
|
|
|
|
});
|
2023-12-26 12:54:21 +01:00
|
|
|
/** @var ShiftEntry[]|DbCollection $shiftEntries */
|
|
|
|
$shiftEntries = $user->shiftEntries()->with('shift')->get();
|
2023-12-16 20:11:41 +01:00
|
|
|
|
|
|
|
$freeShifts = Shift::query()
|
|
|
|
->select('shifts.*')
|
|
|
|
// Load needed from shift if no schedule configured, else from room
|
|
|
|
->leftJoin('schedule_shift', 'schedule_shift.shift_id', '=', 'shifts.id')
|
|
|
|
->leftJoin('needed_angel_types', function (JoinClause $query): void {
|
|
|
|
$query->on('needed_angel_types.shift_id', '=', 'shifts.id')
|
|
|
|
->whereNull('schedule_shift.shift_id');
|
|
|
|
})
|
|
|
|
->leftJoin('needed_angel_types AS nas', function (JoinClause $query): void {
|
|
|
|
$query->on('nas.location_id', '=', 'shifts.location_id')
|
|
|
|
->whereNotNull('schedule_shift.shift_id');
|
|
|
|
})
|
|
|
|
// Not already signed in
|
2023-12-26 12:54:21 +01:00
|
|
|
->whereNotIn('shifts.id', $shiftEntries->pluck('shift_id'))
|
2023-12-16 20:11:41 +01:00
|
|
|
// Same angel types
|
|
|
|
->where(function (EloquentBuilder $query) use ($angelTypes): void {
|
|
|
|
$query
|
|
|
|
->whereIn('needed_angel_types.angel_type_id', $angelTypes)
|
|
|
|
->orWhereIn('nas.angel_type_id', $angelTypes);
|
|
|
|
})
|
|
|
|
// Starts soon
|
|
|
|
->where('shifts.start', '>', Carbon::now())
|
|
|
|
// Where help needed
|
|
|
|
->where(function (Builder $query): void {
|
|
|
|
$query
|
|
|
|
->from('shift_entries')
|
|
|
|
->selectRaw('COUNT(*)')
|
|
|
|
->where(fn(Builder $query) => $this->queryShiftEntries($query));
|
|
|
|
}, '<', Shift::query()->raw('COALESCE(needed_angel_types.count, nas.count)'))
|
|
|
|
->limit(10)
|
|
|
|
->orderBy('start');
|
|
|
|
|
2023-12-26 12:54:21 +01:00
|
|
|
foreach ($shiftEntries as $entry) {
|
|
|
|
$freeShifts->where(function (QueryBuilder $query) use ($entry) {
|
|
|
|
$query->where('end', '<=', $entry->shift->start);
|
|
|
|
$query->orWhere('start', '>=', $entry->shift->end);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-12-16 20:11:41 +01:00
|
|
|
return $freeShifts->get();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function queryShiftEntries(Builder $query): void
|
|
|
|
{
|
|
|
|
$query->select('id')
|
|
|
|
->from('shift_entries')
|
|
|
|
->where(function (Builder $query): void {
|
|
|
|
$query->where('shift_entries.shift_id', $query->raw('needed_angel_types.shift_id'))
|
|
|
|
->where('shift_entries.angel_type_id', $query->raw('needed_angel_types.angel_type_id'));
|
|
|
|
})
|
|
|
|
->orWhere(function (Builder $query): void {
|
|
|
|
$query->where('shift_entries.shift_id', $query->raw('nas.shift_id'))
|
|
|
|
->where('shift_entries.angel_type_id', $query->raw('nas.angel_type_id'));
|
|
|
|
})
|
|
|
|
->groupBy(['shift_entries.shift_id', 'shift_entries.angel_type_id']);
|
|
|
|
}
|
|
|
|
}
|