From 89dc85c3d5f99c194296ad592d4c90413249538c Mon Sep 17 00:00:00 2001
From: Igor Scheller
Date: Wed, 18 Jan 2023 13:02:11 +0100
Subject: [PATCH] Add ShiftEntry model
---
db/factories/Shifts/ShiftEntryFactory.php | 29 +++
...2_30_000000_create_shift_entries_table.php | 114 +++++++++
.../public_dashboard_controller.php | 4 +-
.../controller/shift_entries_controller.php | 76 +++---
includes/controller/shifts_controller.php | 53 ++--
includes/controller/users_controller.php | 37 +--
includes/mailer/shifts_mailer.php | 11 +-
includes/model/NeededAngelTypes_model.php | 9 +-
includes/model/ShiftEntry_model.php | 239 +++---------------
includes/model/Shifts_model.php | 106 +++-----
includes/model/Stats.php | 41 +--
includes/model/User_model.php | 25 +-
includes/pages/admin_active.php | 12 +-
includes/pages/admin_free.php | 4 +-
includes/pages/admin_rooms.php | 5 +-
includes/pages/admin_shifts.php | 9 +-
includes/pages/schedule/ImportSchedule.php | 8 +-
includes/pages/user_ical.php | 4 +-
includes/pages/user_myshifts.php | 69 ++---
includes/pages/user_shifts.php | 2 +-
includes/view/ShiftCalendarRenderer.php | 12 +-
includes/view/ShiftCalendarShiftRenderer.php | 32 +--
includes/view/ShiftEntry_view.php | 14 +-
includes/view/Shifts_view.php | 44 ++--
includes/view/User_view.php | 54 ++--
src/Controllers/Metrics/Stats.php | 42 ++-
src/Models/AngelType.php | 34 ++-
src/Models/Shifts/Shift.php | 44 ++--
src/Models/Shifts/ShiftEntry.php | 63 +++++
src/Models/User/User.php | 15 ++
src/Renderer/TwigServiceProvider.php | 5 +-
tests/Unit/Controllers/Metrics/StatsTest.php | 53 ++++
tests/Unit/FactoriesTest.php | 2 +
tests/Unit/Models/AngelTypeTest.php | 16 +-
tests/Unit/Models/Shifts/ShiftEntryTest.php | 37 +++
tests/Unit/Models/Shifts/ShiftTest.php | 15 ++
tests/Unit/Models/User/UserTest.php | 39 +++
.../Twig/Extensions/ExtensionTest.php | 2 +-
.../Unit/Renderer/TwigServiceProviderTest.php | 13 +-
39 files changed, 787 insertions(+), 606 deletions(-)
create mode 100644 db/factories/Shifts/ShiftEntryFactory.php
create mode 100644 db/migrations/2022_12_30_000000_create_shift_entries_table.php
create mode 100644 src/Models/Shifts/ShiftEntry.php
create mode 100644 tests/Unit/Models/Shifts/ShiftEntryTest.php
diff --git a/db/factories/Shifts/ShiftEntryFactory.php b/db/factories/Shifts/ShiftEntryFactory.php
new file mode 100644
index 00000000..23b3227d
--- /dev/null
+++ b/db/factories/Shifts/ShiftEntryFactory.php
@@ -0,0 +1,29 @@
+faker->optional(.01, false)->boolean();
+
+ return [
+ 'shift_id' => Shift::factory(),
+ 'angel_type_id' => AngelType::factory(),
+ 'user_id' => User::factory(),
+ 'user_comment' => $this->faker->optional(.05, '')->text(),
+ 'freeloaded' => $freeloaded,
+ 'freeloaded_comment' => $freeloaded ? $this->faker->text() : '',
+ ];
+ }
+}
diff --git a/db/migrations/2022_12_30_000000_create_shift_entries_table.php b/db/migrations/2022_12_30_000000_create_shift_entries_table.php
new file mode 100644
index 00000000..b798a33d
--- /dev/null
+++ b/db/migrations/2022_12_30_000000_create_shift_entries_table.php
@@ -0,0 +1,114 @@
+schema->getConnection();
+ $previous = $this->schema->hasTable('ShiftEntry');
+
+ $this->schema->create('shift_entries', function (Blueprint $table): void {
+ $table->increments('id');
+ $this->references($table, 'shifts');
+ $this->references($table, 'angel_types');
+ $this->referencesUser($table);
+
+ $table->mediumText('user_comment')->default('');
+
+ $table->boolean('freeloaded')->default(false)->index();
+ $table->mediumText('freeloaded_comment')->default('');
+
+ $table->index(['angel_type_id', 'shift_id']);
+ });
+
+ if (!$previous) {
+ return;
+ }
+
+ /** @var stdClass[] $records */
+ $records = $connection
+ ->table('ShiftEntry')
+ ->get();
+ foreach ($records as $record) {
+ $connection->table('shift_entries')->insert([
+ 'id' => $record->id,
+ 'shift_id' => $record->SID,
+ 'angel_type_id' => $record->TID,
+ 'user_id' => $record->UID,
+ 'user_comment' => $record->Comment,
+ 'freeloaded' => (bool) $record->freeloaded,
+ 'freeloaded_comment' => $record->freeload_comment,
+ ]);
+ }
+
+ $this->changeReferences(
+ 'ShiftEntry',
+ 'id',
+ 'shift_entries',
+ 'id'
+ );
+
+ $this->schema->drop('ShiftEntry');
+ }
+
+ /**
+ * Recreates the previous table, copies the data and drops the new one
+ */
+ public function down(): void
+ {
+ $connection = $this->schema->getConnection();
+
+ $this->schema->create('ShiftEntry', function (Blueprint $table): void {
+ $table->increments('id');
+ $this->references($table, 'shifts', 'SID')->default(0);
+ $this->references($table, 'angel_types', 'TID')->default(0);
+ $this->references($table, 'users', 'UID')->default(0);
+
+ $table->mediumText('Comment')->nullable();
+
+ $table->mediumText('freeload_comment')->nullable()->default(null);
+ $table->boolean('freeloaded')->index();
+
+ $table->index(['SID', 'TID']);
+ });
+
+ /** @var stdClass[] $records */
+ $records = $connection
+ ->table('shift_entries')
+ ->get();
+ foreach ($records as $record) {
+ $connection->table('ShiftEntry')->insert([
+ 'id' => $record->id,
+ 'SID' => $record->shift_id,
+ 'TID' => $record->angel_type_id,
+ 'UID' => $record->user_id,
+ 'Comment' => $record->user_comment,
+ 'freeloaded' => (bool) $record->freeloaded,
+ 'freeload_comment' => $record->freeloaded_comment,
+ ]);
+ }
+
+ $this->changeReferences(
+ 'shift_entries',
+ 'id',
+ 'ShiftEntry',
+ 'id'
+ );
+
+ $this->schema->drop('shift_entries');
+ }
+}
diff --git a/includes/controller/public_dashboard_controller.php b/includes/controller/public_dashboard_controller.php
index 4b09732e..823f6a86 100644
--- a/includes/controller/public_dashboard_controller.php
+++ b/includes/controller/public_dashboard_controller.php
@@ -107,8 +107,8 @@ function public_dashboard_needed_angels($needed_angels, ShiftsFilter $filter = n
$result = [];
foreach ($needed_angels as $needed_angel) {
$need = $needed_angel['count'] - $needed_angel['taken'];
- if ($need > 0 && (!$filter || in_array($needed_angel['TID'], $filter->getTypes()))) {
- $angeltype = AngelType::find($needed_angel['TID']);
+ if ($need > 0 && (!$filter || in_array($needed_angel['angel_type_id'], $filter->getTypes()))) {
+ $angeltype = AngelType::find($needed_angel['angel_type_id']);
if ($angeltype->show_on_dashboard) {
$result[] = [
'need' => $need,
diff --git a/includes/controller/shift_entries_controller.php b/includes/controller/shift_entries_controller.php
index a06f4d7f..7cd7b352 100644
--- a/includes/controller/shift_entries_controller.php
+++ b/includes/controller/shift_entries_controller.php
@@ -2,6 +2,7 @@
use Engelsystem\Models\AngelType;
use Engelsystem\Models\Shifts\Shift;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
use Engelsystem\ShiftSignupState;
@@ -27,7 +28,7 @@ function shift_entries_controller(): array
return match ($action) {
'create' => shift_entry_create_controller(),
'delete' => shift_entry_delete_controller(),
- default => ['', ''],
+ default => ['', ''],
};
}
@@ -41,7 +42,7 @@ function shift_entry_create_controller(): array
$user = auth()->user();
$request = request();
- if (User_is_freeloader($user)) {
+ if ($user->isFreeloader()) {
throw_redirect(page_link_to('user_myshifts'));
}
@@ -99,14 +100,12 @@ function shift_entry_create_controller_admin(Shift $shift, ?AngelType $angeltype
}
if ($request->hasPostData('submit')) {
- ShiftEntry_create([
- 'SID' => $shift->id,
- 'TID' => $angeltype->id,
- 'UID' => $signup_user->id,
- 'Comment' => '',
- 'freeloaded' => false,
- 'freeload_comment' => ''
- ]);
+ $shiftEntry = new ShiftEntry();
+ $shiftEntry->shift()->associate($shift);
+ $shiftEntry->angelType()->associate($angeltype);
+ $shiftEntry->user()->associate($signup_user);
+ $shiftEntry->save();
+ ShiftEntry_onCreate($shiftEntry);
success(sprintf(__('%s has been subscribed to the shift.'), User_Nick_render($signup_user)));
throw_redirect(shift_link($shift));
@@ -150,14 +149,12 @@ function shift_entry_create_controller_supporter(Shift $shift, AngelType $angelt
}
if ($request->hasPostData('submit')) {
- ShiftEntry_create([
- 'SID' => $shift->id,
- 'TID' => $angeltype->id,
- 'UID' => $signup_user->id,
- 'Comment' => '',
- 'freeloaded' => false,
- 'freeload_comment' => ''
- ]);
+ $shiftEntry = new ShiftEntry();
+ $shiftEntry->shift()->associate($shift);
+ $shiftEntry->angelType()->associate($angeltype);
+ $shiftEntry->user()->associate($signup_user);
+ $shiftEntry->save();
+ ShiftEntry_onCreate($shiftEntry);
success(sprintf(__('%s has been subscribed to the shift.'), User_Nick_render($signup_user)));
throw_redirect(shift_link($shift));
@@ -214,7 +211,9 @@ function shift_entry_create_controller_user(Shift $shift, AngelType $angeltype):
$signup_user = auth()->user();
$needed_angeltype = (new AngelType())->forceFill(NeededAngeltype_by_Shift_and_Angeltype($shift, $angeltype));
- $shift_entries = ShiftEntries_by_shift_and_angeltype($shift->id, $angeltype->id);
+ $shift_entries = $shift->shiftEntries()
+ ->where('angel_type_id', $angeltype->id)
+ ->get();
$shift_signup_state = Shift_signup_allowed(
$signup_user,
$shift,
@@ -232,14 +231,14 @@ function shift_entry_create_controller_user(Shift $shift, AngelType $angeltype):
$comment = '';
if ($request->hasPostData('submit')) {
$comment = strip_request_item_nl('comment');
- ShiftEntry_create([
- 'SID' => $shift->id,
- 'TID' => $angeltype->id,
- 'UID' => $signup_user->id,
- 'Comment' => $comment,
- 'freeloaded' => false,
- 'freeload_comment' => ''
- ]);
+
+ $shiftEntry = new ShiftEntry();
+ $shiftEntry->shift()->associate($shift);
+ $shiftEntry->angelType()->associate($angeltype);
+ $shiftEntry->user()->associate($signup_user);
+ $shiftEntry->user_comment = $comment;
+ $shiftEntry->save();
+ ShiftEntry_onCreate($shiftEntry);
if (
!$angeltype->restricted
@@ -299,7 +298,7 @@ function shift_entry_create_link_admin(Shift $shift, $params = [])
/**
* Load a shift entry from get parameter shift_entry_id.
*
- * @return array
+ * @return ShiftEntry
*/
function shift_entry_load()
{
@@ -308,11 +307,7 @@ function shift_entry_load()
if (!$request->has('shift_entry_id') || !test_request_int('shift_entry_id')) {
throw_redirect(page_link_to('user_shifts'));
}
- $shiftEntry = ShiftEntry($request->input('shift_entry_id'));
- if (empty($shiftEntry)) {
- error(__('Shift entry not found.'));
- throw_redirect(page_link_to('user_shifts'));
- }
+ $shiftEntry = ShiftEntry::findOrFail($request->input('shift_entry_id'));
return $shiftEntry;
}
@@ -328,9 +323,9 @@ function shift_entry_delete_controller()
$request = request();
$shiftEntry = shift_entry_load();
- $shift = Shift($shiftEntry['SID']);
- $angeltype = AngelType::find($shiftEntry['TID']);
- $signout_user = User::find($shiftEntry['UID']);
+ $shift = Shift($shiftEntry->shift);
+ $angeltype = $shiftEntry->angelType;
+ $signout_user = $shiftEntry->user;
if (!Shift_signout_allowed($shift, $angeltype, $signout_user->id)) {
error(__(
'You are not allowed to remove this shift entry. If necessary, ask your supporter or heaven to do so.'
@@ -339,7 +334,8 @@ function shift_entry_delete_controller()
}
if ($request->hasPostData('delete')) {
- ShiftEntry_delete($shiftEntry);
+ $shiftEntry->delete();
+ ShiftEntry_onDelete($shiftEntry);
success(__('Shift entry removed.'));
throw_redirect(shift_link($shift));
}
@@ -347,7 +343,7 @@ function shift_entry_delete_controller()
if ($user->id == $signout_user->id) {
return [
ShiftEntry_delete_title(),
- ShiftEntry_delete_view($shift, $angeltype, $signout_user->id)
+ ShiftEntry_delete_view($shift, $angeltype, $signout_user)
];
}
@@ -360,8 +356,8 @@ function shift_entry_delete_controller()
/**
* Link to delete a shift entry.
*
- * @param array|Shift $shiftEntry
- * @param array $params
+ * @param Shift|ShiftEntry $shiftEntry
+ * @param array $params
* @return string URL
*/
function shift_entry_delete_link($shiftEntry, $params = [])
diff --git a/includes/controller/shifts_controller.php b/includes/controller/shifts_controller.php
index df582ff6..bbaf2d23 100644
--- a/includes/controller/shifts_controller.php
+++ b/includes/controller/shifts_controller.php
@@ -6,7 +6,6 @@ use Engelsystem\Models\AngelType;
use Engelsystem\Models\Shifts\ScheduleShift;
use Engelsystem\Models\Shifts\Shift;
use Engelsystem\Models\Shifts\ShiftType;
-use Engelsystem\Models\User\User;
use Engelsystem\ShiftSignupState;
use Illuminate\Support\Collection;
@@ -159,7 +158,6 @@ function shift_edit_controller()
$shift->updatedBy()->associate(auth()->user());
// Remove merged data as it is not really part of the model and thus can't be saved
- unset($shift->shiftEntry);
unset($shift->neededAngels);
$shift->save();
@@ -244,24 +242,23 @@ function shift_delete_controller()
// Schicht löschen bestätigt
if ($request->hasPostData('delete')) {
- foreach ($shift->shiftEntry as $entry) {
- $type = AngelType::find($entry['TID']);
+ foreach ($shift->shiftEntries as $entry) {
event('shift.entry.deleting', [
- 'user' => User::find($entry['user_id']),
+ 'user' => $entry->user,
'start' => $shift->start,
'end' => $shift->end,
'name' => $shift->shiftType->name,
'title' => $shift->title,
- 'type' => $type->name,
+ 'type' => $entry->angelType->name,
'room' => $shift->room,
- 'freeloaded' => (bool) $entry['freeloaded'],
+ 'freeloaded' => $entry->freeloaded,
]);
}
$shift->delete();
engelsystem_log(
- 'Deleted shift ' . $shift->title . ': ' . $shift->shiftType->name
+ 'Deleted shift ' . $shift->title . ': ' . $shift->shiftType->name
. ' from ' . $shift->start->format('Y-m-d H:i')
. ' to ' . $shift->end->format('Y-m-d H:i')
);
@@ -318,7 +315,9 @@ function shift_controller()
continue;
}
- $shift_entries = ShiftEntries_by_shift_and_angeltype($shift->id, $angeltype->id);
+ $shift_entries = $shift->shiftEntries()
+ ->where('angel_type_id', $angeltype->id)
+ ->get();
$needed_angeltype = (new AngelType())->forceFill($needed_angeltype);
$angeltype_signup_state = Shift_signup_allowed(
@@ -351,8 +350,8 @@ function shifts_controller()
}
return match ($request->input('action')) {
- 'view' => shift_controller(),
- 'next' => shift_next_controller(), // throws redirect
+ 'view' => shift_controller(),
+ 'next' => shift_next_controller(), // throws redirect
default => throw_redirect(page_link_to('/')),
};
}
@@ -368,8 +367,8 @@ function shift_next_controller()
$upcoming_shifts = ShiftEntries_upcoming_for_user(auth()->user());
- if (!empty($upcoming_shifts)) {
- throw_redirect(shift_link($upcoming_shifts[0]));
+ if (!$upcoming_shifts->isEmpty()) {
+ throw_redirect(shift_link($upcoming_shifts[0]->shift));
}
throw_redirect(page_link_to('user_shifts'));
@@ -406,41 +405,41 @@ function shifts_json_export_controller()
// See engelsystem-base/src/main/kotlin/info/metadude/kotlin/library/engelsystem/models/Shift.kt
$data = [
// Name of the shift (type)
- 'name' => $shift->shiftType->name,
+ 'name' => $shift->shiftType->name,
// Shift / Talk title
- 'title' => $shift->title,
+ 'title' => $shift->title,
// Shift description
- 'description' => $shift->description,
+ 'description' => $shift->description,
// Users comment
- 'Comment' => $shift->Comment,
+ 'Comment' => $shift->user_comment,
// Shift id
- 'SID' => $shift->id,
+ 'SID' => $shift->id,
// Shift type id
- 'shifttype_id' => $shift->shift_type_id,
+ 'shifttype_id' => $shift->shift_type_id,
// Talk URL
- 'URL' => $shift->url,
+ 'URL' => $shift->url,
// Room name
- 'Name' => $shift->room->name,
+ 'Name' => $shift->room->name,
// Location map url
- 'map_url' => $shift->room->map_url,
+ 'map_url' => $shift->room->map_url,
// Start timestamp
/** @deprecated start_date should be used */
- 'start' => $shift->start->timestamp,
+ 'start' => $shift->start->timestamp,
// Start date
- 'start_date' => $shift->start->toRfc3339String(),
+ 'start_date' => $shift->start->toRfc3339String(),
// End timestamp
/** @deprecated end_date should be used */
- 'end' => $shift->end->timestamp,
+ 'end' => $shift->end->timestamp,
// End date
- 'end_date' => $shift->end->toRfc3339String(),
+ 'end_date' => $shift->end->toRfc3339String(),
// Timezone offset like "+01:00"
/** @deprecated should be retrieved from start_date or end_date */
- 'timezone' => $timeZone->toOffsetName(),
+ 'timezone' => $timeZone->toOffsetName(),
// The events timezone like "Europe/Berlin"
'event_timezone' => $timeZone->getName(),
];
diff --git a/includes/controller/users_controller.php b/includes/controller/users_controller.php
index 7037105c..ee88475f 100644
--- a/includes/controller/users_controller.php
+++ b/includes/controller/users_controller.php
@@ -1,6 +1,7 @@
needed_angeltypes = Db::select(
'
SELECT DISTINCT `angel_types`.*
- FROM `ShiftEntry`
- JOIN `angel_types` ON `ShiftEntry`.`TID`=`angel_types`.`id`
- WHERE `ShiftEntry`.`SID` = ?
+ FROM `shift_entries`
+ JOIN `angel_types` ON `shift_entries`.`angel_type_id`=`angel_types`.`id`
+ WHERE `shift_entries`.`shift_id` = ?
ORDER BY `angel_types`.`name`
',
[$shift->id]
@@ -220,11 +221,11 @@ function user_controller()
foreach ($neededAngeltypes as &$needed_angeltype) {
$needed_angeltype['users'] = Db::select(
'
- SELECT `ShiftEntry`.`freeloaded`, `users`.*
- FROM `ShiftEntry`
- JOIN `users` ON `ShiftEntry`.`UID`=`users`.`id`
- WHERE `ShiftEntry`.`SID` = ?
- AND `ShiftEntry`.`TID` = ?
+ SELECT `shift_entries`.`freeloaded`, `users`.*
+ FROM `shift_entries`
+ JOIN `users` ON `shift_entries`.`user_id`=`users`.`id`
+ WHERE `shift_entries`.`shift_id` = ?
+ AND `shift_entries`.`angel_type_id` = ?
',
[$shift->id, $needed_angeltype['id']]
);
@@ -247,7 +248,7 @@ function user_controller()
User_view(
$user_source,
auth()->can('admin_user'),
- User_is_freeloader($user_source),
+ $user_source->isFreeloader(),
$user_source->userAngelTypes,
$user_source->groups,
$shifts,
@@ -300,7 +301,12 @@ function users_list_controller()
->orderBy('name')
->get();
foreach ($users as $user) {
- $user->setAttribute('freeloads', count(ShiftEntries_freeloaded_by_user($user->id)));
+ $user->setAttribute(
+ 'freeloads',
+ $user->shiftEntries()
+ ->where('freeloaded', true)
+ ->count()
+ );
}
$users = $users->sortBy(function (User $user) use ($order_by) {
@@ -321,7 +327,7 @@ function users_list_controller()
State::whereArrived(true)->count(),
State::whereActive(true)->count(),
State::whereForceActive(true)->count(),
- ShiftEntries_freeloaded_count(),
+ ShiftEntry::whereFreeloaded(true)->count(),
State::whereGotShirt(true)->count(),
State::query()->sum('got_voucher')
)
@@ -360,6 +366,7 @@ function shiftCalendarRendererByShiftFilter(ShiftsFilter $shiftsFilter)
$shift_entries_source = ShiftEntries_by_ShiftsFilter($shiftsFilter);
$needed_angeltypes = [];
+ /** @var ShiftEntry[][] $shift_entries */
$shift_entries = [];
foreach ($shifts as $shift) {
$needed_angeltypes[$shift->id] = [];
@@ -367,8 +374,8 @@ function shiftCalendarRendererByShiftFilter(ShiftsFilter $shiftsFilter)
}
foreach ($shift_entries_source as $shift_entry) {
- if (isset($shift_entries[$shift_entry['SID']])) {
- $shift_entries[$shift_entry['SID']][] = $shift_entry;
+ if (isset($shift_entries[$shift_entry->shift_id])) {
+ $shift_entries[$shift_entry->shift_id][] = $shift_entry;
}
}
@@ -403,8 +410,8 @@ function shiftCalendarRendererByShiftFilter(ShiftsFilter $shiftsFilter)
foreach ($shift_entries[$shift->id] as $shift_entry) {
if (
- $needed_angeltype['angel_type_id'] == $shift_entry['TID']
- && $shift_entry['freeloaded'] == 0
+ $needed_angeltype['angel_type_id'] == $shift_entry->angel_type_id
+ && !$shift_entry->freeloaded
) {
$taken++;
}
diff --git a/includes/mailer/shifts_mailer.php b/includes/mailer/shifts_mailer.php
index ef0976ba..c1eee921 100644
--- a/includes/mailer/shifts_mailer.php
+++ b/includes/mailer/shifts_mailer.php
@@ -1,11 +1,16 @@
id);
+ /** @var ShiftEntry[]|Collection $shiftEntries */
+ $shiftEntries = $old_shift->shiftEntries()
+ ->with(['user', 'user.settings'])
+ ->get();
$old_room = $old_shift->room;
$new_room = $new_shift->room;
@@ -65,8 +70,8 @@ function mail_shift_change(Shift $old_shift, Shift $new_shift)
$message .= $new_room->name . "\n\n";
$message .= url('/shifts', ['action' => 'view', 'shift_id' => $new_shift->id]) . "\n";
- foreach ($users as $user) {
- $user = (new User())->forceFill($user);
+ foreach ($shiftEntries as $shiftEntry) {
+ $user = $shiftEntry->user;
if ($user->settings->email_shiftinfo) {
engelsystem_email_to_user(
$user,
diff --git a/includes/model/NeededAngelTypes_model.php b/includes/model/NeededAngelTypes_model.php
index 9b6b1ab9..c2d0c9b6 100644
--- a/includes/model/NeededAngelTypes_model.php
+++ b/includes/model/NeededAngelTypes_model.php
@@ -1,6 +1,8 @@
where('shift_id', $shiftId)
+ ->get();
$needed_angeltypes = [];
foreach ($needed_angeltypes_source as $angeltype) {
$angeltype['shift_entries'] = [];
$angeltype['taken'] = 0;
foreach ($shift_entries as $shift_entry) {
- if ($shift_entry['TID'] == $angeltype['angel_type_id'] && $shift_entry['freeloaded'] == 0) {
+ if ($shift_entry->angel_type_id == $angeltype['angel_type_id'] && !$shift_entry->freeloaded) {
$angeltype['taken']++;
$angeltype['shift_entries'][] = $shift_entry;
}
diff --git a/includes/model/ShiftEntry_model.php b/includes/model/ShiftEntry_model.php
index 1323603c..21ec0921 100644
--- a/includes/model/ShiftEntry_model.php
+++ b/includes/model/ShiftEntry_model.php
@@ -1,153 +1,40 @@
shiftType;
- $room = $shift->room;
- $angeltype = AngelType::find($shift_entry['TID']);
- $result = Db::insert(
- '
- INSERT INTO `ShiftEntry` (
- `SID`,
- `TID`,
- `UID`,
- `Comment`,
- `freeload_comment`,
- `freeloaded`
- )
- VALUES(?, ?, ?, ?, ?, ?)
- ',
- [
- $shift_entry['SID'],
- $shift_entry['TID'],
- $shift_entry['UID'],
- $shift_entry['Comment'],
- $shift_entry['freeload_comment'],
- (int) $shift_entry['freeloaded'],
- ]
- );
+ $shift = $shiftEntry->shift;
engelsystem_log(
- 'User ' . User_Nick_render($user, true)
- . ' signed up for shift ' . $shift->title
- . ' (' . $shifttype->name . ')'
- . ' at ' . $room->name
+ 'User ' . User_Nick_render($shiftEntry->user, true)
+ . ' signed up for shift ' . $shiftEntry->shift->title
+ . ' (' . $shift->shiftType->name . ')'
+ . ' at ' . $shift->room->name
. ' from ' . $shift->start->format('Y-m-d H:i')
. ' to ' . $shift->end->format('Y-m-d H:i')
- . ' as ' . $angeltype->name
+ . ' as ' . $shiftEntry->angelType->name
);
- mail_shift_assign($user, $shift);
-
- return $result;
-}
-
-/**
- * Update a shift entry.
- *
- * @param array $shift_entry
- */
-function ShiftEntry_update($shift_entry)
-{
- Db::update(
- '
- UPDATE `ShiftEntry`
- SET
- `Comment` = ?,
- `freeload_comment` = ?,
- `freeloaded` = ?
- WHERE `id` = ?
- ',
- [
- $shift_entry['Comment'],
- $shift_entry['freeload_comment'],
- (int) $shift_entry['freeloaded'],
- $shift_entry['id']
- ]
- );
-}
-
-/**
- * Get a shift entry.
- *
- * @param int $shift_entry_id
- * @return array|null
- */
-function ShiftEntry($shift_entry_id)
-{
- $shiftEntry = Db::selectOne('SELECT * FROM `ShiftEntry` WHERE `id` = ?', [$shift_entry_id]);
-
- return empty($shiftEntry) ? null : $shiftEntry;
+ mail_shift_assign($shiftEntry->user, $shift);
}
/**
* Delete a shift entry.
*
- * @param array $shiftEntry
+ * @param ShiftEntry $shiftEntry
*/
-function ShiftEntry_delete($shiftEntry)
+function ShiftEntry_onDelete(ShiftEntry $shiftEntry)
{
- Db::delete('DELETE FROM `ShiftEntry` WHERE `id` = ?', [$shiftEntry['id']]);
-
- $signout_user = User::find($shiftEntry['UID']);
- $shift = Shift($shiftEntry['SID']);
+ $signout_user = $shiftEntry->user;
+ $shift = Shift($shiftEntry->shift);
$shifttype = $shift->shiftType;
$room = $shift->room;
- $angeltype = AngelType::find($shiftEntry['TID']);
+ $angeltype = $shiftEntry->angelType;
engelsystem_log(
'Shift signout: ' . User_Nick_render($signout_user, true)
@@ -159,100 +46,44 @@ function ShiftEntry_delete($shiftEntry)
. ' as ' . $angeltype->name
);
- mail_shift_removed(User::find($shiftEntry['UID']), $shift);
+ mail_shift_removed($signout_user, $shift);
}
/**
* Returns next (or current) shifts of given user.
*
* @param User $user
- * @return array
+ * @return ShiftEntry[]|Collection
*/
function ShiftEntries_upcoming_for_user(User $user)
{
- return Db::select(
- '
- SELECT *, shifts.id as shift_id
- FROM `ShiftEntry`
- JOIN `shifts` ON (`shifts`.`id` = `ShiftEntry`.`SID`)
- JOIN `shift_types` ON `shift_types`.`id` = `shifts`.`shift_type_id`
- WHERE `ShiftEntry`.`UID` = ?
- AND `shifts`.`end` > NOW()
- ORDER BY `shifts`.`end`
- ',
- [
- $user->id
- ]
- );
+ return $user->shiftEntries()
+ ->with(['shift', 'shift.shiftType'])
+ ->join('shifts', 'shift_entries.shift_id', 'shifts.id')
+ ->where('shifts.end', '>', Carbon::now())
+ ->orderBy('shifts.end')
+ ->get();
}
/**
* Returns shifts completed by the given user.
*
- * @param User $user
+ * @param User $user
* @param Carbon|null $sinceTime
- * @return array
+ * @return ShiftEntry[]|Collection
*/
function ShiftEntries_finished_by_user(User $user, Carbon $sinceTime = null)
{
- return Db::select(
- '
- SELECT *
- FROM `ShiftEntry`
- JOIN `shifts` ON (`shifts`.`id` = `ShiftEntry`.`SID`)
- JOIN `shift_types` ON `shift_types`.`id` = `shifts`.`shift_type_id`
- WHERE `ShiftEntry`.`UID` = ?
- AND `shifts`.`end` < NOW()
- AND `ShiftEntry`.`freeloaded` = 0
- ' . ($sinceTime ? 'AND shifts.start >= "' . $sinceTime->toString() . '"' : '') . '
- ORDER BY `shifts`.`end` desc
- ',
- [
- $user->id,
- ]
- );
-}
+ $query = $user->shiftEntries()
+ ->with(['shift', 'shift.shiftType'])
+ ->join('shifts', 'shift_entries.shift_id', 'shifts.id')
+ ->where('shifts.end', '<', Carbon::now())
+ ->where('freeloaded', false)
+ ->orderByDesc('shifts.end');
-/**
- * Returns all shift entries in given shift for given angeltype.
- *
- * @param int $shift_id
- * @param int $angeltype_id
- * @return array
- */
-function ShiftEntries_by_shift_and_angeltype($shift_id, $angeltype_id)
-{
- return Db::select(
- '
- SELECT *
- FROM `ShiftEntry`
- WHERE `SID` = ?
- AND `TID` = ?
- ',
- [
- $shift_id,
- $angeltype_id,
- ]
- );
-}
+ if ($sinceTime) {
+ $query = $query->where('shifts.start', '>=', $sinceTime);
+ }
-/**
- * Returns all freeloaded shifts for given user.
- *
- * @param int $userId
- * @return array
- */
-function ShiftEntries_freeloaded_by_user($userId)
-{
- return Db::select(
- '
- SELECT *
- FROM `ShiftEntry`
- WHERE `freeloaded` = 1
- AND `UID` = ?
- ',
- [
- $userId
- ]
- );
+ return $query->get();
}
diff --git a/includes/model/Shifts_model.php b/includes/model/Shifts_model.php
index 185f3633..5bdcd136 100644
--- a/includes/model/Shifts_model.php
+++ b/includes/model/Shifts_model.php
@@ -4,11 +4,13 @@ use Engelsystem\Database\Db;
use Engelsystem\Helpers\Carbon;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\Shifts\Shift;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
use Engelsystem\ShiftsFilter;
use Engelsystem\ShiftSignupState;
-use Illuminate\Support\Collection;
+use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Support\Collection as SupportCollection;
/**
* @param AngelType $angeltype
@@ -57,7 +59,7 @@ function Shifts_free($start, $end, ShiftsFilter $filter = null)
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
WHERE (`end` > ? AND `start` < ?)
AND (SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`shift_id`=`shifts`.`id`' . ($filter ? ' AND NeededAngelTypes.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
- > (SELECT COUNT(*) FROM `ShiftEntry` WHERE `ShiftEntry`.`SID`=`shifts`.`id` AND `freeloaded`=0' . ($filter ? ' AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
+ > (SELECT COUNT(*) FROM `shift_entries` WHERE `shift_entries`.`shift_id`=`shifts`.`id` AND shift_entries.`freeloaded`=0' . ($filter ? ' AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
AND s.shift_id IS NULL
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
@@ -68,7 +70,7 @@ function Shifts_free($start, $end, ShiftsFilter $filter = null)
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
WHERE (`end` > ? AND `start` < ?)
AND (SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`room_id`=`shifts`.`room_id`' . ($filter ? ' AND NeededAngelTypes.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
- > (SELECT COUNT(*) FROM `ShiftEntry` WHERE `ShiftEntry`.`SID`=`shifts`.`id` AND `freeloaded`=0' . ($filter ? ' AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
+ > (SELECT COUNT(*) FROM `shift_entries` WHERE `shift_entries`.`shift_id`=`shifts`.`id` AND `freeloaded`=0' . ($filter ? ' AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
AND NOT s.shift_id IS NULL
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
) AS `tmp`
@@ -246,41 +248,21 @@ function NeededAngeltype_by_Shift_and_Angeltype(Shift $shift, AngelType $angelty
/**
* @param ShiftsFilter $shiftsFilter
- * @return array[]
+ * @return ShiftEntry[]|Collection
*/
function ShiftEntries_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
{
- $sql = sprintf(
- '
- SELECT
- users.*,
- `ShiftEntry`.`UID`,
- `ShiftEntry`.`TID`,
- `ShiftEntry`.`SID`,
- `ShiftEntry`.`Comment`,
- `ShiftEntry`.`freeloaded`
- FROM `shifts`
- JOIN `ShiftEntry` ON `ShiftEntry`.`SID`=`shifts`.`id`
- JOIN `users` ON `ShiftEntry`.`UID`=`users`.`id`
- WHERE `shifts`.`room_id` IN (%s)
- AND `start` BETWEEN ? AND ?
- ORDER BY `shifts`.`start`
- ',
- implode(',', $shiftsFilter->getRooms())
- );
- return Db::select(
- $sql,
- [
- $shiftsFilter->getStart(),
- $shiftsFilter->getEnd(),
- ]
- );
+ return ShiftEntry::with('user')
+ ->join('shifts', 'shifts.id', 'shift_entries.shift_id')
+ ->whereIn('shifts.room_id', $shiftsFilter->getRooms())
+ ->whereBetween('start', [$shiftsFilter->getStart(), $shiftsFilter->getEnd()])
+ ->get();
}
/**
* Check if a shift collides with other shifts (in time).
*
- * @param Shift $shift
+ * @param Shift $shift
* @param Shift[]|Collection $shifts
* @return bool
*/
@@ -290,8 +272,8 @@ function Shift_collides(Shift $shift, $shifts)
if ($shift->id != $other_shift->id) {
if (
!(
- $shift->start->timestamp >= $other_shift->end->timestamp
- || $shift->end->timestamp <= $other_shift->start->timestamp
+ $shift->start->timestamp >= $other_shift->end->timestamp
+ || $shift->end->timestamp <= $other_shift->start->timestamp
)
) {
return true;
@@ -304,15 +286,15 @@ function Shift_collides(Shift $shift, $shifts)
/**
* Returns the number of needed angels/free shift entries for an angeltype.
*
- * @param AngelType $needed_angeltype
- * @param array[] $shift_entries
+ * @param AngelType $needed_angeltype
+ * @param ShiftEntry[]|Collection $shift_entries
* @return int
*/
function Shift_free_entries(AngelType $needed_angeltype, $shift_entries)
{
$taken = 0;
foreach ($shift_entries as $shift_entry) {
- if ($shift_entry['freeloaded'] == 0) {
+ if (!$shift_entry->freeloaded) {
$taken++;
}
}
@@ -330,7 +312,7 @@ function Shift_free_entries(AngelType $needed_angeltype, $shift_entries)
* @param array|null $user_angeltype
* @param SHift[]|Collection|null $user_shifts List of the users shifts
* @param AngelType $needed_angeltype
- * @param array[] $shift_entries
+ * @param ShiftEntry[]|Collection $shift_entries
* @return ShiftSignupState
*/
function Shift_signup_allowed_angel(
@@ -410,8 +392,8 @@ function Shift_signup_allowed_angel(
/**
* Check if an angeltype supporter can sign up a user to a shift.
*
- * @param AngelType $needed_angeltype
- * @param array[] $shift_entries
+ * @param AngelType $needed_angeltype
+ * @param ShiftEntry[]|Collection $shift_entries
* @return ShiftSignupState
*/
function Shift_signup_allowed_angeltype_supporter(AngelType $needed_angeltype, $shift_entries)
@@ -427,8 +409,8 @@ function Shift_signup_allowed_angeltype_supporter(AngelType $needed_angeltype, $
/**
* Check if an admin can sign up a user to a shift.
*
- * @param AngelType $needed_angeltype
- * @param array[] $shift_entries
+ * @param AngelType $needed_angeltype
+ * @param ShiftEntry[]|Collection $shift_entries
* @return ShiftSignupState
*/
function Shift_signup_allowed_admin(AngelType $needed_angeltype, $shift_entries)
@@ -484,7 +466,7 @@ function Shift_signout_allowed(Shift $shift, AngelType $angeltype, $signout_user
* @param array|null $user_angeltype
* @param Shift[]|Collection|null $user_shifts List of the users shifts
* @param AngelType $needed_angeltype
- * @param array[] $shift_entries
+ * @param ShiftEntry[]|Collection $shift_entries
* @return ShiftSignupState
*/
function Shift_signup_allowed(
@@ -522,10 +504,10 @@ function Shift_signup_allowed(
* Return users shifts.
*
* @param int $userId
- * @param bool $include_freeload_comments
- * @return Collection|Shift[]
+ * @param bool $include_freeloaded_comments
+ * @return SupportCollection|Shift[]
*/
-function Shifts_by_user($userId, $include_freeload_comments = false)
+function Shifts_by_user($userId, $include_freeloaded_comments = false)
{
$shiftsData = Db::select(
'
@@ -534,19 +516,19 @@ function Shifts_by_user($userId, $include_freeload_comments = false)
`rooms`.name AS Name,
`shift_types`.`id` AS `shifttype_id`,
`shift_types`.`name`,
- `ShiftEntry`.`id` as shift_entry_id,
- `ShiftEntry`.`SID`,
- `ShiftEntry`.`TID`,
- `ShiftEntry`.`UID`,
- `ShiftEntry`.`freeloaded`,
- `ShiftEntry`.`Comment`,
- ' . ($include_freeload_comments ? '`ShiftEntry`.`freeload_comment`, ' : '') . '
+ `shift_entries`.`id` as shift_entry_id,
+ `shift_entries`.`shift_id`,
+ `shift_entries`.`angel_type_id`,
+ `shift_entries`.`user_id`,
+ `shift_entries`.`freeloaded`,
+ `shift_entries`.`user_comment`,
+ ' . ($include_freeloaded_comments ? '`shift_entries`.`freeloaded_comment`, ' : '') . '
`shifts`.*
- FROM `ShiftEntry`
- JOIN `shifts` ON (`ShiftEntry`.`SID` = `shifts`.`id`)
+ FROM `shift_entries`
+ JOIN `shifts` ON (`shift_entries`.`shift_id` = `shifts`.`id`)
JOIN `shift_types` ON (`shift_types`.`id` = `shifts`.`shift_type_id`)
JOIN `rooms` ON (`shifts`.`room_id` = `rooms`.`id`)
- WHERE ShiftEntry.`UID` = ?
+ WHERE shift_entries.`user_id` = ?
ORDER BY `start`
',
[
@@ -578,22 +560,14 @@ function Shift($shift)
return null;
}
- $shift->shiftEntry = Db::select('
- SELECT
- `ShiftEntry`.`id`, `ShiftEntry`.`TID` , `ShiftEntry`.`UID` , `ShiftEntry`.`freeloaded`,
- `users`.`name` AS `username`, `users`.`id` AS `user_id`
- FROM `ShiftEntry`
- LEFT JOIN `users` ON (`users`.`id` = `ShiftEntry`.`UID`)
- WHERE `SID`=?', [$shift->id]);
-
$neededAngels = [];
$angelTypes = NeededAngelTypes_by_shift($shift->id);
foreach ($angelTypes as $type) {
$neededAngels[] = [
- 'TID' => $type['angel_type_id'],
- 'count' => $type['count'],
- 'restricted' => $type['restricted'],
- 'taken' => $type['taken']
+ 'angel_type_id' => $type['angel_type_id'],
+ 'count' => $type['count'],
+ 'restricted' => $type['restricted'],
+ 'taken' => $type['taken']
];
}
$shift->neededAngels = $neededAngels;
diff --git a/includes/model/Stats.php b/includes/model/Stats.php
index ec20725d..04168c64 100644
--- a/includes/model/Stats.php
+++ b/includes/model/Stats.php
@@ -16,10 +16,10 @@ function stats_currently_working(ShiftsFilter $filter = null)
'
SELECT SUM((
SELECT COUNT(*)
- FROM `ShiftEntry`
- WHERE `ShiftEntry`.`SID`=`shifts`.`id`
+ FROM `shift_entries`
+ WHERE `shift_entries`.`shift_id`=`shifts`.`id`
AND `freeloaded`=0
- ' . ($filter ? 'AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
+ ' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
)) AS `count`
FROM `shifts`
WHERE (`end` >= NOW() AND `start` <= NOW())
@@ -89,12 +89,12 @@ function stats_angels_needed_three_hours(ShiftsFilter $filter = null)
AND `NeededAngelTypes`.`shift_id`=`shifts`.`id`
' . ($filter ? 'AND NeededAngelTypes.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
) - (
- SELECT COUNT(*) FROM `ShiftEntry`
- JOIN `angel_types` ON `angel_types`.`id`=`ShiftEntry`.`TID`
+ SELECT COUNT(*) FROM `shift_entries`
+ JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
WHERE `angel_types`.`show_on_dashboard`=TRUE
- AND `ShiftEntry`.`SID`=`shifts`.`id`
+ AND `shift_entries`.`shift_id`=`shifts`.`id`
AND `freeloaded`=0
- ' . ($filter ? 'AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
+ ' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
)
)
AS `count`
@@ -116,12 +116,13 @@ function stats_angels_needed_three_hours(ShiftsFilter $filter = null)
AND `NeededAngelTypes`.`room_id`=`shifts`.`room_id`
' . ($filter ? 'AND NeededAngelTypes.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
) - (
- SELECT COUNT(*) FROM `ShiftEntry`
- JOIN `angel_types` ON `angel_types`.`id`=`ShiftEntry`.`TID`
+ SELECT COUNT(*)
+ FROM `shift_entries`
+ JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
WHERE `angel_types`.`show_on_dashboard`=TRUE
- AND `ShiftEntry`.`SID`=`shifts`.`id`
+ AND `shift_entries`.`shift_id`=`shifts`.`id`
AND `freeloaded`=0
- ' . ($filter ? 'AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
+ ' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
)
)
AS `count`
@@ -168,12 +169,12 @@ function stats_angels_needed_for_nightshifts(ShiftsFilter $filter = null)
AND `NeededAngelTypes`.`shift_id`=`shifts`.`id`
' . ($filter ? 'AND NeededAngelTypes.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
) - (
- SELECT COUNT(*) FROM `ShiftEntry`
- JOIN `angel_types` ON `angel_types`.`id`=`ShiftEntry`.`TID`
+ SELECT COUNT(*) FROM `shift_entries`
+ JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
WHERE `angel_types`.`show_on_dashboard`=TRUE
- AND `ShiftEntry`.`SID`=`shifts`.`id`
- AND `freeloaded`=0
- ' . ($filter ? 'AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
+ AND `shift_entries`.`shift_id`=`shifts`.`id`
+ AND shift_entries.`freeloaded`=0
+ ' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
)
)
AS `count`
@@ -195,12 +196,12 @@ function stats_angels_needed_for_nightshifts(ShiftsFilter $filter = null)
AND `NeededAngelTypes`.`room_id`=`shifts`.`room_id`
' . ($filter ? 'AND angel_types.id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
) - (
- SELECT COUNT(*) FROM `ShiftEntry`
- JOIN `angel_types` ON `angel_types`.`id`=`ShiftEntry`.`TID`
+ SELECT COUNT(*) FROM `shift_entries`
+ JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
WHERE `angel_types`.`show_on_dashboard`=TRUE
- AND `ShiftEntry`.`SID`=`shifts`.`id`
+ AND `shift_entries`.`shift_id`=`shifts`.`id`
AND `freeloaded`=0
- ' . ($filter ? 'AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
+ ' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
)
)
AS `count`
diff --git a/includes/model/User_model.php b/includes/model/User_model.php
index 1c500fb7..fd907a6b 100644
--- a/includes/model/User_model.php
+++ b/includes/model/User_model.php
@@ -25,8 +25,8 @@ function User_tshirt_score($userId)
$shift_sum_formula = User_get_shifts_sum_query();
$result_shifts = Db::selectOne(sprintf('
SELECT ROUND((%s) / 3600, 2) AS `tshirt_score`
- FROM `users` LEFT JOIN `ShiftEntry` ON `users`.`id` = `ShiftEntry`.`UID`
- LEFT JOIN `shifts` ON `ShiftEntry`.`SID` = `shifts`.`id`
+ FROM `users` LEFT JOIN `shift_entries` ON `users`.`id` = `shift_entries`.`user_id`
+ LEFT JOIN `shifts` ON `shift_entries`.`shift_id` = `shifts`.`id`
WHERE `users`.`id` = ?
AND `shifts`.`end` < NOW()
GROUP BY `users`.`id`
@@ -45,17 +45,6 @@ function User_tshirt_score($userId)
return $result_shifts['tshirt_score'] + $worklogHours;
}
-/**
- * Returns true if user is freeloader
- *
- * @param User $user
- * @return bool
- */
-function User_is_freeloader($user)
-{
- return count(ShiftEntries_freeloaded_by_user($user->id)) >= config('max_freeloadable_shifts');
-}
-
/**
* Returns all users that are not member of given angeltype.
*
@@ -196,15 +185,15 @@ function User_get_eligable_voucher_count($user)
? Carbon::createFromFormat('Y-m-d', $voucher_settings['voucher_start'])->setTime(0, 0)
: null;
- $shifts = ShiftEntries_finished_by_user($user, $start);
+ $shiftEntries = ShiftEntries_finished_by_user($user, $start);
$worklog = UserWorkLogsForUser($user->id, $start);
$shifts_done =
- count($shifts)
+ count($shiftEntries)
+ $worklog->count();
$shiftsTime = 0;
- foreach ($shifts as $shift) {
- $shiftsTime += (Carbon::make($shift['end'])->timestamp - Carbon::make($shift['start'])->timestamp) / 60 / 60;
+ foreach ($shiftEntries as $shiftEntry) {
+ $shiftsTime += ($shiftEntry->shift->end->timestamp - $shiftEntry->shift->start->timestamp) / 60 / 60;
}
foreach ($worklog as $entry) {
$shiftsTime += $entry->hours;
@@ -248,7 +237,7 @@ function User_get_shifts_sum_query()
OR (HOUR(shifts.start) <= %1$d AND HOUR(shifts.end) >= %2$d)
))
* (UNIX_TIMESTAMP(shifts.end) - UNIX_TIMESTAMP(shifts.start))
- * (1 - (%3$d + 1) * `ShiftEntry`.`freeloaded`)
+ * (1 - (%3$d + 1) * `shift_entries`.`freeloaded`)
), 0)
',
$nightShifts['start'],
diff --git a/includes/pages/admin_active.php b/includes/pages/admin_active.php
index 5fed6dd7..73105b74 100644
--- a/includes/pages/admin_active.php
+++ b/includes/pages/admin_active.php
@@ -60,7 +60,7 @@ function admin_active()
sprintf(
'
users.*,
- COUNT(ShiftEntry.id) AS shift_count,
+ COUNT(shift_entries.id) AS shift_count,
(%s + (
SELECT COALESCE(SUM(`hours`) * 3600, 0)
FROM `worklogs` WHERE `user_id`=`users`.`id`
@@ -70,8 +70,8 @@ function admin_active()
$shift_sum_formula
)
)
- ->leftJoin('ShiftEntry', 'users.id', '=', 'ShiftEntry.UID')
- ->leftJoin('shifts', 'ShiftEntry.SID', '=', 'shifts.id')
+ ->leftJoin('shift_entries', 'users.id', '=', 'shift_entries.user_id')
+ ->leftJoin('shifts', 'shift_entries.shift_id', '=', 'shifts.id')
->leftJoin('users_state', 'users.id', '=', 'users_state.user_id')
->where('users_state.arrived', '=', true)
->groupBy('users.id')
@@ -152,7 +152,7 @@ function admin_active()
sprintf(
'
users.*,
- COUNT(ShiftEntry.id) AS shift_count,
+ COUNT(shift_entries.id) AS shift_count,
(%s + (
SELECT COALESCE(SUM(`hours`) * 3600, 0)
FROM `worklogs` WHERE `user_id`=`users`.`id`
@@ -162,10 +162,10 @@ function admin_active()
$shift_sum_formula
)
)
- ->leftJoin('ShiftEntry', 'users.id', '=', 'ShiftEntry.UID')
+ ->leftJoin('shift_entries', 'users.id', '=', 'shift_entries.user_id')
->leftJoin('shifts', function ($join) use ($show_all_shifts) {
/** @var JoinClause $join */
- $join->on('ShiftEntry.SID', '=', 'shifts.id');
+ $join->on('shift_entries.shift_id', '=', 'shifts.id');
if (!$show_all_shifts) {
$join->where(function ($query) {
/** @var Builder $query */
diff --git a/includes/pages/admin_free.php b/includes/pages/admin_free.php
index 0287ec1e..44388b4d 100644
--- a/includes/pages/admin_free.php
+++ b/includes/pages/admin_free.php
@@ -40,11 +40,11 @@ function admin_free()
if ($request->has('submit')) {
$query = User::with('personalData')
->select('users.*')
- ->leftJoin('ShiftEntry', 'users.id', 'ShiftEntry.UID')
+ ->leftJoin('shift_entries', 'users.id', 'shift_entries.user_id')
->leftJoin('users_state', 'users.id', 'users_state.user_id')
->leftJoin('shifts', function ($join) {
/** @var JoinClause $join */
- $join->on('ShiftEntry.SID', '=', 'shifts.id')
+ $join->on('shift_entries.shift_id', '=', 'shifts.id')
->where('shifts.start', '<', Carbon::now())
->where('shifts.end', '>', Carbon::now());
})
diff --git a/includes/pages/admin_rooms.php b/includes/pages/admin_rooms.php
index 0874d363..e52fb915 100644
--- a/includes/pages/admin_rooms.php
+++ b/includes/pages/admin_rooms.php
@@ -189,15 +189,14 @@ function admin_rooms()
$shifts = $room->shifts;
foreach ($shifts as $shift) {
$shift = Shift($shift);
- foreach ($shift->shiftEntry as $entry) {
- $type = AngelType::find($entry['TID']);
+ foreach ($shift->shiftEntries as $entry) {
event('shift.entry.deleting', [
'user' => User::find($entry['user_id']),
'start' => $shift->start,
'end' => $shift->end,
'name' => $shift->shiftType->name,
'title' => $shift->title,
- 'type' => $type->name,
+ 'type' => $entry->angelType->name,
'room' => $room,
'freeloaded' => (bool) $entry['freeloaded'],
]);
diff --git a/includes/pages/admin_shifts.php b/includes/pages/admin_shifts.php
index ba24b9dc..7cfd3000 100644
--- a/includes/pages/admin_shifts.php
+++ b/includes/pages/admin_shifts.php
@@ -563,17 +563,16 @@ function admin_shifts_history(): string
foreach ($shifts as $shift) {
$shift = Shift($shift);
- foreach ($shift->shiftEntry as $entry) {
- $type = AngelType::find($entry['TID']);
+ foreach ($shift->shiftEntries as $entry) {
event('shift.entry.deleting', [
- 'user' => User::find($entry['user_id']),
+ 'user' => $entry->user,
'start' => $shift->start,
'end' => $shift->end,
'name' => $shift->shiftType->name,
'title' => $shift->title,
- 'type' => $type->name,
+ 'type' => $entry->angelType->name,
'room' => $shift->room,
- 'freeloaded' => (bool) $entry['freeloaded'],
+ 'freeloaded' => $entry->freeloaded,
]);
}
diff --git a/includes/pages/schedule/ImportSchedule.php b/includes/pages/schedule/ImportSchedule.php
index 3538e011..c0fb4158 100644
--- a/includes/pages/schedule/ImportSchedule.php
+++ b/includes/pages/schedule/ImportSchedule.php
@@ -266,15 +266,15 @@ class ImportSchedule extends BaseController
protected function fireDeleteShiftEntryEvents(Event $event): void
{
$shiftEntries = $this->db
- ->table('ShiftEntry')
+ ->table('shift_entries')
->select([
'shift_types.name', 'shifts.title', 'angel_types.name AS type', 'rooms.id AS room_id',
- 'shifts.start', 'shifts.end', 'ShiftEntry.UID as user_id', 'ShiftEntry.freeloaded'
+ 'shifts.start', 'shifts.end', 'shift_entries.user_id', 'shift_entries.freeloaded'
])
- ->join('shifts', 'shifts.id', 'ShiftEntry.SID')
+ ->join('shifts', 'shifts.id', 'shift_entries.shift_id')
->join('schedule_shift', 'shifts.id', 'schedule_shift.shift_id')
->join('rooms', 'rooms.id', 'shifts.room_id')
- ->join('angel_types', 'angel_types.id', 'ShiftEntry.TID')
+ ->join('angel_types', 'angel_types.id', 'shift_entries.angel_type_id')
->join('shift_types', 'shift_types.id', 'shifts.shift_type_id')
->where('schedule_shift.guid', $event->getGuid())
->get();
diff --git a/includes/pages/user_ical.php b/includes/pages/user_ical.php
index 1ff7e86c..132abe76 100644
--- a/includes/pages/user_ical.php
+++ b/includes/pages/user_ical.php
@@ -60,8 +60,8 @@ function make_ical_entry_from_shift(Shift $shift)
$output .= 'UID:' . md5($shift->start->timestamp . $shift->end->timestamp . $shift->shiftType->name) . "\r\n";
$output .= 'SUMMARY:' . str_replace("\n", "\\n", $shift->shiftType->name)
. ' (' . str_replace("\n", "\\n", $shift->title) . ")\r\n";
- if (isset($shift->Comment)) {
- $output .= 'DESCRIPTION:' . str_replace("\n", "\\n", $shift->Comment) . "\r\n";
+ if (isset($shift->user_comment)) {
+ $output .= 'DESCRIPTION:' . str_replace("\n", "\\n", $shift->user_comment) . "\r\n";
}
$output .= 'DTSTAMP:' . $shift->start->utc()->format('Ymd\THis\Z') . "\r\n";
$output .= 'DTSTART:' . $shift->start->utc()->format('Ymd\THis\Z') . "\r\n";
diff --git a/includes/pages/user_myshifts.php b/includes/pages/user_myshifts.php
index 7cd89e0f..68397f28 100644
--- a/includes/pages/user_myshifts.php
+++ b/includes/pages/user_myshifts.php
@@ -1,7 +1,6 @@
has('edit') && preg_match('/^\d+$/', $request->input('edit'))) {
$shift_entry_id = $request->input('edit');
- $shift = Db::selectOne(
- '
- SELECT
- `ShiftEntry`.`freeloaded`,
- `ShiftEntry`.`freeload_comment`,
- `ShiftEntry`.`Comment`,
- `ShiftEntry`.`UID`,
- `shift_types`.`name`,
- `shifts`.*,
- `angel_types`.`name` AS `angel_type`
- FROM `ShiftEntry`
- JOIN `angel_types` ON (`ShiftEntry`.`TID` = `angel_types`.`id`)
- JOIN `shifts` ON (`ShiftEntry`.`SID` = `shifts`.`id`)
- JOIN `shift_types` ON (`shift_types`.`id` = `shifts`.`shift_type_id`)
- WHERE `ShiftEntry`.`id`=?
- AND `UID`=?
- LIMIT 1
- ',
- [
- $shift_entry_id,
- $shifts_user->id,
- ]
- );
- if (!empty($shift)) {
- /** @var Shift $shift */
- $shift = (new Shift())->forceFill($shift);
-
- $freeloaded = $shift->freeloaded;
- $freeload_comment = $shift->freeloaded_comment;
+ /** @var ShiftEntry $shiftEntry */
+ $shiftEntry = ShiftEntry::where('id', $shift_entry_id)
+ ->where('user_id', $shifts_user->id)
+ ->with(['shift', 'shift.shiftType', 'shift.room', 'user'])
+ ->first();
+ if (!empty($shiftEntry)) {
+ $shift = $shiftEntry->shift;
+ $freeloaded = $shiftEntry->freeloaded;
+ $freeloaded_comment = $shiftEntry->freeloaded_comment;
if ($request->hasPostData('submit')) {
$valid = true;
if (auth()->can('user_shifts_admin')) {
$freeloaded = $request->has('freeloaded');
- $freeload_comment = strip_request_item_nl('freeload_comment');
- if ($freeloaded && $freeload_comment == '') {
+ $freeloaded_comment = strip_request_item_nl('freeloaded_comment');
+ if ($freeloaded && $freeloaded_comment == '') {
$valid = false;
error(__('Please enter a freeload comment!'));
}
}
- $comment = $shift->Comment;
- $user_source = User::find($shift->UID);
+ $comment = $shiftEntry->user_comment;
+ $user_source = $shiftEntry->user;
if (auth()->user()->id == $user_source->id) {
$comment = strip_request_item_nl('comment');
}
if ($valid) {
- ShiftEntry_update([
- 'id' => $shift_entry_id,
- 'Comment' => $comment,
- 'freeloaded' => $freeloaded,
- 'freeload_comment' => $freeload_comment
- ]);
+ $shiftEntry->user_comment = $comment;
+ $shiftEntry->freeloaded = $freeloaded;
+ $shiftEntry->freeloaded_comment = $freeloaded_comment;
+ $shiftEntry->save();
engelsystem_log(
'Updated ' . User_Nick_render($user_source, true) . '\'s shift '
@@ -110,7 +87,7 @@ function user_myshifts()
. ' from ' . $shift->start->format('Y-m-d H:i')
. ' to ' . $shift->end->format('Y-m-d H:i')
. ' with comment ' . $comment
- . '. Freeloaded: ' . ($freeloaded ? 'YES Comment: ' . $freeload_comment : 'NO')
+ . '. Freeloaded: ' . ($freeloaded ? 'YES Comment: ' . $freeloaded_comment : 'NO')
);
success(__('Shift saved.'));
throw_redirect(page_link_to('users', ['action' => 'view', 'user_id' => $shifts_user->id]));
@@ -122,10 +99,10 @@ function user_myshifts()
$shift->start->format('Y-m-d H:i') . ', ' . shift_length($shift),
$shift->room->name,
$shift->shiftType->name,
- $shift->angel_type,
- $shift->Comment,
- $shift->freeloaded,
- $shift->freeload_comment,
+ $shiftEntry->angelType->name,
+ $shiftEntry->user_comment,
+ $shiftEntry->freeloaded,
+ $shiftEntry->freeloaded_comment,
auth()->can('user_shifts_admin')
);
} else {
diff --git a/includes/pages/user_shifts.php b/includes/pages/user_shifts.php
index 990d2c0c..149922dd 100644
--- a/includes/pages/user_shifts.php
+++ b/includes/pages/user_shifts.php
@@ -31,7 +31,7 @@ function user_shifts()
{
$request = request();
- if (User_is_freeloader(auth()->user())) {
+ if (auth()->user()->isFreeloader()) {
throw_redirect(page_link_to('user_myshifts'));
}
diff --git a/includes/view/ShiftCalendarRenderer.php b/includes/view/ShiftCalendarRenderer.php
index b2937398..ff14f90d 100644
--- a/includes/view/ShiftCalendarRenderer.php
+++ b/includes/view/ShiftCalendarRenderer.php
@@ -3,6 +3,8 @@
namespace Engelsystem;
use Engelsystem\Models\Shifts\Shift;
+use Engelsystem\Models\Shifts\ShiftEntry;
+use Illuminate\Support\Collection;
class ShiftCalendarRenderer
{
@@ -45,10 +47,10 @@ class ShiftCalendarRenderer
/**
* ShiftCalendarRenderer constructor.
*
- * @param Shift[] $shifts
- * @param array[] $needed_angeltypes
- * @param array[] $shift_entries
- * @param ShiftsFilter $shiftsFilter
+ * @param Shift[] $shifts
+ * @param array[] $needed_angeltypes
+ * @param ShiftEntry[][]|Collection $shift_entries
+ * @param ShiftsFilter $shiftsFilter
*/
public function __construct($shifts, private $needed_angeltypes, private $shift_entries, ShiftsFilter $shiftsFilter)
{
@@ -204,7 +206,7 @@ class ShiftCalendarRenderer
/**
* Renders a tick/block for given time
*
- * @param int $time unix timestamp
+ * @param int $time unix timestamp
* @param boolean $label Should time labels be generated?
* @return string rendered tick html
*/
diff --git a/includes/view/ShiftCalendarShiftRenderer.php b/includes/view/ShiftCalendarShiftRenderer.php
index ea8f1f63..9e5bfb1c 100644
--- a/includes/view/ShiftCalendarShiftRenderer.php
+++ b/includes/view/ShiftCalendarShiftRenderer.php
@@ -4,7 +4,9 @@ namespace Engelsystem;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\Shifts\Shift;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\User\User;
+use Illuminate\Support\Collection;
use function theme_type;
@@ -16,10 +18,10 @@ class ShiftCalendarShiftRenderer
/**
* Renders a shift
*
- * @param Shift $shift The shift to render
- * @param array[] $needed_angeltypes
- * @param array $shift_entries
- * @param User $user The user who is viewing the shift calendar
+ * @param Shift $shift The shift to render
+ * @param array[] $needed_angeltypes
+ * @param ShiftEntry[]|Collection $shift_entries
+ * @param User $user The user who is viewing the shift calendar
* @return array
*/
public function render(Shift $shift, $needed_angeltypes, $shift_entries, $user)
@@ -80,10 +82,10 @@ class ShiftCalendarShiftRenderer
}
/**
- * @param Shift $shift
- * @param array[] $needed_angeltypes
- * @param array[] $shift_entries
- * @param User $user
+ * @param Shift $shift
+ * @param array[] $needed_angeltypes
+ * @param ShiftEntry[]|Collection $shift_entries
+ * @param User $user
* @return array
*/
private function renderShiftNeededAngeltypes(Shift $shift, $needed_angeltypes, $shift_entries, $user)
@@ -93,7 +95,7 @@ class ShiftCalendarShiftRenderer
$shift_entries_filtered[$needed_angeltype['id']] = [];
}
foreach ($shift_entries as $shift_entry) {
- $shift_entries_filtered[$shift_entry['TID']][] = $shift_entry;
+ $shift_entries_filtered[$shift_entry->angel_type_id][] = $shift_entry;
}
$html = '';
@@ -144,11 +146,11 @@ class ShiftCalendarShiftRenderer
/**
* Renders a list entry containing the needed angels for an angeltype
*
- * @param Shift $shift The shift which is rendered
- * @param array[] $shift_entries
- * @param array $angeltype The angeltype, containing information about needed angeltypes
+ * @param Shift $shift The shift which is rendered
+ * @param ShiftEntry[]|Collection $shift_entries
+ * @param array $angeltype The angeltype, containing information about needed angeltypes
* and already signed up angels
- * @param User $user The user who is viewing the shift calendar
+ * @param User $user The user who is viewing the shift calendar
* @return array
*/
private function renderShiftNeededAngeltype(Shift $shift, $shift_entries, $angeltype, $user)
@@ -156,8 +158,8 @@ class ShiftCalendarShiftRenderer
$angeltype = (new AngelType())->forceFill($angeltype);
$entry_list = [];
foreach ($shift_entries as $entry) {
- $class = $entry['freeloaded'] ? 'text-decoration-line-through' : '';
- $entry_list[] = '' . User_Nick_render($entry) . '';
+ $class = $entry->freeloaded ? 'text-decoration-line-through' : '';
+ $entry_list[] = '' . User_Nick_render($entry->user) . '';
}
$shift_signup_state = Shift_signup_allowed(
$user,
diff --git a/includes/view/ShiftEntry_view.php b/includes/view/ShiftEntry_view.php
index d84cf24c..1da3ce07 100644
--- a/includes/view/ShiftEntry_view.php
+++ b/includes/view/ShiftEntry_view.php
@@ -39,11 +39,11 @@ function ShiftEntry_delete_view_admin(Shift $shift, AngelType $angeltype, User $
*
* @param Shift $shift
* @param AngelType $angeltype
- * @param int $signoff_user_id
+ * @param User $signoff_user
*
* @return string HTML
*/
-function ShiftEntry_delete_view(Shift $shift, AngelType $angeltype, $signoff_user_id)
+function ShiftEntry_delete_view(Shift $shift, AngelType $angeltype, User $signoff_user)
{
return page_with_title(ShiftEntry_delete_title(), [
info(sprintf(
@@ -56,7 +56,7 @@ function ShiftEntry_delete_view(Shift $shift, AngelType $angeltype, $signoff_use
form([
buttons([
- button(user_link($signoff_user_id), icon('x-lg') . __('cancel')),
+ button(user_link($signoff_user->id), icon('x-lg') . __('cancel')),
form_submit('delete', icon('trash') . __('delete'), 'btn-danger', false),
]),
]),
@@ -180,7 +180,7 @@ function ShiftEntry_create_title()
* @param string $type
* @param string $comment
* @param bool $freeloaded
- * @param string $freeload_comment
+ * @param string $freeloaded_comment
* @param bool $user_admin_shifts
* @return string
*/
@@ -192,7 +192,7 @@ function ShiftEntry_edit_view(
$type,
$comment,
$freeloaded,
- $freeload_comment,
+ $freeloaded_comment,
$user_admin_shifts = false
) {
$freeload_form = [];
@@ -200,9 +200,9 @@ function ShiftEntry_edit_view(
$freeload_form = [
form_checkbox('freeloaded', __('Freeloaded'), $freeloaded),
form_textarea(
- 'freeload_comment',
+ 'freeloaded_comment',
__('Freeload comment (Only for shift coordination):'),
- $freeload_comment
+ $freeloaded_comment
)
];
}
diff --git a/includes/view/Shifts_view.php b/includes/view/Shifts_view.php
index d7b9d2ad..7da4bdc5 100644
--- a/includes/view/Shifts_view.php
+++ b/includes/view/Shifts_view.php
@@ -3,8 +3,8 @@
use Engelsystem\Models\AngelType;
use Engelsystem\Models\Room;
use Engelsystem\Models\Shifts\Shift;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\Shifts\ShiftType;
-use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
use Engelsystem\ShiftSignupState;
use Illuminate\Support\Collection;
@@ -75,8 +75,8 @@ function Shift_editor_info_render(Shift $shift)
}
/**
- * @param Shift $shift
- * @param AngelType $angeltype
+ * @param Shift $shift
+ * @param AngelType $angeltype
* @return string
*/
function Shift_signup_button_render(Shift $shift, AngelType $angeltype)
@@ -136,16 +136,16 @@ function Shift_view(Shift $shift, ShiftType $shifttype, Room $room, $angeltypes_
$needed_angels .= Shift_view_render_needed_angeltype($needed_angeltype, $angeltypes, $shift, $user_shift_admin);
}
- $shiftEntry = new Collection($shift->shiftEntry);
- foreach ($shiftEntry->groupBy('TID') as $angelTypes) {
+ $shiftEntry = $shift->shiftEntries;
+ foreach ($shiftEntry->groupBy('angel_type_id') as $angelTypes) {
/** @var Collection $angelTypes */
- $type = $angelTypes->first()['TID'];
- if (!$neededAngels->where('TID', $type)->first()) {
+ $type = $angelTypes->first()['angel_type_id'];
+ if (!$neededAngels->where('angel_type_id', $type)->first()) {
$needed_angels .= Shift_view_render_needed_angeltype([
- 'TID' => $type,
- 'count' => 0,
- 'restricted' => true,
- 'taken' => $angelTypes->count(),
+ 'angel_type_id' => $type,
+ 'count' => 0,
+ 'restricted' => true,
+ 'taken' => $angelTypes->count(),
], $angeltypes, $shift, $user_shift_admin);
}
}
@@ -213,7 +213,7 @@ function Shift_view(Shift $shift, ShiftType $shifttype, Room $room, $angeltypes_
*/
function Shift_view_render_needed_angeltype($needed_angeltype, $angeltypes, Shift $shift, $user_shift_admin)
{
- $angeltype = $angeltypes[$needed_angeltype['TID']];
+ $angeltype = $angeltypes[$needed_angeltype['angel_type_id']];
$angeltype_supporter = auth()->user()->isAngelTypeSupporter($angeltype)
|| auth()->can('admin_user_angeltypes');
@@ -242,8 +242,8 @@ function Shift_view_render_needed_angeltype($needed_angeltype, $angeltypes, Shif
);
$angels = [];
- foreach ($shift->shiftEntry as $shift_entry) {
- if ($shift_entry['TID'] == $needed_angeltype['TID']) {
+ foreach ($shift->shiftEntries as $shift_entry) {
+ if ($shift_entry->angel_type_id == $needed_angeltype['angel_type_id']) {
$angels[] = Shift_view_render_shift_entry($shift_entry, $user_shift_admin, $angeltype_supporter, $shift);
}
}
@@ -255,30 +255,30 @@ function Shift_view_render_needed_angeltype($needed_angeltype, $angeltypes, Shif
}
/**
- * @param array $shift_entry
+ * @param ShiftEntry $shift_entry
* @param bool $user_shift_admin
* @param bool $angeltype_supporter
* @param Shift $shift
* @return string
*/
-function Shift_view_render_shift_entry($shift_entry, $user_shift_admin, $angeltype_supporter, Shift $shift)
+function Shift_view_render_shift_entry(ShiftEntry $shift_entry, $user_shift_admin, $angeltype_supporter, Shift $shift)
{
- $entry = User_Nick_render(User::find($shift_entry['UID']));
- if ($shift_entry['freeloaded']) {
+ $entry = User_Nick_render($shift_entry->user);
+ if ($shift_entry->freeloaded) {
$entry = '' . $entry . '';
}
- $isUser = $shift_entry['UID'] == auth()->user()->id;
+ $isUser = $shift_entry->user_id == auth()->user()->id;
if ($user_shift_admin || $angeltype_supporter || $isUser) {
$entry .= ' ';
if ($user_shift_admin || $isUser) {
$entry .= button_icon(
- page_link_to('user_myshifts', ['edit' => $shift_entry['id'], 'id' => $shift_entry['UID']]),
+ page_link_to('user_myshifts', ['edit' => $shift_entry->id, 'id' => $shift_entry->user_id]),
'pencil',
'btn-sm'
);
}
- $angeltype = AngelType::find($shift_entry['TID']);
- $disabled = Shift_signout_allowed($shift, $angeltype, $shift_entry['UID']) ? '' : ' btn-disabled';
+ $angeltype = $shift_entry->angelType;
+ $disabled = Shift_signout_allowed($shift, $angeltype, $shift_entry->user_id) ? '' : ' btn-disabled';
$entry .= button_icon(shift_entry_delete_link($shift_entry), 'trash', 'btn-sm' . $disabled);
$entry .= '
';
}
diff --git a/includes/view/User_view.php b/includes/view/User_view.php
index 9ddb4ab0..a5bbb5f8 100644
--- a/includes/view/User_view.php
+++ b/includes/view/User_view.php
@@ -4,6 +4,7 @@ use Carbon\Carbon;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\Group;
use Engelsystem\Models\Shifts\Shift;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\User\User;
use Engelsystem\Models\Worklog;
use Illuminate\Support\Collection;
@@ -197,14 +198,15 @@ function User_shift_state_render($user)
}
$upcoming_shifts = ShiftEntries_upcoming_for_user($user);
- if (empty($upcoming_shifts)) {
+ if ($upcoming_shifts->isEmpty()) {
return '' . __('Free') . '';
}
- $nextShift = array_shift($upcoming_shifts);
+ /** @var ShiftEntry $nextShiftEntry */
+ $nextShiftEntry = $upcoming_shifts->first();
- $start = Carbon::make($nextShift['start']);
- $end = Carbon::make($nextShift['end']);
+ $start = $nextShiftEntry->shift->start;
+ $end = $nextShiftEntry->shift->end;
$startFormat = $start->format(__('Y-m-d H:i'));
$endFormat = $end->format(__('Y-m-d H:i'));
$startTimestamp = $start->timestamp;
@@ -244,8 +246,9 @@ function User_last_shift_render($user)
return '';
}
- $lastShift = array_shift($last_shifts);
- $end = Carbon::make($lastShift['end']);
+ /** @var ShiftEntry $lastShiftEntry */
+ $lastShiftEntry = $last_shifts->first();
+ $end = $lastShiftEntry->shift->end;
return ''
. __('Shift ended %c')
@@ -307,7 +310,7 @@ function User_view_myshift(Shift $shift, $user_source, $its_me)
];
if ($its_me) {
- $myshift['comment'] = $shift->Comment;
+ $myshift['comment'] = $shift->user_comment;
}
if ($shift->freeloaded) {
@@ -316,7 +319,7 @@ function User_view_myshift(Shift $shift, $user_source, $its_me)
. '
';
if (auth()->can('user_shifts_admin')) {
$myshift['comment'] .= '
'
- . '' . __('Freeloaded') . ': ' . $shift->freeload_comment . '
';
+ . '' . __('Freeloaded') . ': ' . $shift->freeloaded_comment . '
';
} else {
$myshift['comment'] .= '
' . __('Freeloaded') . '
';
}
@@ -332,7 +335,8 @@ function User_view_myshift(Shift $shift, $user_source, $its_me)
'btn-sm'
);
}
- if (Shift_signout_allowed($shift, (new AngelType())->forceFill(['id' => $shift->TID]), $user_source->id)) {
+
+ if (Shift_signout_allowed($shift, (new AngelType())->forceFill(['id' => $shift->angel_type_id]), $user_source->id)) {
$myshift['actions'][] = button(
shift_entry_delete_link($shift),
icon('trash') . __('sign off'),
@@ -517,7 +521,7 @@ function User_view(
return page_with_title(
' '
. (
- (config('enable_pronoun') && $user_source->personalData->pronoun)
+ (config('enable_pronoun') && $user_source->personalData->pronoun)
? '' . htmlspecialchars($user_source->personalData->pronoun) . ' '
: ''
)
@@ -554,7 +558,7 @@ function User_view(
),
icon('valentine') . __('Vouchers')
)
- : '',
+ : '',
$admin_user_worklog_privilege ? button(
url('/admin/user/' . $user_source->id . '/worklog'),
icon('clock-history') . __('worklog.add')
@@ -572,13 +576,13 @@ function User_view(
icon('braces') . __('JSON Export')
) : '',
($its_me && (
- $auth->can('shifts_json_export')
- || $auth->can('ical')
- || $auth->can('atom')
- )) ? button(
- page_link_to('user_myshifts', ['reset' => 1]),
- icon('arrow-repeat') . __('Reset API key')
- ) : ''
+ $auth->can('shifts_json_export')
+ || $auth->can('ical')
+ || $auth->can('atom')
+ )) ? button(
+ page_link_to('user_myshifts', ['reset' => 1]),
+ icon('arrow-repeat') . __('Reset API key')
+ ) : ''
])
])
]),
@@ -591,7 +595,7 @@ function User_view(
. $user_source->contact->dect
. ''
)
- : '' ,
+ : '',
config('enable_mobile_show') && $user_source->contact->mobile ?
$user_source->settings->mobile_show ?
heading(
@@ -600,15 +604,15 @@ function User_view(
. $user_source->contact->mobile
. ''
)
- : ''
- : '' ,
+ : ''
+ : '',
$auth->can('user_messages') ?
heading(
''
. icon('envelope')
. ''
)
- : '' ,
+ : '',
]),
User_view_state($admin_user_privilege, $freeloader, $user_source),
User_angeltypes_render($user_angeltypes),
@@ -794,8 +798,8 @@ function User_oauth_render(User $user)
foreach ($user->oauth as $oauth) {
$output[] = __(
isset($config[$oauth->provider]['name'])
- ? $config[$oauth->provider]['name']
- : Str::ucfirst($oauth->provider)
+ ? $config[$oauth->provider]['name']
+ : Str::ucfirst($oauth->provider)
);
}
@@ -887,7 +891,7 @@ function render_user_departure_date_hint()
*/
function render_user_freeloader_hint()
{
- if (User_is_freeloader(auth()->user())) {
+ if (auth()->user()->isFreeloader()) {
return sprintf(
__('You freeloaded at least %s shifts. Shift signup is locked. Please go to heavens desk to be unlocked again.'),
config('max_freeloadable_shifts')
diff --git a/src/Controllers/Metrics/Stats.php b/src/Controllers/Metrics/Stats.php
index 5ae326e0..9e4fbbb6 100644
--- a/src/Controllers/Metrics/Stats.php
+++ b/src/Controllers/Metrics/Stats.php
@@ -45,27 +45,25 @@ class Stats
$query = State::whereArrived(true);
if (!is_null($working)) {
- // @codeCoverageIgnoreStart
$query
->leftJoin('worklogs', 'worklogs.user_id', '=', 'users_state.user_id')
- ->leftJoin('ShiftEntry', 'ShiftEntry.UID', '=', 'users_state.user_id')
+ ->leftJoin('shift_entries', 'shift_entries.user_id', '=', 'users_state.user_id')
->distinct();
$query->where(function ($query) use ($working): void {
/** @var QueryBuilder $query */
if ($working) {
$query
- ->whereNotNull('ShiftEntry.SID')
+ ->whereNotNull('shift_entries.shift_id')
->orWhereNotNull('worklogs.hours');
return;
}
$query
- ->whereNull('ShiftEntry.SID')
+ ->whereNull('shift_entries.shift_id')
->whereNull('worklogs.hours');
});
- // @codeCoverageIgnoreEnd
}
return $query->count('users_state.user_id');
@@ -104,18 +102,17 @@ class Stats
* The number of currently working users
*
* @param bool|null $freeloaded
- * @codeCoverageIgnore
*/
public function currentlyWorkingUsers(bool $freeloaded = null): int
{
$query = User::query()
- ->join('ShiftEntry', 'ShiftEntry.UID', '=', 'users.id')
- ->join('shifts', 'shifts.id', '=', 'ShiftEntry.SID')
+ ->join('shift_entries', 'shift_entries.user_id', '=', 'users.id')
+ ->join('shifts', 'shifts.id', '=', 'shift_entries.shift_id')
->where('shifts.start', '<=', Carbon::now())
->where('shifts.end', '>', Carbon::now());
if (!is_null($freeloaded)) {
- $query->where('ShiftEntry.freeloaded', '=', $freeloaded);
+ $query->where('shift_entries.freeloaded', '=', $freeloaded);
}
return $query->count();
@@ -202,13 +199,13 @@ class Stats
* @param bool|null $done
* @param bool|null $freeloaded
*
- * @codeCoverageIgnore
+ * @codeCoverageIgnore because it is only used in functions that use TIMESTAMPDIFF
*/
protected function workSecondsQuery(bool $done = null, bool $freeloaded = null): QueryBuilder
{
$query = $this
- ->getQuery('ShiftEntry')
- ->join('shifts', 'shifts.id', '=', 'ShiftEntry.SID');
+ ->getQuery('shift_entries')
+ ->join('shifts', 'shifts.id', '=', 'shift_entries.shift_id');
if (!is_null($freeloaded)) {
$query->where('freeloaded', '=', $freeloaded);
@@ -227,13 +224,13 @@ class Stats
* @param bool|null $done
* @param bool|null $freeloaded
*
- * @codeCoverageIgnore
+ * @codeCoverageIgnore as TIMESTAMPDIFF is not implemented in SQLite
*/
public function workSeconds(bool $done = null, bool $freeloaded = null): int
{
$query = $this->workSecondsQuery($done, $freeloaded);
- return (int) $query->sum($this->raw('end - start'));
+ return (int) $query->sum($this->raw('TIMESTAMPDIFF(MINUTE, start, end) * 60'));
}
/**
@@ -242,22 +239,19 @@ class Stats
* @param bool|null $done
* @param bool|null $freeloaded
*
- * @codeCoverageIgnore
+ * @codeCoverageIgnore as TIMESTAMPDIFF is not implemented in SQLite
*/
public function workBuckets(array $buckets, bool $done = null, bool $freeloaded = null): array
{
return $this->getBuckets(
$buckets,
$this->workSecondsQuery($done, $freeloaded),
- 'UID',
- 'SUM(end - start)',
- 'SUM(end - start)'
+ 'user_id',
+ 'SUM(TIMESTAMPDIFF(MINUTE, start, end) * 60)',
+ 'SUM(TIMESTAMPDIFF(MINUTE, start, end) * 60)'
);
}
- /**
- * @codeCoverageIgnore As long as its only used for old tables
- */
protected function getBuckets(
array $buckets,
BuilderContract $basicQuery,
@@ -281,18 +275,12 @@ class Stats
return $return;
}
- /**
- * @codeCoverageIgnore
- */
public function worklogSeconds(): int
{
return (int) Worklog::query()
->sum($this->raw('hours * 60 * 60'));
}
- /**
- * @codeCoverageIgnore
- */
public function worklogBuckets(array $buckets): array
{
return $this->getBuckets(
diff --git a/src/Models/AngelType.php b/src/Models/AngelType.php
index 085c1c15..a4543768 100644
--- a/src/Models/AngelType.php
+++ b/src/Models/AngelType.php
@@ -4,28 +4,31 @@ declare(strict_types=1);
namespace Engelsystem\Models;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Illuminate\Database\Eloquent\Builder;
use Engelsystem\Models\User\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Query\Builder as QueryBuilder;
/**
- * @property int $id
- * @property string $name
- * @property string $description
- * @property string $contact_name
- * @property string $contact_dect
- * @property string $contact_email
- * @property boolean $restricted # If users need an introduction
- * @property boolean $requires_driver_license # If users must have a driver license
- * @property boolean $no_self_signup # Users can sign up for shifts
- * @property boolean $show_on_dashboard # Show on public dashboard
- * @property boolean $hide_register # Hide from registration page
+ * @property int $id
+ * @property string $name
+ * @property string $description
+ * @property string $contact_name
+ * @property string $contact_dect
+ * @property string $contact_email
+ * @property boolean $restricted # If users need an introduction
+ * @property boolean $requires_driver_license # If users must have a driver license
+ * @property boolean $no_self_signup # Users can sign up for shifts
+ * @property boolean $show_on_dashboard # Show on public dashboard
+ * @property boolean $hide_register # Hide from registration page
*
- * @property-read Collection|User[] $userAngelTypes
- * @property-read UserAngelType $pivot
+ * @property-read UserAngelType $pivot
+ * @property-read Collection|ShiftEntry[] $shiftEntries
+ * @property-read Collection|User[] $userAngelTypes
*
* @method static QueryBuilder|AngelType[] whereId($value)
* @method static QueryBuilder|AngelType[] whereName($value)
@@ -68,6 +71,11 @@ class AngelType extends BaseModel
'hide_register' => 'boolean',
];
+ public function shiftEntries(): HasMany
+ {
+ return $this->hasMany(ShiftEntry::class);
+ }
+
public function userAngelTypes(): BelongsToMany
{
return $this
diff --git a/src/Models/Shifts/Shift.php b/src/Models/Shifts/Shift.php
index 9e8af282..21cdb0ac 100644
--- a/src/Models/Shifts/Shift.php
+++ b/src/Models/Shifts/Shift.php
@@ -8,31 +8,34 @@ use Carbon\Carbon;
use Engelsystem\Models\BaseModel;
use Engelsystem\Models\Room;
use Engelsystem\Models\User\User;
+use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
use Illuminate\Database\Query\Builder as QueryBuilder;
/**
- * @property int $id
- * @property string $title
- * @property string $description
- * @property string $url
- * @property Carbon $start
- * @property Carbon $end
- * @property int $shift_type_id
- * @property int $room_id
- * @property string $transaction_id
- * @property int $created_by
- * @property int|null $updated_by
- * @property Carbon|null $created_at
- * @property Carbon|null $updated_at
+ * @property int $id
+ * @property string $title
+ * @property string $description
+ * @property string $url
+ * @property Carbon $start
+ * @property Carbon $end
+ * @property int $shift_type_id
+ * @property int $room_id
+ * @property string $transaction_id
+ * @property int $created_by
+ * @property int|null $updated_by
+ * @property Carbon|null $created_at
+ * @property Carbon|null $updated_at
*
- * @property-read QueryBuilder|Schedule $schedule
- * @property-read QueryBuilder|ShiftType $shiftType
- * @property-read QueryBuilder|Room $room
- * @property-read QueryBuilder|User $createdBy
- * @property-read QueryBuilder|User|null $updatedBy
+ * @property-read QueryBuilder|Schedule $schedule
+ * @property-read QueryBuilder|Collection|ShiftEntry[] $shiftEntries
+ * @property-read QueryBuilder|ShiftType $shiftType
+ * @property-read QueryBuilder|Room $room
+ * @property-read QueryBuilder|User $createdBy
+ * @property-read QueryBuilder|User|null $updatedBy
*
* @method static QueryBuilder|Shift[] whereId($value)
* @method static QueryBuilder|Shift[] whereTitle($value)
@@ -88,6 +91,11 @@ class Shift extends BaseModel
return $this->hasOneThrough(Schedule::class, ScheduleShift::class, null, 'id', null, 'schedule_id');
}
+ public function shiftEntries(): HasMany
+ {
+ return $this->hasMany(ShiftEntry::class);
+ }
+
public function shiftType(): BelongsTo
{
return $this->belongsTo(ShiftType::class);
diff --git a/src/Models/Shifts/ShiftEntry.php b/src/Models/Shifts/ShiftEntry.php
new file mode 100644
index 00000000..5014bce1
--- /dev/null
+++ b/src/Models/Shifts/ShiftEntry.php
@@ -0,0 +1,63 @@
+ */
+ protected $fillable = [ // phpcs:ignore
+ 'shift_id',
+ 'angel_type_id',
+ 'user_id',
+ 'user_comment',
+ 'freeloaded',
+ 'freeloaded_comment',
+ ];
+
+ /** @var array default attributes */
+ protected $attributes = [ // phpcs:ignore
+ 'user_comment' => '',
+ 'freeloaded' => false,
+ 'freeloaded_comment' => '',
+ ];
+
+ public function shift(): BelongsTo
+ {
+ return $this->belongsTo(Shift::class);
+ }
+
+ public function angelType(): BelongsTo
+ {
+ return $this->belongsTo(AngelType::class);
+ }
+}
diff --git a/src/Models/User/User.php b/src/Models/User/User.php
index 15fccde0..baa771b7 100644
--- a/src/Models/User/User.php
+++ b/src/Models/User/User.php
@@ -13,6 +13,7 @@ use Engelsystem\Models\OAuth;
use Engelsystem\Models\Privilege;
use Engelsystem\Models\Question;
use Engelsystem\Models\Shifts\Shift;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\UserAngelType;
use Engelsystem\Models\Worklog;
use Illuminate\Database\Eloquent\Builder;
@@ -47,6 +48,7 @@ use Illuminate\Support\Collection as SupportCollection;
* @property-read SupportCollection|Privilege[] $privileges
* @property-read Collection|AngelType[] $userAngelTypes
* @property-read UserAngelType $pivot
+ * @property-read Collection|ShiftEntry[] $shiftEntries
* @property-read Collection|Worklog[] $worklogs
* @property-read Collection|Worklog[] $worklogsCreated
* @property-read Collection|Question[] $questionsAsked
@@ -109,6 +111,14 @@ class User extends BaseModel
return $this->belongsToMany(Group::class, 'users_groups');
}
+ public function isFreeloader(): bool
+ {
+ return $this->shiftEntries()
+ ->where('freeloaded', true)
+ ->count()
+ >= config('max_freeloadable_shifts');
+ }
+
public function license(): HasOne
{
return $this
@@ -189,6 +199,11 @@ class User extends BaseModel
return $this->hasMany(OAuth::class);
}
+ public function shiftEntries(): HasMany
+ {
+ return $this->hasMany(ShiftEntry::class);
+ }
+
public function worklogs(): HasMany
{
return $this->hasMany(Worklog::class);
diff --git a/src/Renderer/TwigServiceProvider.php b/src/Renderer/TwigServiceProvider.php
index 354c2c70..3bd4b0ee 100644
--- a/src/Renderer/TwigServiceProvider.php
+++ b/src/Renderer/TwigServiceProvider.php
@@ -76,8 +76,10 @@ class TwigServiceProvider extends ServiceProvider
$this->app->instance('twig.loader', $twigLoader);
$cache = $this->app->get('path.cache.views');
+ $twigDebug = false;
if ($config->get('environment') == 'development') {
$cache = false;
+ $twigDebug = true;
}
$twig = $this->app->make(
@@ -86,7 +88,8 @@ class TwigServiceProvider extends ServiceProvider
'options' => [
'cache' => $cache,
'auto_reload' => true,
- 'strict_variables' => ($config->get('environment') == 'development'),
+ 'debug' => $twigDebug,
+ 'strict_variables' => $twigDebug,
],
]
);
diff --git a/tests/Unit/Controllers/Metrics/StatsTest.php b/tests/Unit/Controllers/Metrics/StatsTest.php
index 9696178f..049608f7 100644
--- a/tests/Unit/Controllers/Metrics/StatsTest.php
+++ b/tests/Unit/Controllers/Metrics/StatsTest.php
@@ -13,6 +13,7 @@ use Engelsystem\Models\OAuth;
use Engelsystem\Models\Question;
use Engelsystem\Models\Room;
use Engelsystem\Models\Shifts\Shift;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\User\License;
use Engelsystem\Models\User\PasswordReset;
use Engelsystem\Models\User\PersonalData;
@@ -163,6 +164,35 @@ class StatsTest extends TestCase
$this->assertEquals(2.4 * 60 * 60 + 1.2 * 60 * 60, $seconds);
}
+ /**
+ * @covers \Engelsystem\Controllers\Metrics\Stats::worklogBuckets
+ * @covers \Engelsystem\Controllers\Metrics\Stats::getBuckets
+ */
+ public function testWorklogBuckets(): void
+ {
+ Worklog::factory()->create(['hours' => 1.2, 'worked_at' => Carbon::now()->subDay()]);
+ Worklog::factory()->create(['hours' => 1.9, 'worked_at' => Carbon::now()->subDay()]);
+ Worklog::factory()->create(['hours' => 3, 'worked_at' => Carbon::now()->subDay()]);
+ Worklog::factory()->create(['hours' => 10, 'worked_at' => Carbon::now()->subDay()]);
+
+ $stats = new Stats($this->database);
+ $buckets = $stats->worklogBuckets([
+ 1 * 60 * 60,
+ 2 * 60 * 60,
+ 3 * 60 * 60,
+ 4 * 60 * 60,
+ '+Inf'
+ ]);
+
+ $this->assertEquals([
+ 3600 => 0,
+ 7200 => 2,
+ 10800 => 3,
+ 14400 => 3,
+ '+Inf' => 4,
+ ], $buckets);
+ }
+
/**
* @covers \Engelsystem\Controllers\Metrics\Stats::rooms
*/
@@ -251,9 +281,13 @@ class StatsTest extends TestCase
public function testArrivedUsers(): void
{
$this->addUsers();
+ ShiftEntry::factory()->create(['user_id' => 3]);
+ ShiftEntry::factory()->create(['user_id' => 4]);
$stats = new Stats($this->database);
$this->assertEquals(7, $stats->arrivedUsers());
+ $this->assertEquals(5, $stats->arrivedUsers(false));
+ $this->assertEquals(2, $stats->arrivedUsers(true));
}
/**
@@ -293,6 +327,25 @@ class StatsTest extends TestCase
$this->assertEquals(1, $stats->email('news'));
}
+ /**
+ * @covers \Engelsystem\Controllers\Metrics\Stats::currentlyWorkingUsers
+ */
+ public function testCurrentlyWorkingUsers(): void
+ {
+ $this->addUsers();
+ /** @var Shift $shift */
+ $shift = Shift::factory()->create(['start' => Carbon::now()->subHour(), 'end' => Carbon::now()->addHour()]);
+
+ ShiftEntry::factory()->create(['shift_id' => $shift->id]);
+ ShiftEntry::factory()->create(['shift_id' => $shift->id]);
+ ShiftEntry::factory()->create(['shift_id' => $shift->id, 'freeloaded' => true]);
+
+ $stats = new Stats($this->database);
+ $this->assertEquals(3, $stats->currentlyWorkingUsers());
+ $this->assertEquals(2, $stats->currentlyWorkingUsers(false));
+ $this->assertEquals(1, $stats->currentlyWorkingUsers(true));
+ }
+
/**
* @covers \Engelsystem\Controllers\Metrics\Stats::faq
*/
diff --git a/tests/Unit/FactoriesTest.php b/tests/Unit/FactoriesTest.php
index 01c18dda..4ea8c3f7 100644
--- a/tests/Unit/FactoriesTest.php
+++ b/tests/Unit/FactoriesTest.php
@@ -10,6 +10,7 @@ use Engelsystem\Models\Question;
use Engelsystem\Models\Room;
use Engelsystem\Models\Shifts\Schedule;
use Engelsystem\Models\Shifts\Shift;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\User\Contact;
use Engelsystem\Models\User\License;
use Engelsystem\Models\User\PasswordReset;
@@ -41,6 +42,7 @@ class FactoriesTest extends TestCase
[Question::class],
[Room::class],
[Schedule::class],
+ [ShiftEntry::class],
[Settings::class],
[Shift::class],
[State::class],
diff --git a/tests/Unit/Models/AngelTypeTest.php b/tests/Unit/Models/AngelTypeTest.php
index 7e3d43e6..d21ffcff 100644
--- a/tests/Unit/Models/AngelTypeTest.php
+++ b/tests/Unit/Models/AngelTypeTest.php
@@ -3,6 +3,7 @@
namespace Engelsystem\Test\Unit\Models;
use Engelsystem\Models\AngelType;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
@@ -47,8 +48,7 @@ class AngelTypeTest extends ModelTest
User::factory(1)->create();
$user2 = User::factory()->create();
- $angelType = new AngelType(['name' => 'Test']);
- $angelType->save();
+ $angelType = AngelType::create(['name' => 'Test']);
$angelType->userAngelTypes()->attach($user1);
$angelType->userAngelTypes()->attach($user2);
@@ -61,6 +61,18 @@ class AngelTypeTest extends ModelTest
$this->assertCount(2, $angeltypes);
}
+ /**
+ * @covers \Engelsystem\Models\AngelType::shiftEntries
+ */
+ public function testShiftEntries(): void
+ {
+ $angelType = AngelType::create(['name' => 'test type']);
+
+ ShiftEntry::factory(3)->create(['angel_type_id' => $angelType->id]);
+
+ $this->assertCount(3, $angelType->shiftEntries);
+ }
+
/**
* @covers \Engelsystem\Models\AngelType::boot
*/
diff --git a/tests/Unit/Models/Shifts/ShiftEntryTest.php b/tests/Unit/Models/Shifts/ShiftEntryTest.php
new file mode 100644
index 00000000..af47c44d
--- /dev/null
+++ b/tests/Unit/Models/Shifts/ShiftEntryTest.php
@@ -0,0 +1,37 @@
+create();
+ /** @var AngelType $angelType */
+ $angelType = AngelType::factory()->create();
+ /** @var User $user */
+ $user = User::factory()->create();
+
+ $model = new ShiftEntry();
+ $model->shift()->associate($shift);
+ $model->angelType()->associate($angelType);
+ $model->user()->associate($user);
+ $model->save();
+
+ $model = ShiftEntry::find(1);
+ $this->assertEquals($shift->id, $model->shift->id);
+ $this->assertEquals($angelType->id, $model->angelType->id);
+ $this->assertEquals($user->id, $model->user->id);
+ }
+}
diff --git a/tests/Unit/Models/Shifts/ShiftTest.php b/tests/Unit/Models/Shifts/ShiftTest.php
index b74855d2..fae30feb 100644
--- a/tests/Unit/Models/Shifts/ShiftTest.php
+++ b/tests/Unit/Models/Shifts/ShiftTest.php
@@ -9,6 +9,7 @@ use Engelsystem\Models\Room;
use Engelsystem\Models\Shifts\Schedule;
use Engelsystem\Models\Shifts\ScheduleShift;
use Engelsystem\Models\Shifts\Shift;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\Shifts\ShiftType;
use Engelsystem\Models\User\User;
use Engelsystem\Test\Unit\Models\ModelTest;
@@ -73,4 +74,18 @@ class ShiftTest extends ModelTest
$this->assertEquals(1, Shift::find(2)->schedule->id);
$this->assertEquals(1, Shift::find(3)->schedule->id);
}
+
+ /**
+ * @covers \Engelsystem\Models\Shifts\Shift::shiftEntries
+ */
+ public function testShiftEntries(): void
+ {
+ /** @var Shift $shift */
+ $shift = Shift::factory()->make();
+ $shift->save();
+
+ ShiftEntry::factory(5)->create(['shift_id' => $shift->id]);
+
+ $this->assertCount(5, $shift->shiftEntries);
+ }
}
diff --git a/tests/Unit/Models/User/UserTest.php b/tests/Unit/Models/User/UserTest.php
index f4e38d51..a2679e8f 100644
--- a/tests/Unit/Models/User/UserTest.php
+++ b/tests/Unit/Models/User/UserTest.php
@@ -4,6 +4,7 @@ namespace Engelsystem\Test\Unit\Models\User;
use Carbon\Carbon;
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
+use Engelsystem\Config\Config;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\BaseModel;
use Engelsystem\Models\Group;
@@ -13,6 +14,7 @@ use Engelsystem\Models\OAuth;
use Engelsystem\Models\Privilege;
use Engelsystem\Models\Question;
use Engelsystem\Models\Shifts\Shift;
+use Engelsystem\Models\Shifts\ShiftEntry;
use Engelsystem\Models\User\Contact;
use Engelsystem\Models\User\HasUserModel;
use Engelsystem\Models\User\License;
@@ -209,6 +211,30 @@ class UserTest extends ModelTest
$this->assertEquals($relatedModelIds, $user->{$name}->modelKeys());
}
+ /**
+ * @covers \Engelsystem\Models\User\User::isFreeloader
+ */
+ public function testIsFreeloader(): void
+ {
+ $this->app->instance('config', new Config([
+ 'max_freeloadable_shifts' => 2,
+ ]));
+
+ $user = new User($this->data);
+ $user->save();
+ $this->assertFalse($user->isFreeloader());
+
+ ShiftEntry::factory()->create(['user_id' => $user->id]);
+ ShiftEntry::factory()->create(['user_id' => $user->id, 'freeloaded' => true]);
+ $this->assertFalse($user->isFreeloader());
+
+ ShiftEntry::factory()->create(['user_id' => $user->id, 'freeloaded' => true]);
+ $this->assertTrue($user->isFreeloader());
+
+ ShiftEntry::factory()->create(['user_id' => $user->id, 'freeloaded' => true]);
+ $this->assertTrue($user->isFreeloader());
+ }
+
/**
* @covers \Engelsystem\Models\User\User::userAngelTypes
*/
@@ -334,6 +360,19 @@ class UserTest extends ModelTest
$this->assertCount(1, $oauth);
}
+ /**
+ * @covers \Engelsystem\Models\User\User::shiftEntries
+ */
+ public function testShiftEntries(): void
+ {
+ $user = new User($this->data);
+ $user->save();
+
+ ShiftEntry::factory(2)->create(['user_id' => $user->id]);
+
+ $this->assertCount(2, $user->shiftEntries);
+ }
+
/**
* @covers \Engelsystem\Models\User\User::worklogs
*/
diff --git a/tests/Unit/Renderer/Twig/Extensions/ExtensionTest.php b/tests/Unit/Renderer/Twig/Extensions/ExtensionTest.php
index 188463a0..2d512daf 100644
--- a/tests/Unit/Renderer/Twig/Extensions/ExtensionTest.php
+++ b/tests/Unit/Renderer/Twig/Extensions/ExtensionTest.php
@@ -40,7 +40,7 @@ abstract class ExtensionTest extends TestCase
*/
protected function assertExtensionExists(
string $name,
- callable $callback,
+ mixed $callback,
array $functions,
array $options = []
): void {
diff --git a/tests/Unit/Renderer/TwigServiceProviderTest.php b/tests/Unit/Renderer/TwigServiceProviderTest.php
index c05937ee..0b289128 100644
--- a/tests/Unit/Renderer/TwigServiceProviderTest.php
+++ b/tests/Unit/Renderer/TwigServiceProviderTest.php
@@ -136,7 +136,12 @@ class TwigServiceProviderTest extends ServiceProviderTest
->method('make')
->withConsecutive(
[TwigLoader::class, ['paths' => $viewsPath]],
- [Twig::class, ['options' => ['cache' => false, 'auto_reload' => true, 'strict_variables' => true]]],
+ [Twig::class, ['options' => [
+ 'cache' => false,
+ 'auto_reload' => true,
+ 'strict_variables' => true,
+ 'debug' => true,
+ ]]],
[TwigEngine::class]
)->willReturnOnConsecutiveCalls(
$twigLoader,
@@ -162,10 +167,10 @@ class TwigServiceProviderTest extends ServiceProviderTest
$this->setExpects($app, 'tag', ['renderer.twigEngine', ['renderer.engine']]);
- $config->expects($this->exactly(3))
+ $config->expects($this->exactly(2))
->method('get')
- ->withConsecutive(['environment'], ['environment'], ['timezone'])
- ->willReturnOnConsecutiveCalls('development', 'development', 'The/World');
+ ->withConsecutive(['environment'], ['timezone'])
+ ->willReturnOnConsecutiveCalls('development', 'The/World');
$twig->expects($this->once())
->method('getExtension')