diff --git a/includes/controller/angeltypes_controller.php b/includes/controller/angeltypes_controller.php index 3d61c7fc..741f8afb 100644 --- a/includes/controller/angeltypes_controller.php +++ b/includes/controller/angeltypes_controller.php @@ -175,7 +175,9 @@ function angeltype_controller() $angeltype = AngelType::findOrFail(request()->input('angeltype_id')); /** @var UserAngelType $user_angeltype */ $user_angeltype = UserAngelType::whereUserId($user->id)->where('angel_type_id', $angeltype->id)->first(); - $members = $angeltype->userAngelTypes->sortBy('name', SORT_NATURAL | SORT_FLAG_CASE); + $members = $angeltype->userAngelTypes + ->sortBy('name', SORT_NATURAL | SORT_FLAG_CASE) + ->load(['state', 'personalData', 'contact']); $days = angeltype_controller_shiftsFilterDays($angeltype); $shiftsFilter = angeltype_controller_shiftsFilter($angeltype, $days); if (request()->input('showFilledShifts')) { diff --git a/includes/controller/users_controller.php b/includes/controller/users_controller.php index cb94560a..2e92ccae 100644 --- a/includes/controller/users_controller.php +++ b/includes/controller/users_controller.php @@ -7,6 +7,7 @@ use Engelsystem\Models\User\User; use Engelsystem\ShiftCalendarRenderer; use Engelsystem\ShiftsFilter; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Support\Str; /** @@ -297,13 +298,15 @@ function users_list_controller() } /** @var User[]|Collection $users */ - $users = User::with(['contact', 'personalData', 'state']) + $users = User::with(['contact', 'personalData', 'state', 'shiftEntries' => function (HasMany $query) { + $query->where('freeloaded', true); + }]) ->orderBy('name') ->get(); foreach ($users as $user) { $user->setAttribute( 'freeloads', - $user->shiftEntries() + $user->shiftEntries ->where('freeloaded', true) ->count() ); diff --git a/includes/model/Shifts_model.php b/includes/model/Shifts_model.php index 8443514f..ff2c9dd2 100644 --- a/includes/model/Shifts_model.php +++ b/includes/model/Shifts_model.php @@ -116,7 +116,7 @@ function Shifts_free($start, $end, ShiftsFilter $filter = null) $shifts = collect($shifts); - return Shift::query() + return Shift::with(['location', 'shiftType']) ->whereIn('id', $shifts->pluck('id')->toArray()) ->orderBy('shifts.start') ->get(); @@ -189,12 +189,14 @@ function Shifts_by_ShiftsFilter(ShiftsFilter $shiftsFilter) ] ); - $shifts = []; + $shifts = new Collection(); foreach ($shiftsData as $shift) { $shifts[] = (new Shift())->forceFill($shift); } - return collect($shifts); + $shifts->load(['location', 'shiftType']); + + return $shifts; } /** @@ -354,7 +356,7 @@ function NeededAngeltype_by_Shift_and_Angeltype(Shift $shift, AngelType $angelty */ function ShiftEntries_by_ShiftsFilter(ShiftsFilter $shiftsFilter) { - return ShiftEntry::with('user') + return ShiftEntry::with('user', 'user.state') ->join('shifts', 'shifts.id', 'shift_entries.shift_id') ->whereIn('shifts.location_id', $shiftsFilter->getLocations()) ->whereBetween('start', [$shiftsFilter->getStart(), $shiftsFilter->getEnd()]) @@ -638,12 +640,13 @@ function Shifts_by_user($userId, $include_freeloaded_comments = false) ] ); - $shifts = []; + $shifts = new Collection(); foreach ($shiftsData as $data) { $shifts[] = (new Shift())->forceFill($data); } + $shifts->load(['shiftType', 'location']); - return collect($shifts); + return $shifts; } /** diff --git a/includes/model/UserWorkLog_model.php b/includes/model/UserWorkLog_model.php index a15c7969..a6413f78 100644 --- a/includes/model/UserWorkLog_model.php +++ b/includes/model/UserWorkLog_model.php @@ -18,6 +18,7 @@ function UserWorkLogsForUser($userId, Carbon $sinceTime = null) if ($sinceTime) { $worklogs = $worklogs->whereDate('worked_at', '>=', $sinceTime); } + $worklogs->with(['user', 'creator']); return $worklogs->get(); } diff --git a/includes/pages/admin_active.php b/includes/pages/admin_active.php index 6e036c4d..a1fe103c 100644 --- a/includes/pages/admin_active.php +++ b/includes/pages/admin_active.php @@ -151,7 +151,7 @@ function admin_active() } } - $query = User::with('personalData') + $query = User::with(['personalData', 'state']) ->selectRaw( sprintf( ' diff --git a/includes/pages/admin_arrive.php b/includes/pages/admin_arrive.php index fa3c877e..fa590980 100644 --- a/includes/pages/admin_arrive.php +++ b/includes/pages/admin_arrive.php @@ -65,7 +65,7 @@ function admin_arrive() } /** @var User[] $users */ - $users = User::with('personalData')->orderBy('name')->get(); + $users = User::with(['personalData', 'state'])->orderBy('name')->get(); $arrival_count_at_day = []; $planned_arrival_count_at_day = []; $planned_departure_count_at_day = []; diff --git a/includes/pages/admin_free.php b/includes/pages/admin_free.php index 505d6974..b40d9782 100644 --- a/includes/pages/admin_free.php +++ b/includes/pages/admin_free.php @@ -40,7 +40,7 @@ function admin_free() /** @var User[] $users */ $users = []; if ($request->has('submit')) { - $query = User::with('personalData') + $query = User::with(['personalData', 'contact', 'state']) ->select('users.*') ->leftJoin('shift_entries', 'users.id', 'shift_entries.user_id') ->leftJoin('users_state', 'users.id', 'users_state.user_id') diff --git a/includes/pages/admin_groups.php b/includes/pages/admin_groups.php index c8539274..62ea115a 100644 --- a/includes/pages/admin_groups.php +++ b/includes/pages/admin_groups.php @@ -21,13 +21,13 @@ function admin_groups() $html = ''; $request = request(); /** @var Group[]|Collection $groups */ - $groups = Group::query()->orderBy('name')->get(); + $groups = Group::with('privileges')->orderBy('name')->get(); if (!$request->has('action')) { $groups_table = []; foreach ($groups as $group) { /** @var Privilege[]|Collection $privileges */ - $privileges = $group->privileges()->orderBy('name')->get(); + $privileges = $group->privileges->sortBy('name'); $privileges_html = []; foreach ($privileges as $privilege) { diff --git a/includes/pages/admin_shifts.php b/includes/pages/admin_shifts.php index bedc32be..f435cec2 100644 --- a/includes/pages/admin_shifts.php +++ b/includes/pages/admin_shifts.php @@ -326,6 +326,9 @@ function admin_shifts() $shifts_table = []; foreach ($shifts as $shift) { + $shiftType = $shifttypes_source->find($shift['shift_type_id']); + $location = $locations->find($shift['location_id']); + /** @var Carbon $start */ $start = $shift['start']; /** @var Carbon $end */ @@ -340,9 +343,9 @@ function admin_shifts() . '' . ', ' . round($end->copy()->diffInMinutes($start) / 60, 2) . 'h' . '
' - . location_name_render(Location::find($shift['location_id'])), + . location_name_render($location), 'title' => - htmlspecialchars(ShiftType::find($shifttype_id)->name) + htmlspecialchars($shiftType->name) . ($shift['title'] ? '
' . htmlspecialchars($shift['title']) : ''), 'needed_angels' => '', ]; diff --git a/includes/pages/schedule/ImportSchedule.php b/includes/pages/schedule/ImportSchedule.php index b6ce626d..fed44373 100644 --- a/includes/pages/schedule/ImportSchedule.php +++ b/includes/pages/schedule/ImportSchedule.php @@ -552,8 +552,7 @@ class ImportSchedule extends BaseController $existingShifts = $this->getScheduleShiftsByGuid($scheduleUrl, $scheduleEventsGuidList); foreach ($existingShifts as $scheduleShift) { $guid = $scheduleShift->guid; - /** @var Shift $shift */ - $shift = Shift::with('location')->find($scheduleShift->shift_id); + $shift = $scheduleShift->shift; $event = $scheduleEvents[$guid]; $location = $locations->where('name', $event->getRoom()->getName())->first(); @@ -620,7 +619,7 @@ class ImportSchedule extends BaseController */ protected function getScheduleShiftsByGuid(ScheduleUrl $scheduleUrl, array $events) { - return ScheduleShift::query() + return ScheduleShift::with('shift.location') ->whereIn('guid', $events) ->where('schedule_id', $scheduleUrl->id) ->get(); @@ -633,7 +632,7 @@ class ImportSchedule extends BaseController */ protected function getScheduleShiftsWhereNotGuid(ScheduleUrl $scheduleUrl, array $events) { - return ScheduleShift::query() + return ScheduleShift::with('shift.location') ->whereNotIn('guid', $events) ->where('schedule_id', $scheduleUrl->id) ->get(); diff --git a/includes/pages/user_shifts.php b/includes/pages/user_shifts.php index 63b5fb9e..c1710e04 100644 --- a/includes/pages/user_shifts.php +++ b/includes/pages/user_shifts.php @@ -297,7 +297,6 @@ function view_user_shifts() return page([ div('col-md-12', [ - msg(), view(__DIR__ . '/../../resources/views/pages/user-shifts.html', [ 'title' => shifts_title(), 'add_link' => auth()->can('admin_shifts') ? $link : '', diff --git a/src/Controllers/Admin/QuestionsController.php b/src/Controllers/Admin/QuestionsController.php index c033bdb4..cf6d7be9 100644 --- a/src/Controllers/Admin/QuestionsController.php +++ b/src/Controllers/Admin/QuestionsController.php @@ -38,7 +38,8 @@ class QuestionsController extends BaseController $questions = $this->question ->orderBy('answered_at') ->orderByDesc('created_at') - ->get(); + ->get() + ->load(['user.state', 'answerer.state']); return $this->response->withView( 'pages/questions/overview.twig', diff --git a/src/Controllers/MessagesController.php b/src/Controllers/MessagesController.php index 2aef9b51..7a339e6f 100644 --- a/src/Controllers/MessagesController.php +++ b/src/Controllers/MessagesController.php @@ -218,7 +218,8 @@ class MessagesController extends BaseController $join->on('messages.id', '=', 'conversations.last_id'); }) ->orderBy('created_at', 'DESC') - ->get(); + ->get() + ->load(['receiver.personalData', 'receiver.state']); } protected function raw(mixed $value): QueryExpression diff --git a/src/Controllers/NewsController.php b/src/Controllers/NewsController.php index 69f35f80..8c001e4a 100644 --- a/src/Controllers/NewsController.php +++ b/src/Controllers/NewsController.php @@ -53,8 +53,7 @@ class NewsController extends BaseController $newsId = (int) $request->getAttribute('news_id'); $news = $this->news - ->with('user') - ->with('comments') + ->with(['user', 'comments.user.state', 'comments.user.personalData']) ->findOrFail($newsId); return $this->renderView('pages/news/news.twig', ['news' => $news]); diff --git a/src/Controllers/QuestionsController.php b/src/Controllers/QuestionsController.php index 85b28489..f336686d 100644 --- a/src/Controllers/QuestionsController.php +++ b/src/Controllers/QuestionsController.php @@ -36,7 +36,8 @@ class QuestionsController extends BaseController ->whereUserId($this->auth->user()->id) ->orderByDesc('answered_at') ->orderBy('created_at') - ->get(); + ->get() + ->load(['user.state', 'answerer.state']); return $this->response->withView( 'pages/questions/overview.twig', diff --git a/src/Helpers/Authenticator.php b/src/Helpers/Authenticator.php index b5459dcc..1c7e056f 100644 --- a/src/Helpers/Authenticator.php +++ b/src/Helpers/Authenticator.php @@ -42,7 +42,7 @@ class Authenticator } $this->user = $this->userFromSession(); - if (!$this->user && request()->getAttribute('route-api-accessible', false)) { + if (!$this->user && $this->isApiRequest()) { $this->user = $this->userFromApi(); } @@ -102,8 +102,10 @@ class Authenticator if ($user) { $this->permissions = $user->privileges->pluck('name')->toArray(); - $user->last_login_at = new Carbon(); - $user->save(); + if ($user->last_login_at < Carbon::now()->subMinutes(5) && !$this->isApiRequest()) { + $user->last_login_at = Carbon::now(); + $user->save(['touch' => false]); + } } elseif ($this->session->get('user_id')) { $this->session->remove('user_id'); } @@ -206,6 +208,11 @@ class Authenticator return $this->user; } + protected function isApiRequest(): bool + { + return (bool) request()->getAttribute('route-api-accessible', false); + } + public function setPassword(User $user, string $password): void { $user->password = password_hash($password, $this->passwordAlgorithm); diff --git a/src/Renderer/Twig/Extensions/Globals.php b/src/Renderer/Twig/Extensions/Globals.php index fb7c9a8a..fbefa090 100644 --- a/src/Renderer/Twig/Extensions/Globals.php +++ b/src/Renderer/Twig/Extensions/Globals.php @@ -14,6 +14,8 @@ use function array_key_exists; class Globals extends TwigExtension implements GlobalsInterface { + protected array $globals = []; + public function __construct(protected Authenticator $auth, protected Request $request) { } @@ -22,6 +24,18 @@ class Globals extends TwigExtension implements GlobalsInterface * Returns a list of global variables to add to the existing list. */ public function getGlobals(): array + { + if (empty($this->globals)) { + $this->globals = $this->getGlobalValues(); + } + + return $this->globals; + } + + /** + * Generates the list of global variables + */ + protected function getGlobalValues(): array { $user = $this->auth->user(); $themes = config('themes'); diff --git a/tests/Unit/Helpers/AuthenticatorTest.php b/tests/Unit/Helpers/AuthenticatorTest.php index 0369ebc0..f2bf4d3c 100644 --- a/tests/Unit/Helpers/AuthenticatorTest.php +++ b/tests/Unit/Helpers/AuthenticatorTest.php @@ -207,6 +207,7 @@ class AuthenticatorTest extends ServiceProviderTest /** * @covers \Engelsystem\Helpers\Authenticator::can + * @covers \Engelsystem\Helpers\Authenticator::isApiRequest */ public function testCan(): void { diff --git a/tests/Unit/Renderer/Twig/Extensions/GlobalsTest.php b/tests/Unit/Renderer/Twig/Extensions/GlobalsTest.php index b005034d..1f3d01b6 100644 --- a/tests/Unit/Renderer/Twig/Extensions/GlobalsTest.php +++ b/tests/Unit/Renderer/Twig/Extensions/GlobalsTest.php @@ -31,6 +31,7 @@ class GlobalsTest extends ExtensionTest /** * @covers \Engelsystem\Renderer\Twig\Extensions\Globals::__construct * @covers \Engelsystem\Renderer\Twig\Extensions\Globals::getGlobals + * @covers \Engelsystem\Renderer\Twig\Extensions\Globals::getGlobalValues */ public function testGetGlobals(): void { @@ -82,6 +83,7 @@ class GlobalsTest extends ExtensionTest $this->assertGlobalsExists('theme', $theme2, $globals); // User + $extension = new Globals($auth, $request); $globals = $extension->getGlobals(); $this->assertGlobalsExists('user', $user, $globals); $this->assertGlobalsExists('user_messages', 0, $globals); @@ -89,15 +91,21 @@ class GlobalsTest extends ExtensionTest $this->assertGlobalsExists('theme', $theme, $globals); // User with not available theme configured + $extension = new Globals($auth, $request); $user->settings->theme = 9999; $globals = $extension->getGlobals(); $this->assertGlobalsExists('themeId', 42, $globals); // Request query parameter + $extension = new Globals($auth, $request); $request->query->set('theme', 1337); $globals = $extension->getGlobals(); $this->assertGlobalsExists('user', [], $globals); $this->assertGlobalsExists('themeId', 1337, $globals); $this->assertGlobalsExists('theme', $theme3, $globals); + + // Second retrieval is loaded directly + $globals = $extension->getGlobals(); + $this->assertGlobalsExists('themeId', 1337, $globals); } }