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);
}
}