Added UserAngelType model

This commit is contained in:
Igor Scheller 2022-12-03 00:57:04 +01:00 committed by Michael Weimann
parent 99e7a088b0
commit 7f78f59840
27 changed files with 686 additions and 533 deletions

View File

@ -0,0 +1,27 @@
<?php
namespace Database\Factories\Engelsystem\Models;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
use Illuminate\Database\Eloquent\Factories\Factory;
class UserAngelTypeFactory extends Factory
{
/** @var string */
protected $model = UserAngelType::class;
/**
* @return array
*/
public function definition(): array
{
return [
'user_id' => User::factory(),
'angel_type_id' => AngelType::factory(),
'confirm_user_id' => $this->faker->optional()->passthrough(User::factory()),
'supporter' => $this->faker->boolean(),
];
}
}

View File

@ -0,0 +1,101 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Migrations;
use Engelsystem\Database\Migration\Migration;
use Illuminate\Database\Schema\Blueprint;
use stdClass;
class CreateUserAngelTypesTable extends Migration
{
use ChangesReferences;
use Reference;
/**
* Creates the new table, copies the data and drops the old one
*/
public function up(): void
{
$connection = $this->schema->getConnection();
$this->schema->create('user_angel_type', function (Blueprint $table) {
$table->increments('id');
$this->referencesUser($table);
$this->references($table, 'angel_types')->index();
$this->references($table, 'users', 'confirm_user_id')->nullable()->default(null)->index();
$table->boolean('supporter')->default(false)->index();
$table->index(['user_id', 'angel_type_id', 'confirm_user_id']);
$table->unique(['user_id', 'angel_type_id']);
});
if (!$this->schema->hasTable('UserAngelTypes')) {
return;
}
/** @var stdClass[] $records */
$records = $connection
->table('UserAngelTypes')
->get();
foreach ($records as $record) {
$connection->table('user_angel_type')->insert([
'id' => $record->id,
'user_id' => $record->user_id,
'angel_type_id' => $record->angeltype_id,
'confirm_user_id' => $record->confirm_user_id ?: null,
'supporter' => (bool)$record->supporter,
]);
}
$this->changeReferences(
'UserAngelTypes',
'id',
'user_angel_type',
'id'
);
$this->schema->drop('UserAngelTypes');
}
/**
* Recreates the previous table, copies the data and drops the new one
*/
public function down(): void
{
$connection = $this->schema->getConnection();
$this->schema->create('UserAngelTypes', function (Blueprint $table) {
$table->increments('id');
$this->referencesUser($table);
$this->references($table, 'angel_types', 'angeltype_id')->index('angeltype_id');
$this->references($table, 'users', 'confirm_user_id')->nullable()->index('confirm_user_id');
$table->boolean('supporter')->nullable()->index('coordinator');
$table->index(['user_id', 'angeltype_id', 'confirm_user_id'], 'user_id');
});
/** @var stdClass[] $records */
$records = $connection
->table('user_angel_type')
->get();
foreach ($records as $record) {
$connection->table('UserAngelTypes')->insert([
'id' => $record->id,
'user_id' => $record->user_id,
'angeltype_id' => $record->angel_type_id,
'confirm_user_id' => $record->confirm_user_id ?: null,
'supporter' => (bool)$record->supporter,
]);
}
$this->changeReferences(
'user_angel_type',
'id',
'UserAngelTypes',
'id',
'integer'
);
$this->schema->drop('user_angel_type');
}
}

View File

@ -1,6 +1,7 @@
<?php <?php
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Engelsystem\Models\UserAngelType;
use Engelsystem\ShiftsFilter; use Engelsystem\ShiftsFilter;
use Engelsystem\ShiftsFilterRenderer; use Engelsystem\ShiftsFilterRenderer;
use Engelsystem\ValidationResult; use Engelsystem\ValidationResult;
@ -45,7 +46,7 @@ function angeltypes_controller()
* Path to angeltype view. * Path to angeltype view.
* *
* @param int $angeltype_id AngelType id * @param int $angeltype_id AngelType id
* @param array $params additional params * @param array $params additional params
* @return string * @return string
*/ */
function angeltype_link($angeltype_id, $params = []) function angeltype_link($angeltype_id, $params = [])
@ -116,7 +117,7 @@ function angeltype_edit_controller()
// Edit existing angeltype // Edit existing angeltype
$angeltype = AngelType::findOrFail($request->input('angeltype_id')); $angeltype = AngelType::findOrFail($request->input('angeltype_id'));
if (!User_is_AngelType_supporter(auth()->user(), $angeltype)) { if (!auth()->user()->isAngelTypeSupporter($angeltype) && !auth()->can('admin_user_angeltypes')) {
throw_redirect(page_link_to('angeltypes')); throw_redirect(page_link_to('angeltypes'));
} }
} else { } else {
@ -193,8 +194,9 @@ function angeltype_controller()
} }
$angeltype = AngelType::findOrFail(request()->input('angeltype_id')); $angeltype = AngelType::findOrFail(request()->input('angeltype_id'));
$user_angeltype = UserAngelType_by_User_and_AngelType($user->id, $angeltype); /** @var UserAngelType $user_angeltype */
$members = Users_by_angeltype($angeltype); $user_angeltype = UserAngelType::whereUserId($user->id)->where('angel_type_id', $angeltype->id)->first();
$members = $angeltype->userAngelTypes->sortBy('name');
$days = angeltype_controller_shiftsFilterDays($angeltype); $days = angeltype_controller_shiftsFilterDays($angeltype);
$shiftsFilter = angeltype_controller_shiftsFilter($angeltype, $days); $shiftsFilter = angeltype_controller_shiftsFilter($angeltype, $days);
@ -210,7 +212,7 @@ function angeltype_controller()
$tab = 1; $tab = 1;
} }
$isSupporter = !is_null($user_angeltype) && $user_angeltype['supporter']; $isSupporter = !is_null($user_angeltype) && $user_angeltype->supporter;
return [ return [
sprintf(__('Team %s'), $angeltype->name), sprintf(__('Team %s'), $angeltype->name),
AngelType_view( AngelType_view(
@ -291,7 +293,6 @@ function angeltypes_list_controller()
} }
$angeltypes = AngelTypes_with_user($user->id); $angeltypes = AngelTypes_with_user($user->id);
foreach ($angeltypes as $angeltype) { foreach ($angeltypes as $angeltype) {
$actions = [ $actions = [
button( button(
@ -315,11 +316,11 @@ function angeltypes_list_controller()
} }
$angeltype->membership = AngelType_render_membership($angeltype); $angeltype->membership = AngelType_render_membership($angeltype);
if (!empty($angeltype->user_angeltype_id)) { if (!empty($angeltype->user_angel_type_id)) {
$actions[] = button( $actions[] = button(
page_link_to( page_link_to(
'user_angeltypes', 'user_angeltypes',
['action' => 'delete', 'user_angeltype_id' => $angeltype->user_angeltype_id] ['action' => 'delete', 'user_angeltype_id' => $angeltype->user_angel_type_id]
), ),
icon('box-arrow-right') . __('leave'), icon('box-arrow-right') . __('leave'),
'btn-sm' 'btn-sm'
@ -387,13 +388,13 @@ function AngelTypes_with_user($userId): Collection
return AngelType::query() return AngelType::query()
->select([ ->select([
'angel_types.*', 'angel_types.*',
'UserAngelTypes.id AS user_angeltype_id', 'user_angel_type.id AS user_angel_type_id',
'UserAngelTypes.confirm_user_id', 'user_angel_type.confirm_user_id',
'UserAngelTypes.supporter', 'user_angel_type.supporter',
]) ])
->leftJoin('UserAngelTypes', function (JoinClause $join) use ($userId) { ->leftJoin('user_angel_type', function (JoinClause $join) use ($userId) {
$join->on('angel_types.id', 'UserAngelTypes.angeltype_id'); $join->on('angel_types.id', 'user_angel_type.angel_type_id');
$join->where('UserAngelTypes.user_id', $userId); $join->where('user_angel_type.user_id', $userId);
}) })
->get(); ->get();
} }

View File

@ -3,6 +3,7 @@
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Engelsystem\Models\Room; use Engelsystem\Models\Room;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
use Engelsystem\ShiftSignupState; use Engelsystem\ShiftSignupState;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
@ -62,7 +63,7 @@ function shift_entry_create_controller(): array
throw_redirect(user_link($user->id)); throw_redirect(user_link($user->id));
} }
if (User_is_AngelType_supporter($user, $angeltype)) { if ($user->isAngelTypeSupporter($angeltype) || auth()->can('admin_user_angeltypes')) {
return shift_entry_create_controller_supporter($shift, $angeltype); return shift_entry_create_controller_supporter($shift, $angeltype);
} }
@ -145,7 +146,8 @@ function shift_entry_create_controller_supporter($shift, AngelType $angeltype):
if ($request->has('user_id')) { if ($request->has('user_id')) {
$signup_user = User::find($request->input('user_id')); $signup_user = User::find($request->input('user_id'));
} }
if (!UserAngelType_exists($signup_user->id, $angeltype)) {
if (!$signup_user->userAngelTypes()->wherePivot('angel_type_id', $angeltype->id)->exists()) {
error(__('User is not in angeltype.')); error(__('User is not in angeltype.'));
throw_redirect(shift_link($shift)); throw_redirect(shift_link($shift));
} }
@ -164,7 +166,7 @@ function shift_entry_create_controller_supporter($shift, AngelType $angeltype):
throw_redirect(shift_link($shift)); throw_redirect(shift_link($shift));
} }
$users = Users_by_angeltype($angeltype); $users = $angeltype->userAngelTypes->sortBy('name');
$users_select = []; $users_select = [];
foreach ($users as $u) { foreach ($users as $u) {
$users_select[$u->id] = $u->name; $users_select[$u->id] = $u->name;
@ -205,7 +207,7 @@ function shift_entry_error_message(ShiftSignupState $shift_signup_state)
* Sign up for a shift. * Sign up for a shift.
* Case: User * Case: User
* *
* @param array $shift * @param array $shift
* @param AngelType $angeltype * @param AngelType $angeltype
* @return array * @return array
*/ */
@ -242,8 +244,14 @@ function shift_entry_create_controller_user($shift, AngelType $angeltype): array
'freeload_comment' => '' 'freeload_comment' => ''
]); ]);
if (!$angeltype->restricted && !UserAngelType_exists($signup_user->id, $angeltype)) { if (
UserAngelType_create($signup_user->id, $angeltype); !$angeltype->restricted
&& !$angeltype->userAngelTypes()->wherePivot('user_id', $signup_user->id)->exists()
) {
$userAngelType = new UserAngelType();
$userAngelType->user()->associate($signup_user);
$userAngelType->angelType()->associate($angeltype);
$userAngelType->save();
} }
success(__('You are subscribed. Thank you!')); success(__('You are subscribed. Thank you!'));
@ -260,9 +268,9 @@ function shift_entry_create_controller_user($shift, AngelType $angeltype): array
/** /**
* Link to create a shift entry. * Link to create a shift entry.
* *
* @param array $shift * @param array $shift
* @param AngelType $angeltype * @param AngelType $angeltype
* @param array $params * @param array $params
* @return string URL * @return string URL
*/ */
function shift_entry_create_link($shift, AngelType $angeltype, $params = []) function shift_entry_create_link($shift, AngelType $angeltype, $params = [])

View File

@ -3,6 +3,8 @@
use Engelsystem\Mail\EngelsystemMailer; use Engelsystem\Mail\EngelsystemMailer;
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
use Illuminate\Database\Eloquent\Collection;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Mailer\Exception\TransportException; use Symfony\Component\Mailer\Exception\TransportException;
@ -13,21 +15,36 @@ use Symfony\Component\Mailer\Exception\TransportException;
*/ */
function user_angeltypes_unconfirmed_hint() function user_angeltypes_unconfirmed_hint()
{ {
$unconfirmed_user_angeltypes = User_unconfirmed_AngelTypes(auth()->user()->id); $restrictedSupportedAngelTypes = auth()
if (count($unconfirmed_user_angeltypes) == 0) { ->user()
->userAngelTypes()
->wherePivot('supporter', true)
->where('restricted', true)
->get();
/** @var Collection|UserAngelType[] $unconfirmed_user_angeltypes */
$unconfirmed_user_angeltypes = UserAngelType::query()
->with('AngelType')
->select(['user_angel_type.*', UserAngelType::query()->raw('count(angel_type_id) as users_count')])
->whereIn('angel_type_id', $restrictedSupportedAngelTypes->pluck('id')->toArray())
->whereNull('confirm_user_id')
->groupBy('angel_type_id')
->get();
if (!$unconfirmed_user_angeltypes->count()) {
return null; return null;
} }
$unconfirmed_links = []; $unconfirmed_links = [];
foreach ($unconfirmed_user_angeltypes as $user_angeltype) { foreach ($unconfirmed_user_angeltypes as $user_angeltype) {
$unconfirmed_links[] = '<a class="text-info" href="' $unconfirmed_links[] = '<a class="text-info" href="'
. page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $user_angeltype['angeltype_id']]) . page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $user_angeltype->angel_type_id])
. '">' . $user_angeltype['name'] . '">' . $user_angeltype->angelType->name
. ' (+' . $user_angeltype['count'] . ')' . ' (+' . $user_angeltype->count . ')'
. '</a>'; . '</a>';
} }
$count = count($unconfirmed_user_angeltypes); $count = $unconfirmed_user_angeltypes->count();
return return
_e( _e(
'There is %d unconfirmed angeltype.', 'There is %d unconfirmed angeltype.',
@ -53,19 +70,16 @@ function user_angeltypes_delete_all_controller(): array
throw_redirect(page_link_to('angeltypes')); throw_redirect(page_link_to('angeltypes'));
} }
$angeltype = AngelType::find($request->input('angeltype_id')); $angeltype = AngelType::findOrFail($request->input('angeltype_id'));
if (empty($angeltype)) { if (!auth()->user()->isAngelTypeSupporter($angeltype) && !auth()->can('admin_user_angeltypes')) {
error(__('Angeltype doesn\'t exist.'));
throw_redirect(page_link_to('angeltypes'));
}
if (!User_is_AngelType_supporter(auth()->user(), $angeltype)) {
error(__('You are not allowed to delete all users for this angeltype.')); error(__('You are not allowed to delete all users for this angeltype.'));
throw_redirect(page_link_to('angeltypes')); throw_redirect(page_link_to('angeltypes'));
} }
if ($request->hasPostData('deny_all')) { if ($request->hasPostData('deny_all')) {
UserAngelTypes_delete_all_unconfirmed($angeltype->id); UserAngelType::whereAngelTypeId($angeltype->id)
->whereNull('confirm_user_id')
->delete();
engelsystem_log(sprintf('Denied all users for angeltype %s', AngelType_name_render($angeltype, true))); engelsystem_log(sprintf('Denied all users for angeltype %s', AngelType_name_render($angeltype, true)));
success(sprintf(__('Denied all users for angeltype %s.'), AngelType_name_render($angeltype))); success(sprintf(__('Denied all users for angeltype %s.'), AngelType_name_render($angeltype)));
@ -94,20 +108,22 @@ function user_angeltypes_confirm_all_controller(): array
} }
$angeltype = AngelType::findOrFail($request->input('angeltype_id')); $angeltype = AngelType::findOrFail($request->input('angeltype_id'));
if (!auth()->can('admin_user_angeltypes') && !User_is_AngelType_supporter($user, $angeltype)) { if (!auth()->can('admin_user_angeltypes') && !$user->isAngelTypeSupporter($angeltype)) {
error(__('You are not allowed to confirm all users for this angeltype.')); error(__('You are not allowed to confirm all users for this angeltype.'));
throw_redirect(page_link_to('angeltypes')); throw_redirect(page_link_to('angeltypes'));
} }
if ($request->hasPostData('confirm_all')) { if ($request->hasPostData('confirm_all')) {
$users = UserAngelTypes_all_unconfirmed($angeltype->id); /** @var Collection|User[] $users */
UserAngelTypes_confirm_all($angeltype->id, $user->id); $users = $angeltype->userAngelTypes()->wherePivot('confirm_user_id', '=', null)->get();
UserAngelType::whereAngelTypeId($angeltype->id)
->whereNull('confirm_user_id')
->update(['confirm_user_id' => $user->id]);
engelsystem_log(sprintf('Confirmed all users for angeltype %s', AngelType_name_render($angeltype, true))); engelsystem_log(sprintf('Confirmed all users for angeltype %s', AngelType_name_render($angeltype, true)));
success(sprintf(__('Confirmed all users for angeltype %s.'), AngelType_name_render($angeltype))); success(sprintf(__('Confirmed all users for angeltype %s.'), AngelType_name_render($angeltype)));
foreach ($users as $user) { foreach ($users as $user) {
$user = User::find($user['user_id']);
user_angeltype_confirm_email($user, $angeltype); user_angeltype_confirm_email($user, $angeltype);
} }
@ -135,26 +151,18 @@ function user_angeltype_confirm_controller(): array
throw_redirect(page_link_to('angeltypes')); throw_redirect(page_link_to('angeltypes'));
} }
$user_angeltype = UserAngelType($request->input('user_angeltype_id')); /** @var UserAngelType $user_angeltype */
if (empty($user_angeltype)) { $user_angeltype = UserAngelType::findOrFail($request->input('user_angeltype_id'));
error(__('User angeltype doesn\'t exist.')); $angeltype = $user_angeltype->angelType;
throw_redirect(page_link_to('angeltypes')); if (!$user->isAngelTypeSupporter($angeltype) && !auth()->can('admin_user_angeltypes')) {
}
$angeltype = AngelType::findOrFail($user_angeltype['angeltype_id']);
if (!User_is_AngelType_supporter($user, $angeltype)) {
error(__('You are not allowed to confirm this users angeltype.')); error(__('You are not allowed to confirm this users angeltype.'));
throw_redirect(page_link_to('angeltypes')); throw_redirect(page_link_to('angeltypes'));
} }
$user_source = User::find($user_angeltype['user_id']); $user_source = $user_angeltype->user;
if (!$user_source) {
error(__('User doesn\'t exist.'));
throw_redirect(page_link_to('angeltypes'));
}
if ($request->hasPostData('confirm_user')) { if ($request->hasPostData('confirm_user')) {
UserAngelType_confirm($user_angeltype['id'], $user->id); $user_angeltype->confirmUser()->associate($user);
$user_angeltype->save();
engelsystem_log(sprintf( engelsystem_log(sprintf(
'%s confirmed for angeltype %s', '%s confirmed for angeltype %s',
@ -253,21 +261,21 @@ function user_angeltype_delete_controller(): array
throw_redirect(page_link_to('angeltypes')); throw_redirect(page_link_to('angeltypes'));
} }
$user_angeltype = UserAngelType($request->input('user_angeltype_id')); /** @var UserAngelType $user_angeltype */
if (empty($user_angeltype)) { $user_angeltype = UserAngelType::findOrFail($request->input('user_angeltype_id'));
error(__('User angeltype doesn\'t exist.')); $angeltype = $user_angeltype->angelType;
throw_redirect(page_link_to('angeltypes')); $user_source = $user_angeltype->user;
} if (
$user->id != $user_angeltype->user_id
$angeltype = AngelType::findOrFail($user_angeltype['angeltype_id']); && !$user->isAngelTypeSupporter($angeltype)
$user_source = User::findOrFail($user_angeltype['user_id']); && !auth()->can('admin_user_angeltypes')
if ($user->id != $user_angeltype['user_id'] && !User_is_AngelType_supporter($user, $angeltype)) { ) {
error(__('You are not allowed to delete this users angeltype.')); error(__('You are not allowed to delete this users angeltype.'));
throw_redirect(page_link_to('angeltypes')); throw_redirect(page_link_to('angeltypes'));
} }
if ($request->hasPostData('delete')) { if ($request->hasPostData('delete')) {
UserAngelType_delete($user_angeltype); $user_angeltype->delete();
engelsystem_log(sprintf('User %s removed from %s.', User_Nick_render($user_source, true), $angeltype->name)); engelsystem_log(sprintf('User %s removed from %s.', User_Nick_render($user_source, true), $angeltype->name));
success(sprintf(__('User %s removed from %s.'), User_Nick_render($user_source), $angeltype->name)); success(sprintf(__('User %s removed from %s.'), User_Nick_render($user_source), $angeltype->name));
@ -308,17 +316,14 @@ function user_angeltype_update_controller(): array
throw_redirect(page_link_to('angeltypes')); throw_redirect(page_link_to('angeltypes'));
} }
$user_angeltype = UserAngelType($request->input('user_angeltype_id')); /** @var UserAngelType $user_angeltype */
if (empty($user_angeltype)) { $user_angeltype = UserAngelType::findOrFail($request->input('user_angeltype_id'));
error(__('User angeltype doesn\'t exist.')); $angeltype = $user_angeltype->angelType;
throw_redirect(page_link_to('angeltypes')); $user_source = $user_angeltype->user;
}
$angeltype = AngelType::findOrFail($user_angeltype['angeltype_id']);
$user_source = User::findOrFail($user_angeltype['user_id']);
if ($request->hasPostData('submit')) { if ($request->hasPostData('submit')) {
UserAngelType_update($user_angeltype['id'], $supporter); $user_angeltype->supporter = $supporter;
$user_angeltype->save();
$msg = $supporter $msg = $supporter
? __('Added supporter rights for %s to %s.') ? __('Added supporter rights for %s to %s.')
@ -353,7 +358,7 @@ function user_angeltype_add_controller(): array
$angeltype = AngelType::findOrFail(request()->input('angeltype_id')); $angeltype = AngelType::findOrFail(request()->input('angeltype_id'));
// User is joining by itself // User is joining by itself
if (!User_is_AngelType_supporter(auth()->user(), $angeltype)) { if (!auth()->user()->isAngelTypeSupporter($angeltype) && !auth()->can('admin_user_angeltypes')) {
return user_angeltype_join_controller($angeltype); return user_angeltype_join_controller($angeltype);
} }
@ -369,8 +374,11 @@ function user_angeltype_add_controller(): array
if ($request->hasPostData('submit')) { if ($request->hasPostData('submit')) {
$user_source = load_user(); $user_source = load_user();
if (!UserAngelType_exists($user_source->id, $angeltype)) { if (!$angeltype->userAngelTypes()->wherePivot('user_id', $user_source->id)->exists()) {
$user_angeltype_id = UserAngelType_create($user_source->id, $angeltype); $userAngelType = new UserAngelType();
$userAngelType->user()->associate($user_source);
$userAngelType->angelType()->associate($angeltype);
$userAngelType->save();
engelsystem_log(sprintf( engelsystem_log(sprintf(
'User %s added to %s.', 'User %s added to %s.',
@ -384,7 +392,9 @@ function user_angeltype_add_controller(): array
)); ));
if ($request->hasPostData('auto_confirm_user')) { if ($request->hasPostData('auto_confirm_user')) {
UserAngelType_confirm($user_angeltype_id, $user_source->id); $userAngelType->confirmUser()->associate($user_source);
$userAngelType->save();
engelsystem_log(sprintf( engelsystem_log(sprintf(
'User %s confirmed as %s.', 'User %s confirmed as %s.',
User_Nick_render($user_source, true), User_Nick_render($user_source, true),
@ -414,7 +424,8 @@ function user_angeltype_join_controller(AngelType $angeltype)
{ {
$user = auth()->user(); $user = auth()->user();
$user_angeltype = UserAngelType_by_User_and_AngelType($user->id, $angeltype); /** @var UserAngelType $user_angeltype */
$user_angeltype = UserAngelType::whereUserId($user->id)->where('angel_type_id', $angeltype->id)->first();
if (!empty($user_angeltype)) { if (!empty($user_angeltype)) {
error(sprintf(__('You are already a %s.'), $angeltype->name)); error(sprintf(__('You are already a %s.'), $angeltype->name));
throw_redirect(page_link_to('angeltypes')); throw_redirect(page_link_to('angeltypes'));
@ -422,18 +433,22 @@ function user_angeltype_join_controller(AngelType $angeltype)
$request = request(); $request = request();
if ($request->hasPostData('submit')) { if ($request->hasPostData('submit')) {
$user_angeltype_id = UserAngelType_create($user->id, $angeltype); $userAngelType = new UserAngelType();
$userAngelType->user()->associate($user);
$userAngelType->angelType()->associate($angeltype);
$userAngelType->save();
$success_message = sprintf(__('You joined %s.'), $angeltype->name);
engelsystem_log(sprintf( engelsystem_log(sprintf(
'User %s joined %s.', 'User %s joined %s.',
User_Nick_render($user, true), User_Nick_render($user, true),
AngelType_name_render($angeltype, true) AngelType_name_render($angeltype, true)
)); ));
success($success_message); success(sprintf(__('You joined %s.'), $angeltype->name));
if (auth()->can('admin_user_angeltypes') && $request->hasPostData('auto_confirm_user')) { if (auth()->can('admin_user_angeltypes') && $request->hasPostData('auto_confirm_user')) {
UserAngelType_confirm($user_angeltype_id, $user->id); $userAngelType->confirmUser()->associate($user);
$userAngelType->save();
engelsystem_log(sprintf( engelsystem_log(sprintf(
'User %s confirmed as %s.', 'User %s confirmed as %s.',
User_Nick_render($user, true), User_Nick_render($user, true),

View File

@ -17,9 +17,9 @@ function user_driver_license_required_hint()
return null; return null;
} }
$angeltypes = User_angeltypes($user->id); $angeltypes = $user->userAngelTypes;
foreach ($angeltypes as $angeltype) { foreach ($angeltypes as $angeltype) {
if ($angeltype['requires_driver_license']) { if ($angeltype->requires_driver_license) {
return sprintf( return sprintf(
__('You joined an angeltype which requires a driving license. Please edit your driving license information here: %s.'), __('You joined an angeltype which requires a driving license. Please edit your driving license information here: %s.'),
'<a href="' . user_driver_license_edit_link() . '" class="text-info">' . __('driving license information') . '</a>' '<a href="' . user_driver_license_edit_link() . '" class="text-info">' . __('driving license information') . '</a>'

View File

@ -250,7 +250,7 @@ function user_controller()
$user_source, $user_source,
auth()->can('admin_user'), auth()->can('admin_user'),
User_is_freeloader($user_source), User_is_freeloader($user_source),
User_angeltypes($user_source->id), $user_source->userAngelTypes,
$user_source->groups, $user_source->groups,
$shifts, $shifts,
$user->id == $user_source->id, $user->id == $user_source->id,

View File

@ -3,7 +3,6 @@
namespace Engelsystem\Events\Listener; namespace Engelsystem\Events\Listener;
use Engelsystem\Config\Config; use Engelsystem\Config\Config;
use Engelsystem\Database\Database;
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@ -12,10 +11,10 @@ use Psr\Log\LoggerInterface;
class OAuth2 class OAuth2
{ {
/** @var array */ /** @var array */
protected $config; protected array $config;
/** @var LoggerInterface */ /** @var LoggerInterface */
protected $log; protected LoggerInterface $log;
/** /**
* @param Config $config * @param Config $config
@ -29,16 +28,14 @@ class OAuth2
/** /**
* @param string $event * @param string $event
* @param string $provider * @param string $provider OAuth provider name
* @param Collection $data OAuth userdata * @param Collection $data OAuth userdata
*/ */
public function login(string $event, string $provider, Collection $data) public function login(string $event, string $provider, Collection $data): void
{ {
/** @var Database $db */
$db = app(Database::class);
$ssoTeams = $this->getSsoTeams($provider); $ssoTeams = $this->getSsoTeams($provider);
$user = auth()->user(); $user = auth()->user();
$currentUserAngeltypes = collect($db->select('SELECT * FROM UserAngelTypes WHERE user_id = ?', [$user->id])); $currentUserAngeltypes = $user->userAngelTypes;
$userGroups = $data->get(($this->config[$provider] ?? [])['groups'] ?? 'groups', []); $userGroups = $data->get(($this->config[$provider] ?? [])['groups'] ?? 'groups', []);
foreach ($userGroups as $groupName) { foreach ($userGroups as $groupName) {
@ -47,7 +44,9 @@ class OAuth2
} }
$team = $ssoTeams[$groupName]; $team = $ssoTeams[$groupName];
$userAngeltype = $currentUserAngeltypes->where('angeltype_id', $team['id'])->first(); $angelType = AngelType::find($team['id']);
/** @var AngelType $userAngeltype */
$userAngeltype = $currentUserAngeltypes->where('pivot.angel_type_id', $team['id'])->first();
$supporter = $team['supporter']; $supporter = $team['supporter'];
$confirmed = $supporter ? $user->id : null; $confirmed = $supporter ? $user->id : null;
@ -56,15 +55,13 @@ class OAuth2
'SSO {provider}: Added to angeltype {angeltype}, confirmed: {confirmed}, supporter: {supporter}', 'SSO {provider}: Added to angeltype {angeltype}, confirmed: {confirmed}, supporter: {supporter}',
[ [
'provider' => $provider, 'provider' => $provider,
'angeltype' => AngelType::find($team['id'])->name, 'angeltype' => $angelType->name,
'confirmed' => $confirmed ? 'yes' : 'no', 'confirmed' => $confirmed ? 'yes' : 'no',
'supporter' => $supporter ? 'yes' : 'no', 'supporter' => $supporter ? 'yes' : 'no',
] ]
); );
$db->insert(
'INSERT INTO UserAngelTypes (user_id, angeltype_id, confirm_user_id, supporter) VALUES (?, ?, ?, ?)', $user->userAngelTypes()->attach($angelType, ['supporter' => $supporter, 'confirm_user_id' => $confirmed]);
[$user->id, $team['id'], $confirmed, $supporter]
);
continue; continue;
} }
@ -73,40 +70,33 @@ class OAuth2
continue; continue;
} }
if ($userAngeltype->supporter != $supporter) { if ($userAngeltype->pivot->supporter != $supporter) {
$db->update( $userAngeltype->pivot->supporter = $supporter;
'UPDATE UserAngelTypes SET supporter=? WHERE id = ?', $userAngeltype->pivot->save();
[$supporter, $userAngeltype->id]
);
$this->log->info( $this->log->info(
'SSO {provider}: Set supporter state for angeltype {angeltype}', 'SSO {provider}: Set supporter state for angeltype {angeltype}',
[ [
'provider' => $provider, 'provider' => $provider,
'angeltype' => AngelType::find($userAngeltype->angeltype_id)->name, 'angeltype' => $userAngeltype->pivot->angelType->name,
] ]
); );
} }
if (!$userAngeltype->confirm_user_id) { if (!$userAngeltype->pivot->confirm_user_id) {
$db->update( $userAngeltype->pivot->confirmUser()->associate($user);
'UPDATE UserAngelTypes SET confirm_user_id=? WHERE id = ?', $userAngeltype->pivot->save();
[$user->id, $userAngeltype->id]
);
$this->log->info( $this->log->info(
'SSO {provider}: Set confirmed state for angeltype {angeltype}', 'SSO {provider}: Set confirmed state for angeltype {angeltype}',
[ [
'provider' => $provider, 'provider' => $provider,
'angeltype' => AngelType::find($userAngeltype->angeltype_id)->name, 'angeltype' => $userAngeltype->pivot->angelType->name,
] ]
); );
} }
} }
} }
/**
* @param string $provider
* @return array
*/
public function getSsoTeams(string $provider): array public function getSsoTeams(string $provider): array
{ {
$config = $this->config[$provider] ?? []; $config = $this->config[$provider] ?? [];

View File

@ -18,7 +18,6 @@ $includeFiles = [
__DIR__ . '/../includes/model/ShiftsFilter.php', __DIR__ . '/../includes/model/ShiftsFilter.php',
__DIR__ . '/../includes/model/ShiftSignupState.php', __DIR__ . '/../includes/model/ShiftSignupState.php',
__DIR__ . '/../includes/model/Stats.php', __DIR__ . '/../includes/model/Stats.php',
__DIR__ . '/../includes/model/UserAngelTypes_model.php',
__DIR__ . '/../includes/model/User_model.php', __DIR__ . '/../includes/model/User_model.php',
__DIR__ . '/../includes/model/UserWorkLog_model.php', __DIR__ . '/../includes/model/UserWorkLog_model.php',
__DIR__ . '/../includes/model/ValidationResult.php', __DIR__ . '/../includes/model/ValidationResult.php',

View File

@ -5,6 +5,7 @@ use Engelsystem\Models\AngelType;
use Engelsystem\Models\Room; use Engelsystem\Models\Room;
use Engelsystem\Models\Shifts\ShiftType; use Engelsystem\Models\Shifts\ShiftType;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
use Engelsystem\ShiftsFilter; use Engelsystem\ShiftsFilter;
use Engelsystem\ShiftSignupState; use Engelsystem\ShiftSignupState;
@ -376,7 +377,7 @@ function Shift_signup_allowed_angel(
} }
if (empty($user_angeltype)) { if (empty($user_angeltype)) {
$user_angeltype = UserAngelType_by_User_and_AngelType($user->id, $angeltype); $user_angeltype = UserAngelType::whereUserId($user->id)->where('angel_type_id', $angeltype->id)->first();
} }
if ( if (
@ -421,7 +422,7 @@ function Shift_signup_allowed_angeltype_supporter(AngelType $needed_angeltype, $
* Check if an admin can sign up a user to a shift. * Check if an admin can sign up a user to a shift.
* *
* @param AngelType $needed_angeltype * @param AngelType $needed_angeltype
* @param array[] $shift_entries * @param array[] $shift_entries
* @return ShiftSignupState * @return ShiftSignupState
*/ */
function Shift_signup_allowed_admin(AngelType $needed_angeltype, $shift_entries) function Shift_signup_allowed_admin(AngelType $needed_angeltype, $shift_entries)
@ -456,7 +457,7 @@ function Shift_signout_allowed($shift, AngelType $angeltype, $signout_user_id)
// angeltype supporter can sign out any user at any time from their supported angeltype // angeltype supporter can sign out any user at any time from their supported angeltype
if ( if (
auth()->can('shiftentry_edit_angeltype_supporter') auth()->can('shiftentry_edit_angeltype_supporter')
&& User_is_AngelType_supporter($user, $angeltype) && ($user->isAngelTypeSupporter($angeltype) || auth()->can('admin_user_angeltypes'))
) { ) {
return true; return true;
} }
@ -495,7 +496,7 @@ function Shift_signup_allowed(
if ( if (
auth()->can('shiftentry_edit_angeltype_supporter') auth()->can('shiftentry_edit_angeltype_supporter')
&& User_is_AngelType_supporter(auth()->user(), $angeltype) && (auth()->user()->isAngelTypeSupporter($angeltype) || auth()->can('admin_user_angeltypes'))
) { ) {
return Shift_signup_allowed_angeltype_supporter($needed_angeltype, $shift_entries); return Shift_signup_allowed_angeltype_supporter($needed_angeltype, $shift_entries);
} }

View File

@ -1,284 +0,0 @@
<?php
use Engelsystem\Database\Db;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\User\User;
/**
* User angeltypes model
*/
/**
* Checks if a user joined an angeltype.
*
* @param int $userId The user to be checked
* @param AngelType $angeltype The angeltype to be checked
* @return boolean
*/
function UserAngelType_exists($userId, AngelType $angeltype)
{
return count(Db::select('
SELECT `id`
FROM `UserAngelTypes`
WHERE `UserAngelTypes`.`user_id`=?
AND `angeltype_id`=?
', [$userId, $angeltype->id])) > 0;
}
/**
* List users angeltypes.
*
* @param int $userId
* @return array[]
*/
function User_angeltypes($userId)
{
return Db::select('
SELECT `angel_types`.*, `UserAngelTypes`.`confirm_user_id`, `UserAngelTypes`.`supporter`
FROM `UserAngelTypes`
JOIN `angel_types` ON `UserAngelTypes`.`angeltype_id` = `angel_types`.`id`
WHERE `UserAngelTypes`.`user_id`=?
', [$userId]);
}
/**
* Gets unconfirmed user angeltypes for angeltypes of which the given user is a supporter.
*
* @param int $userId
* @return array[]
*/
function User_unconfirmed_AngelTypes($userId)
{
return Db::select('
SELECT
`UserAngelTypes`.*,
`angel_types`.`name`,
count(`UnconfirmedMembers`.`user_id`) AS `count`
FROM `UserAngelTypes`
JOIN `angel_types` ON `UserAngelTypes`.`angeltype_id`=`angel_types`.`id`
JOIN `UserAngelTypes` AS `UnconfirmedMembers` ON `UserAngelTypes`.`angeltype_id`=`UnconfirmedMembers`.`angeltype_id`
WHERE `UserAngelTypes`.`user_id`=?
AND `UserAngelTypes`.`supporter`=TRUE
AND `angel_types`.`restricted`=TRUE
AND `UnconfirmedMembers`.`confirm_user_id` IS NULL
GROUP BY `UserAngelTypes`.`angeltype_id`, `UserAngelTypes`.`id`, angel_types.name, UserAngelTypes.user_id, UserAngelTypes.confirm_user_id, UserAngelTypes.supporter
ORDER BY `angel_types`.`name`
', [$userId]);
}
/**
* Returns true if user is angeltype supporter or has privilege admin_user_angeltypes.
*
* @param User $user
* @param AngelType $angeltype
* @return bool
*/
function User_is_AngelType_supporter($user, AngelType $angeltype)
{
if (!$user) {
return false;
}
$privileges = $user->privileges->pluck('name')->toArray();
return
count(
Db::select(
'
SELECT `id`
FROM `UserAngelTypes`
WHERE `user_id`=?
AND `angeltype_id`=?
AND `supporter`=TRUE
LIMIT 1
',
[
$user->id,
$angeltype->id
]
)
) > 0
|| in_array('admin_user_angeltypes', $privileges);
}
/**
* Add or remove supporter rights.
*
* @param int $user_angeltype_id
* @param bool $supporter
*/
function UserAngelType_update($user_angeltype_id, $supporter)
{
Db::update('
UPDATE `UserAngelTypes`
SET `supporter`=?
WHERE `id`=?
LIMIT 1
', [(int)$supporter, $user_angeltype_id]);
}
/**
* Delete all unconfirmed UserAngelTypes for given Angeltype.
*
* @param int $angeltype_id
*/
function UserAngelTypes_delete_all_unconfirmed(int $angeltype_id)
{
Db::delete('
DELETE FROM `UserAngelTypes`
WHERE `angeltype_id`=?
AND `confirm_user_id` IS NULL
', [$angeltype_id]);
}
/**
* Confirm all unconfirmed UserAngelTypes for given Angeltype.
*
* @param int $angeltype_id
* @param int $confirm_user_id
*/
function UserAngelTypes_confirm_all($angeltype_id, $confirm_user_id)
{
Db::update('
UPDATE `UserAngelTypes`
SET `confirm_user_id`=?
WHERE `angeltype_id`=?
AND `confirm_user_id` IS NULL
', [$confirm_user_id, $angeltype_id]);
}
/**
* Get all unconfirmed Users for given Angeltype
*
* @param int $angeltype_id
*/
function UserAngelTypes_all_unconfirmed($angeltype_id)
{
return Db::select('
SELECT *
FROM `UserAngelTypes`
WHERE `angeltype_id`=?
AND `confirm_user_id` IS NULL
', [$angeltype_id]);
}
/**
* Confirm an UserAngelType with confirming user.
*
* @param int $user_angeltype_id
* @param int $confirm_user_id
*/
function UserAngelType_confirm($user_angeltype_id, $confirm_user_id)
{
Db::update('
UPDATE `UserAngelTypes`
SET `confirm_user_id`=?
WHERE `id`=?
LIMIT 1', [$confirm_user_id, $user_angeltype_id]);
}
/**
* Delete an UserAngelType.
*
* @param array $user_angeltype
*/
function UserAngelType_delete($user_angeltype)
{
Db::delete('
DELETE FROM `UserAngelTypes`
WHERE `id`=?
LIMIT 1', [$user_angeltype['id']]);
}
/**
* Create an UserAngelType.
*
* @param int $userId
* @param AngelType $angeltype
* @return int
*/
function UserAngelType_create($userId, AngelType $angeltype)
{
Db::insert(
'
INSERT INTO `UserAngelTypes` (`user_id`, `angeltype_id`, `supporter`)
VALUES (?, ?, FALSE)
',
[
$userId,
$angeltype->id
]
);
return Db::getPdo()->lastInsertId();
}
/**
* Get an UserAngelType by its id.
*
* @param int $user_angeltype_id
* @return array|null
*/
function UserAngelType($user_angeltype_id)
{
$userAngelType = Db::selectOne('
SELECT *
FROM `UserAngelTypes`
WHERE `id`=?
LIMIT 1', [$user_angeltype_id]);
return empty($userAngelType) ? null : $userAngelType;
}
/**
* Get an UserAngelType by user and angeltype.
*
* @param int $userId
* @param AngelType $angeltype
* @return array|null
*/
function UserAngelType_by_User_and_AngelType($userId, AngelType $angeltype)
{
return Db::selectOne(
'
SELECT *
FROM `UserAngelTypes`
WHERE `user_id`=?
AND `angeltype_id`=?
LIMIT 1
',
[
$userId,
$angeltype->id
]
);
}
/**
* Get an UserAngelTypes by user
*
* @param int $userId
* @param bool $onlyConfirmed
* @return array[]|null
*/
function UserAngelTypes_by_User($userId, $onlyConfirmed = false)
{
return Db::select(
'
SELECT *
FROM `UserAngelTypes`
' . ($onlyConfirmed ? 'LEFT JOIN angel_types AS a ON a.id=UserAngelTypes.angeltype_id' : '') . '
WHERE `user_id`=?
'
. (
$onlyConfirmed ? 'AND (
a.`restricted`=0
OR (
NOT `UserAngelTypes`.`confirm_user_id` IS NULL
OR `UserAngelTypes`.`id` IS NULL
)
)' : ''
),
[$userId]
);
}

View File

@ -60,44 +60,21 @@ function User_is_freeloader($user)
/** /**
* Returns all users that are not member of given angeltype. * Returns all users that are not member of given angeltype.
* *
* @param array $angeltype Angeltype * @param AngelType $angeltype Angeltype
* *
* @return User[]|Collection * @return User[]|Collection
*/ */
function Users_by_angeltype_inverted($angeltype) function Users_by_angeltype_inverted(AngelType $angeltype)
{ {
return User::query() return User::query()
->select('users.*') ->select('users.*')
->leftJoin('UserAngelTypes', function ($query) use ($angeltype) { ->leftJoin('user_angel_type', function ($query) use ($angeltype) {
/** @var JoinClause $query */ /** @var JoinClause $query */
$query $query
->on('users.id', '=', 'UserAngelTypes.user_id') ->on('users.id', '=', 'user_angel_type.user_id')
->where('UserAngelTypes.angeltype_id', '=', $angeltype['id']); ->where('user_angel_type.angel_type_id', '=', $angeltype->id);
}) })
->whereNull('UserAngelTypes.id') ->whereNull('user_angel_type.id')
->orderBy('users.name')
->get();
}
/**
* Returns all members of given angeltype.
*
* @param AngelType $angeltype
* @return User[]|Collection
*/
function Users_by_angeltype(AngelType $angeltype)
{
return User::query()
->select(
'users.*',
'UserAngelTypes.id AS user_angeltype_id',
'UserAngelTypes.confirm_user_id',
'UserAngelTypes.supporter',
'users_licenses.*'
)
->join('UserAngelTypes', 'users.id', '=', 'UserAngelTypes.user_id')
->leftJoin('users_licenses', 'users.id', '=', 'users_licenses.user_id')
->where('UserAngelTypes.angeltype_id', '=', $angeltype->id)
->orderBy('users.name') ->orderBy('users.name')
->get(); ->get();
} }

View File

@ -34,6 +34,7 @@ function admin_free()
$angelType = $request->input('angeltype', ''); $angelType = $request->input('angeltype', '');
/** @var User[] $users */
$users = []; $users = [];
if ($request->has('submit')) { if ($request->has('submit')) {
$query = User::with('personalData') $query = User::with('personalData')
@ -52,16 +53,16 @@ function admin_free()
->groupBy('users.id'); ->groupBy('users.id');
if (!empty($angelType)) { if (!empty($angelType)) {
$query->join('UserAngelTypes', function ($join) use ($angelType) { $query->join('user_angel_type', function ($join) use ($angelType) {
/** @var JoinClause $join */ /** @var JoinClause $join */
$join->on('UserAngelTypes.user_id', '=', 'users.id') $join->on('user_angel_type.user_id', '=', 'users.id')
->where('UserAngelTypes.angeltype_id', '=', $angelType); ->where('user_angel_type.angel_type_id', '=', $angelType);
}); });
$query->join('angel_types', function ($join) { $query->join('angel_types', function ($join) {
/** @var JoinClause $join */ /** @var JoinClause $join */
$join->on('UserAngelTypes.angeltype_id', '=', 'angel_types.id') $join->on('user_angel_type.angel_type_id', '=', 'angel_types.id')
->whereNotNull('UserAngelTypes.confirm_user_id') ->whereNotNull('user_angel_type.confirm_user_id')
->orWhere('angel_types.restricted', '=', '0'); ->orWhere('angel_types.restricted', '=', '0');
}); });
} }

View File

@ -2,7 +2,6 @@
use Carbon\Carbon; use Carbon\Carbon;
use Engelsystem\Database\Database; use Engelsystem\Database\Database;
use Engelsystem\Database\Db;
use Engelsystem\Events\Listener\OAuth2; use Engelsystem\Events\Listener\OAuth2;
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Engelsystem\Models\Group; use Engelsystem\Models\Group;
@ -81,7 +80,7 @@ function guest_register()
continue; continue;
} }
$angel_types[$angel_type->id] = $angel_type->name $angel_types[$angel_type->id] = $angel_type->name
. ($angel_type->restricted ? ' (' . __('Requires introduction') . ')' : ''); . ($angel_type->restricted ? ' (' . __('Requires introduction') . ')' : '');
if (!$angel_type->restricted) { if (!$angel_type->restricted) {
$selected_angel_types[] = $angel_type->id; $selected_angel_types[] = $angel_type->id;
} }
@ -310,11 +309,9 @@ function guest_register()
// Assign angel-types // Assign angel-types
$user_angel_types_info = []; $user_angel_types_info = [];
foreach ($selected_angel_types as $selected_angel_type_id) { foreach ($selected_angel_types as $selected_angel_type_id) {
Db::insert( $angelType = AngelType::findOrFail($selected_angel_type_id);
'INSERT INTO `UserAngelTypes` (`user_id`, `angeltype_id`, `supporter`) VALUES (?, ?, FALSE)', $user->userAngelTypes()->attach($angelType);
[$user->id, $selected_angel_type_id] $user_angel_types_info[] = $angelType->name;
);
$user_angel_types_info[] = $angel_types[$selected_angel_type_id];
} }
// Commit complete user data // Commit complete user data

View File

@ -4,7 +4,10 @@ use Engelsystem\Database\Db;
use Engelsystem\Helpers\Carbon; use Engelsystem\Helpers\Carbon;
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Engelsystem\Models\Room; use Engelsystem\Models\Room;
use Engelsystem\Models\UserAngelType;
use Engelsystem\ShiftsFilter; use Engelsystem\ShiftsFilter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
/** /**
@ -94,9 +97,9 @@ function update_ShiftsFilter_timerange(ShiftsFilter $shiftsFilter, $days)
/** /**
* Update given ShiftsFilter with filter params from user input * Update given ShiftsFilter with filter params from user input
* *
* @param ShiftsFilter $shiftsFilter The shifts filter to update from request data * @param ShiftsFilter $shiftsFilter The shifts filter to update from request data
* @param boolean $user_shifts_admin Has the user user_shift_admin privilege? * @param boolean $user_shifts_admin Has the user user_shift_admin privilege?
* @param string[] $days An array of available filter days * @param string[] $days An array of available filter days
*/ */
function update_ShiftsFilter(ShiftsFilter $shiftsFilter, $user_shifts_admin, $days) function update_ShiftsFilter(ShiftsFilter $shiftsFilter, $user_shifts_admin, $days)
{ {
@ -157,6 +160,7 @@ function load_types()
error(__('The administration has not configured any angeltypes yet - or you are not subscribed to any angeltype.')); error(__('The administration has not configured any angeltypes yet - or you are not subscribed to any angeltype.'));
throw_redirect(page_link_to('/')); throw_redirect(page_link_to('/'));
} }
$types = Db::select( $types = Db::select(
' '
SELECT SELECT
@ -165,15 +169,15 @@ function load_types()
( (
`angel_types`.`restricted`=0 `angel_types`.`restricted`=0
OR ( OR (
NOT `UserAngelTypes`.`confirm_user_id` IS NULL NOT `user_angel_type`.`confirm_user_id` IS NULL
OR `UserAngelTypes`.`id` IS NULL OR `user_angel_type`.`id` IS NULL
) )
) AS `enabled` ) AS `enabled`
FROM `angel_types` FROM `angel_types`
LEFT JOIN `UserAngelTypes` LEFT JOIN `user_angel_type`
ON ( ON (
`UserAngelTypes`.`angeltype_id`=`angel_types`.`id` `user_angel_type`.`angel_type_id`=`angel_types`.`id`
AND `UserAngelTypes`.`user_id`=? AND `user_angel_type`.`user_id`=?
) )
ORDER BY `angel_types`.`name` ORDER BY `angel_types`.`name`
', ',
@ -181,9 +185,11 @@ function load_types()
$user->id, $user->id,
] ]
); );
if (empty($types)) { if (empty($types)) {
return unrestricted_angeltypes(); return unrestricted_angeltypes();
} }
return $types; return $types;
} }
@ -208,12 +214,16 @@ function view_user_shifts()
$types = load_types(); $types = load_types();
$ownTypes = []; $ownTypes = [];
foreach (UserAngelTypes_by_User($user->id, true) as $type) { /** @var EloquentCollection|UserAngelType[] $userAngelTypes */
if (!$type['confirm_user_id'] && $type['restricted']) { $userAngelTypes = UserAngelType::whereUserId($user->id)
continue; ->leftJoin('angel_types', 'user_angel_type.angel_type_id', 'angel_types.id')
} ->where(function (Builder $query) {
$query->whereNotNull('user_angel_type.confirm_user_id')
$ownTypes[] = (int)$type['angeltype_id']; ->orWhere('angel_types.restricted', false);
})
->get();
foreach ($userAngelTypes as $type) {
$ownTypes[] = $type->angel_type_id;
} }
if (!$session->has('shifts-filter')) { if (!$session->has('shifts-filter')) {

View File

@ -3,6 +3,7 @@
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Engelsystem\Models\User\License; use Engelsystem\Models\User\License;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
use Engelsystem\ShiftCalendarRenderer; use Engelsystem\ShiftCalendarRenderer;
use Engelsystem\ShiftsFilterRenderer; use Engelsystem\ShiftsFilterRenderer;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@ -38,7 +39,7 @@ function AngelType_name_render(AngelType $angeltype, $plain = false)
*/ */
function AngelType_render_membership(AngelType $user_angeltype) function AngelType_render_membership(AngelType $user_angeltype)
{ {
if (!empty($user_angeltype->user_angeltype_id)) { if (!empty($user_angeltype->user_angel_type_id)) {
if ($user_angeltype->restricted) { if ($user_angeltype->restricted) {
if (empty($user_angeltype->confirm_user_id)) { if (empty($user_angeltype->confirm_user_id)) {
return icon('mortarboard-fill') . __('Unconfirmed'); return icon('mortarboard-fill') . __('Unconfirmed');
@ -135,17 +136,17 @@ function AngelType_edit_view(AngelType $angeltype, bool $supporter_mode)
/** /**
* Renders the buttons for the angeltype view. * Renders the buttons for the angeltype view.
* *
* @param AngelType $angeltype * @param AngelType $angeltype
* @param array|null $user_angeltype * @param UserAngelType|null $user_angeltype
* @param bool $admin_angeltypes * @param bool $admin_angeltypes
* @param bool $supporter * @param bool $supporter
* @param License $user_driver_license * @param License $user_driver_license
* @param User|null $user * @param User|null $user
* @return string * @return string
*/ */
function AngelType_view_buttons( function AngelType_view_buttons(
AngelType $angeltype, AngelType $angeltype,
$user_angeltype, ?UserAngelType $user_angeltype,
$admin_angeltypes, $admin_angeltypes,
$supporter, $supporter,
$user_driver_license, $user_driver_license,
@ -173,14 +174,14 @@ function AngelType_view_buttons(
error(__('This angeltype requires a driver license. Please enter your driver license information!')); error(__('This angeltype requires a driver license. Please enter your driver license information!'));
} }
if ($angeltype->restricted && empty($user_angeltype['confirm_user_id'])) { if ($angeltype->restricted && !$user_angeltype->confirm_user_id) {
error(sprintf( error(sprintf(
__('You are unconfirmed for this angeltype. Please go to the introduction for %s to get confirmed.'), __('You are unconfirmed for this angeltype. Please go to the introduction for %s to get confirmed.'),
$angeltype->name $angeltype->name
)); ));
} }
$buttons[] = button( $buttons[] = button(
page_link_to('user_angeltypes', ['action' => 'delete', 'user_angeltype_id' => $user_angeltype['id']]), page_link_to('user_angeltypes', ['action' => 'delete', 'user_angeltype_id' => $user_angeltype->id]),
icon('box-arrow-right') . __('leave') icon('box-arrow-right') . __('leave')
); );
} }
@ -230,12 +231,12 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
$member['has_license_forklift'] = icon_bool($member->license->drive_forklift); $member['has_license_forklift'] = icon_bool($member->license->drive_forklift);
} }
if ($angeltype->restricted && empty($member['confirm_user_id'])) { if ($angeltype->restricted && empty($member->pivot->confirm_user_id)) {
$member['actions'] = table_buttons([ $member['actions'] = table_buttons([
button( button(
page_link_to( page_link_to(
'user_angeltypes', 'user_angeltypes',
['action' => 'confirm', 'user_angeltype_id' => $member['user_angeltype_id']] ['action' => 'confirm', 'user_angeltype_id' => $member->pivot->id]
), ),
__('confirm'), __('confirm'),
'btn-sm' 'btn-sm'
@ -243,20 +244,20 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
button( button(
page_link_to( page_link_to(
'user_angeltypes', 'user_angeltypes',
['action' => 'delete', 'user_angeltype_id' => $member['user_angeltype_id']] ['action' => 'delete', 'user_angeltype_id' => $member->pivot->id]
), ),
__('deny'), __('deny'),
'btn-sm' 'btn-sm'
) )
]); ]);
$members_unconfirmed[] = $member; $members_unconfirmed[] = $member;
} elseif ($member['supporter']) { } elseif ($member->pivot->supporter) {
if ($admin_angeltypes) { if ($admin_angeltypes) {
$member['actions'] = table_buttons([ $member['actions'] = table_buttons([
button( button(
page_link_to('user_angeltypes', [ page_link_to('user_angeltypes', [
'action' => 'update', 'action' => 'update',
'user_angeltype_id' => $member['user_angeltype_id'], 'user_angeltype_id' => $member->pivot->id,
'supporter' => 0 'supporter' => 0
]), ]),
icon('person-fill-down') . __('Remove supporter rights'), icon('person-fill-down') . __('Remove supporter rights'),
@ -274,7 +275,7 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
button( button(
page_link_to('user_angeltypes', [ page_link_to('user_angeltypes', [
'action' => 'update', 'action' => 'update',
'user_angeltype_id' => $member['user_angeltype_id'], 'user_angeltype_id' => $member->pivot->id,
'supporter' => 1 'supporter' => 1
]), ]),
icon('person-fill-up') . __('Add supporter rights'), icon('person-fill-up') . __('Add supporter rights'),
@ -284,7 +285,7 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
button( button(
page_link_to('user_angeltypes', [ page_link_to('user_angeltypes', [
'action' => 'delete', 'action' => 'delete',
'user_angeltype_id' => $member['user_angeltype_id'] 'user_angeltype_id' => $member->pivot->id
]), ]),
icon('trash') . __('remove'), icon('trash') . __('remove'),
'btn-sm' 'btn-sm'
@ -338,7 +339,7 @@ function AngelType_view_table_headers(AngelType $angeltype, $supporter, $admin_a
* *
* @param AngelType $angeltype * @param AngelType $angeltype
* @param User[] $members * @param User[] $members
* @param array $user_angeltype * @param UserAngelType|null $user_angeltype
* @param bool $admin_user_angeltypes * @param bool $admin_user_angeltypes
* @param bool $admin_angeltypes * @param bool $admin_angeltypes
* @param bool $supporter * @param bool $supporter
@ -352,7 +353,7 @@ function AngelType_view_table_headers(AngelType $angeltype, $supporter, $admin_a
function AngelType_view( function AngelType_view(
AngelType $angeltype, AngelType $angeltype,
$members, $members,
$user_angeltype, ?UserAngelType $user_angeltype,
$admin_user_angeltypes, $admin_user_angeltypes,
$admin_angeltypes, $admin_angeltypes,
$supporter, $supporter,
@ -553,13 +554,13 @@ function AngelTypes_about_view_angeltype(AngelType $angeltype)
$html .= AngelTypes_render_contact_info($angeltype); $html .= AngelTypes_render_contact_info($angeltype);
} }
if (isset($angeltype->user_angeltype_id)) { if (isset($angeltype->user_angel_type_id)) {
$buttons = []; $buttons = [];
if (!empty($angeltype->user_angeltype_id)) { if (!empty($angeltype->user_angel_type_id)) {
$buttons[] = button( $buttons[] = button(
page_link_to( page_link_to(
'user_angeltypes', 'user_angeltypes',
['action' => 'delete', 'user_angeltype_id' => $angeltype->user_angeltype_id] ['action' => 'delete', 'user_angeltype_id' => $angeltype->user_angel_type_id]
), ),
icon('box-arrow-right') . __('leave') icon('box-arrow-right') . __('leave')
); );

View File

@ -4,6 +4,7 @@ use Engelsystem\Models\AngelType;
use Engelsystem\Models\Room; use Engelsystem\Models\Room;
use Engelsystem\Models\Shifts\ShiftType; use Engelsystem\Models\Shifts\ShiftType;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
use Engelsystem\ShiftSignupState; use Engelsystem\ShiftSignupState;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@ -75,20 +76,21 @@ function Shift_editor_info_render($shift)
/** /**
* @param array $shift * @param array $shift
* @param AngelType $angeltype * @param AngelType $angeltype
* @param array $user_angeltype
* @return string * @return string
*/ */
function Shift_signup_button_render($shift, AngelType $angeltype, $user_angeltype = null) function Shift_signup_button_render($shift, AngelType $angeltype)
{ {
if (empty($user_angeltype)) { /** @var UserAngelType|null $user_angeltype */
$user_angeltype = UserAngelType_by_User_and_AngelType(auth()->user()->id, $angeltype); $user_angeltype = UserAngelType::whereUserId(auth()->user()->id)
} ->where('angel_type_id', $angeltype->id)
->first();
if ( if (
isset($angeltype->shift_signup_state) isset($angeltype->shift_signup_state)
&& ( && (
$angeltype->shift_signup_state->isSignupAllowed() $angeltype->shift_signup_state->isSignupAllowed()
|| User_is_AngelType_supporter(auth()->user(), $angeltype) || auth()->user()->isAngelTypeSupporter($angeltype)
|| auth()->can('admin_user_angeltypes')
) )
) { ) {
return button(shift_entry_create_link($shift, $angeltype), __('Sign up')); return button(shift_entry_create_link($shift, $angeltype), __('Sign up'));
@ -101,6 +103,7 @@ function Shift_signup_button_render($shift, AngelType $angeltype, $user_angeltyp
) )
); );
} }
return ''; return '';
} }
@ -208,7 +211,8 @@ function Shift_view($shift, ShiftType $shifttype, Room $room, $angeltypes_source
function Shift_view_render_needed_angeltype($needed_angeltype, $angeltypes, $shift, $user_shift_admin) function Shift_view_render_needed_angeltype($needed_angeltype, $angeltypes, $shift, $user_shift_admin)
{ {
$angeltype = $angeltypes[$needed_angeltype['TID']]; $angeltype = $angeltypes[$needed_angeltype['TID']];
$angeltype_supporter = User_is_AngelType_supporter(auth()->user(), $angeltype); $angeltype_supporter = auth()->user()->isAngelTypeSupporter($angeltype)
|| auth()->can('admin_user_angeltypes');
$needed_angels = ''; $needed_angels = '';

View File

@ -2,15 +2,16 @@
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
/** /**
* @param array $user_angeltype * @param UserAngelType $user_angeltype
* @param User $user * @param User $user
* @param AngelType $angeltype * @param AngelType $angeltype
* @param bool $supporter * @param bool $supporter
* @return string * @return string
*/ */
function UserAngelType_update_view($user_angeltype, User $user, AngelType $angeltype, bool $supporter) function UserAngelType_update_view(UserAngelType $user_angeltype, User $user, AngelType $angeltype, bool $supporter)
{ {
return page_with_title($supporter ? __('Add supporter rights') : __('Remove supporter rights'), [ return page_with_title($supporter ? __('Add supporter rights') : __('Remove supporter rights'), [
msg(), msg(),
@ -31,7 +32,7 @@ function UserAngelType_update_view($user_angeltype, User $user, AngelType $angel
]), ]),
], page_link_to('user_angeltypes', [ ], page_link_to('user_angeltypes', [
'action' => 'update', 'action' => 'update',
'user_angeltype_id' => $user_angeltype['id'], 'user_angeltype_id' => $user_angeltype->id,
'supporter' => ($supporter ? '1' : '0'), 'supporter' => ($supporter ? '1' : '0'),
])), ])),
]); ]);
@ -80,12 +81,12 @@ function UserAngelTypes_confirm_all_view(AngelType $angeltype)
} }
/** /**
* @param array $user_angeltype * @param UserAngelType $user_angeltype
* @param User $user * @param User $user
* @param AngelType $angeltype * @param AngelType $angeltype
* @return string * @return string
*/ */
function UserAngelType_confirm_view($user_angeltype, $user, AngelType $angeltype) function UserAngelType_confirm_view(UserAngelType $user_angeltype, User $user, AngelType $angeltype)
{ {
return page_with_title(__('Confirm angeltype for user'), [ return page_with_title(__('Confirm angeltype for user'), [
msg(), msg(),
@ -99,17 +100,17 @@ function UserAngelType_confirm_view($user_angeltype, $user, AngelType $angeltype
button(angeltype_link($angeltype->id), icon('x-lg') . __('cancel')), button(angeltype_link($angeltype->id), icon('x-lg') . __('cancel')),
form_submit('confirm_user', icon('check-lg') . __('yes'), 'btn-primary', false), form_submit('confirm_user', icon('check-lg') . __('yes'), 'btn-primary', false),
]), ]),
], page_link_to('user_angeltypes', ['action' => 'confirm', 'user_angeltype_id' => $user_angeltype['id']])), ], page_link_to('user_angeltypes', ['action' => 'confirm', 'user_angeltype_id' => $user_angeltype->id])),
]); ]);
} }
/** /**
* @param array $user_angeltype * @param UserAngelType $user_angeltype
* @param User $user * @param User $user
* @param AngelType $angeltype * @param AngelType $angeltype
* @return string * @return string
*/ */
function UserAngelType_delete_view($user_angeltype, $user, AngelType $angeltype) function UserAngelType_delete_view(UserAngelType $user_angeltype, User $user, AngelType $angeltype)
{ {
return page_with_title(__('Remove angeltype'), [ return page_with_title(__('Remove angeltype'), [
msg(), msg(),
@ -123,7 +124,7 @@ function UserAngelType_delete_view($user_angeltype, $user, AngelType $angeltype)
button(angeltype_link($angeltype->id), icon('x-lg') . __('cancel')), button(angeltype_link($angeltype->id), icon('x-lg') . __('cancel')),
form_submit('delete', icon('check-lg') . __('yes'), 'btn-primary', false), form_submit('delete', icon('check-lg') . __('yes'), 'btn-primary', false),
]), ]),
], page_link_to('user_angeltypes', ['action' => 'delete', 'user_angeltype_id' => $user_angeltype['id']])), ], page_link_to('user_angeltypes', ['action' => 'delete', 'user_angeltype_id' => $user_angeltype->id])),
], true); ], true);
} }

View File

@ -432,7 +432,7 @@ function User_view_worklog(Worklog $worklog, $admin_user_worklog_privilege)
* @param User $user_source * @param User $user_source
* @param bool $admin_user_privilege * @param bool $admin_user_privilege
* @param bool $freeloader * @param bool $freeloader
* @param array[] $user_angeltypes * @param AngelType[] $user_angeltypes
* @param Group[] $user_groups * @param Group[] $user_groups
* @param array[] $shifts * @param array[] $shifts
* @param bool $its_me * @param bool $its_me
@ -488,7 +488,7 @@ function User_view(
$needs_drivers_license = false; $needs_drivers_license = false;
foreach ($user_angeltypes as $angeltype) { foreach ($user_angeltypes as $angeltype) {
$needs_drivers_license = $needs_drivers_license || $angeltype['requires_driver_license']; $needs_drivers_license = $needs_drivers_license || $angeltype->requires_driver_license;
} }
return page_with_title( return page_with_title(
@ -719,7 +719,7 @@ function User_view_state_admin($freeloader, $user_source)
} }
/** /**
* @param array[] $user_angeltypes * @param AngelType[] $user_angeltypes
* @return string * @return string
*/ */
function User_angeltypes_render($user_angeltypes) function User_angeltypes_render($user_angeltypes)
@ -727,11 +727,11 @@ function User_angeltypes_render($user_angeltypes)
$output = []; $output = [];
foreach ($user_angeltypes as $angeltype) { foreach ($user_angeltypes as $angeltype) {
$class = 'text-success'; $class = 'text-success';
if ($angeltype['restricted'] == 1 && empty($angeltype['confirm_user_id'])) { if ($angeltype->restricted && !$angeltype->pivot->confirm_user_id) {
$class = 'text-warning'; $class = 'text-warning';
} }
$output[] = '<a href="' . angeltype_link($angeltype['id']) . '" class="' . $class . '">' $output[] = '<a href="' . angeltype_link($angeltype->id) . '" class="' . $class . '">'
. ($angeltype['supporter'] ? icon('patch-check') : '') . $angeltype['name'] . ($angeltype->pivot->supporter ? icon('patch-check') : '') . $angeltype->name
. '</a>'; . '</a>';
} }
return div('col-md-2', [ return div('col-md-2', [

View File

@ -5,21 +5,27 @@ declare(strict_types=1);
namespace Engelsystem\Models; namespace Engelsystem\Models;
use Illuminate\Database\Eloquent\Builder; 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\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Query\Builder as QueryBuilder;
/** /**
* @property int $id * @property int $id
* @property string $name * @property string $name
* @property string $description * @property string $description
* @property string $contact_name * @property string $contact_name
* @property string $contact_dect * @property string $contact_dect
* @property string $contact_email * @property string $contact_email
* @property boolean $restricted # If users need an introduction * @property boolean $restricted # If users need an introduction
* @property boolean $requires_driver_license # If users must have a driver license * @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 $no_self_signup # Users can sign up for shifts
* @property boolean $show_on_dashboard # Show on public dashboard * @property boolean $show_on_dashboard # Show on public dashboard
* @property boolean $hide_register # Hide from registration page * @property boolean $hide_register # Hide from registration page
*
* @property-read Collection|User[] $userAngelTypes
* @property-read UserAngelType $pivot
* *
* @method static QueryBuilder|AngelType[] whereId($value) * @method static QueryBuilder|AngelType[] whereId($value)
* @method static QueryBuilder|AngelType[] whereName($value) * @method static QueryBuilder|AngelType[] whereName($value)
@ -62,13 +68,12 @@ class AngelType extends BaseModel
'hide_register' => 'boolean', 'hide_register' => 'boolean',
]; ];
/** public function userAngelTypes(): BelongsToMany
* @codeCoverageIgnore For some reasons parent::boot gets ignored here 0o
*/
protected static function boot(): void
{ {
parent::boot(); return $this
static::addGlobalScope('order', fn(Builder $builder) => $builder->orderBy('name')); ->belongsToMany(User::class, 'user_angel_type')
->using(UserAngelType::class)
->withPivot(UserAngelType::getPivotAttributes());
} }
public function hasContactInfo(): bool public function hasContactInfo(): bool
@ -77,4 +82,13 @@ class AngelType extends BaseModel
|| !empty($this->contact_dect) || !empty($this->contact_dect)
|| !empty($this->contact_email); || !empty($this->contact_email);
} }
/**
* @codeCoverageIgnore For some reasons parent::boot get s ignored here 0o
*/
protected static function boot(): void
{
parent::boot();
static::addGlobalScope('order', fn(Builder $builder) => $builder->orderBy('name'));
}
} }

View File

@ -3,6 +3,7 @@
namespace Engelsystem\Models\User; namespace Engelsystem\Models\User;
use Carbon\Carbon; use Carbon\Carbon;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\BaseModel; use Engelsystem\Models\BaseModel;
use Engelsystem\Models\Group; use Engelsystem\Models\Group;
use Engelsystem\Models\Message; use Engelsystem\Models\Message;
@ -11,6 +12,7 @@ use Engelsystem\Models\NewsComment;
use Engelsystem\Models\OAuth; use Engelsystem\Models\OAuth;
use Engelsystem\Models\Privilege; use Engelsystem\Models\Privilege;
use Engelsystem\Models\Question; use Engelsystem\Models\Question;
use Engelsystem\Models\UserAngelType;
use Engelsystem\Models\Worklog; use Engelsystem\Models\Worklog;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
@ -42,6 +44,8 @@ use Illuminate\Support\Collection as SupportCollection;
* @property-read Collection|NewsComment[] $newsComments * @property-read Collection|NewsComment[] $newsComments
* @property-read Collection|OAuth[] $oauth * @property-read Collection|OAuth[] $oauth
* @property-read SupportCollection|Privilege[] $privileges * @property-read SupportCollection|Privilege[] $privileges
* @property-read Collection|AngelType[] $userAngelTypes
* @property-read UserAngelType $pivot
* @property-read Collection|Worklog[] $worklogs * @property-read Collection|Worklog[] $worklogs
* @property-read Collection|Worklog[] $worklogsCreated * @property-read Collection|Worklog[] $worklogsCreated
* @property-read Collection|Question[] $questionsAsked * @property-read Collection|Question[] $questionsAsked
@ -171,6 +175,29 @@ class User extends BaseModel
->withDefault(); ->withDefault();
} }
/**
* @return BelongsToMany
*/
public function userAngelTypes(): BelongsToMany
{
return $this
->belongsToMany(AngelType::class, 'user_angel_type')
->using(UserAngelType::class)
->withPivot(UserAngelType::getPivotAttributes());
}
/**
* @param AngelType $angelType
* @return bool
*/
public function isAngelTypeSupporter(AngelType $angelType): bool
{
return $this->userAngelTypes()
->wherePivot('angel_type_id', $angelType->id)
->wherePivot('supporter', true)
->exists();
}
/** /**
* @return HasMany * @return HasMany
*/ */

View File

@ -3,14 +3,14 @@
namespace Engelsystem\Models\User; namespace Engelsystem\Models\User;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Eloquent\Builder;
/** /**
* @property int $user_id * @property int $user_id
* *
* @property-read QueryBuilder|User $user * @property-read User $user
* *
* @method static QueryBuilder|static[] whereUserId($value) * @method static Builder|static[] whereUserId($value)
*/ */
trait UsesUserModel trait UsesUserModel
{ {

View File

@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Models;
use Engelsystem\Models\User\User;
use Engelsystem\Models\User\UsesUserModel;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Pivot;
use Illuminate\Database\Query\Builder as QueryBuilder;
/**
* @mixin Builder
*
* @property int $id
* @property int $angel_type_id
* @property int $confirm_user_id
* @property bool $supporter
*
* @property-read AngelType $angelType
* @property-read User $confirmUser
*
* @method static QueryBuilder|AngelType[] whereId($value)
* @method static QueryBuilder|AngelType[] whereAngelTypeId($value)
* @method static QueryBuilder|AngelType[] whereConfirmUserId($value)
* @method static QueryBuilder|AngelType[] whereSupporter($value)
*/
class UserAngelType extends Pivot
{
use HasFactory;
use UsesUserModel;
/** @var bool Increment the IDs */
public $incrementing = true;
/** @var bool Disable timestamps */
public $timestamps = false;
/** @var array */
protected $fillable = [
'user_id',
'angel_type_id',
'confirm_user_id',
'supporter',
];
/** @var string[] */
protected $casts = [
'user_id' => 'integer',
'angel_type_id' => 'integer',
'confirm_user_id' => 'integer',
'supporter' => 'boolean',
];
/**
* Returns a list of attributes that can be requested for this pivot table
*
* @return string[]
*/
public static function getPivotAttributes(): array
{
return ['id', 'confirm_user_id', 'supporter'];
}
public function angelType(): BelongsTo
{
return $this->belongsTo(AngelType::class);
}
public function confirmUser(): BelongsTo
{
return $this->belongsTo(User::class, 'confirm_user_id');
}
}

View File

@ -3,6 +3,8 @@
namespace Engelsystem\Test\Unit\Models; namespace Engelsystem\Test\Unit\Models;
use Engelsystem\Models\AngelType; use Engelsystem\Models\AngelType;
use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
class AngelTypeTest extends ModelTest class AngelTypeTest extends ModelTest
{ {
@ -36,7 +38,31 @@ class AngelTypeTest extends ModelTest
} }
/** /**
* @covers \Engelsystem\Models\AngelType::boot * @covers \Engelsystem\Models\AngelType::userAngelTypes
*/
public function testUserAngelTypes(): void
{
User::factory(2)->create();
$user1 = User::factory()->create();
User::factory(1)->create();
$user2 = User::factory()->create();
$angelType = new AngelType(['name' => 'Test']);
$angelType->save();
$angelType->userAngelTypes()->attach($user1);
$angelType->userAngelTypes()->attach($user2);
/** @var UserAngelType $userAngelType */
$userAngelType = UserAngelType::find(1);
$this->assertEquals($angelType->id, $userAngelType->angelType->id);
$angeltypes = $angelType->userAngelTypes;
$this->assertCount(2, $angeltypes);
}
/**
* @covers \Engelsystem\Models\AngelType::boot
*/ */
public function testBoot(): void public function testBoot(): void
{ {

View File

@ -41,8 +41,8 @@ class ScheduleTest extends ModelTest
$st->save(); $st->save();
$schedule = new Schedule($this->data); $schedule = new Schedule($this->data);
$schedule->save();
$schedule->shiftType()->associate($st); $schedule->shiftType()->associate($st);
$schedule->save();
$this->assertEquals('Shift Type', Schedule::find(1)->shiftType->name); $this->assertEquals('Shift Type', Schedule::find(1)->shiftType->name);
} }

View File

@ -4,6 +4,7 @@ namespace Engelsystem\Test\Unit\Models\User;
use Carbon\Carbon; use Carbon\Carbon;
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\BaseModel; use Engelsystem\Models\BaseModel;
use Engelsystem\Models\Group; use Engelsystem\Models\Group;
use Engelsystem\Models\News; use Engelsystem\Models\News;
@ -18,6 +19,7 @@ use Engelsystem\Models\User\PersonalData;
use Engelsystem\Models\User\Settings; use Engelsystem\Models\User\Settings;
use Engelsystem\Models\User\State; use Engelsystem\Models\User\State;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
use Engelsystem\Models\Worklog; use Engelsystem\Models\Worklog;
use Engelsystem\Test\Unit\Models\ModelTest; use Engelsystem\Test\Unit\Models\ModelTest;
use Exception; use Exception;
@ -212,6 +214,52 @@ class UserTest extends ModelTest
$this->assertEquals($relatedModelIds, $user->{$name}->modelKeys()); $this->assertEquals($relatedModelIds, $user->{$name}->modelKeys());
} }
/**
* @covers \Engelsystem\Models\User\User::userAngelTypes
* @return void
*/
public function testUserAngelTypes()
{
AngelType::factory(2)->create();
$angelType1 = AngelType::factory()->create();
AngelType::factory(1)->create();
$angelType2 = AngelType::factory()->create();
$user = new User($this->data);
$user->save();
$user->userAngelTypes()->attach($angelType1);
$user->userAngelTypes()->attach($angelType2);
/** @var UserAngelType $userAngelType */
$userAngelType = UserAngelType::find(1);
$this->assertEquals($user->id, $userAngelType->user->id);
$angeltypes = $user->userAngelTypes;
$this->assertCount(2, $angeltypes);
}
/**
* @covers \Engelsystem\Models\User\User::isAngelTypeSupporter
* @return void
*/
public function testIsAngelTypeSupporter()
{
/** @var AngelType $angelType1 */
$angelType1 = AngelType::factory()->create();
/** @var AngelType $angelType2 */
$angelType2 = AngelType::factory()->create();
$user = new User($this->data);
$user->save();
$user->userAngelTypes()->attach($angelType1, ['supporter' => true]);
$user->userAngelTypes()->attach($angelType2);
$this->assertTrue($user->isAngelTypeSupporter($angelType1));
$this->assertFalse($user->isAngelTypeSupporter($angelType2));
}
/** /**
* @covers \Engelsystem\Models\User\User::privileges * @covers \Engelsystem\Models\User\User::privileges
* @covers \Engelsystem\Models\User\User::getPrivilegesAttribute * @covers \Engelsystem\Models\User\User::getPrivilegesAttribute

View File

@ -0,0 +1,112 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Test\Unit\Models;
use Engelsystem\Models\AngelType;
use Engelsystem\Models\User\User;
use Engelsystem\Models\UserAngelType;
use Illuminate\Database\Eloquent\Model;
class UserAngelTypeTest extends ModelTest
{
/** @var User|Model */
protected $user;
/** @var User|Model */
protected $confirmed;
/** @var AngelType|Model */
protected $angeltype;
/**
* @covers \Engelsystem\Models\UserAngelType
*/
public function testCreateDefault(): void
{
$model = new UserAngelType();
$model->user()->associate($this->user);
$model->angelType()->associate($this->angeltype);
$model->save();
/** @var UserAngelType $model */
$model = UserAngelType::find(1);
$this->assertEquals($this->user->id, $model->user->id);
$this->assertEquals($this->angeltype->id, $model->angelType->id);
$this->assertNull($model->confirmUser);
$this->assertFalse($model->supporter);
}
/**
* @covers \Engelsystem\Models\UserAngelType
* @covers \Engelsystem\Models\UserAngelType::angelType
* @covers \Engelsystem\Models\UserAngelType::confirmUser
*/
public function testCreateAssociation(): void
{
$this->user
->userAngelTypes()
->attach($this->angeltype, ['confirm_user_id' => $this->confirmed->id, 'supporter' => true]);
/** @var UserAngelType $model */
$model = UserAngelType::find(1);
$this->assertEquals($this->user->id, $model->user->id);
$this->assertEquals($this->angeltype->id, $model->angelType->id);
$this->assertEquals($this->confirmed->id, $model->confirmUser->id);
$this->assertTrue($model->supporter);
}
/**
* @covers \Engelsystem\Models\UserAngelType::confirmUser
*/
public function testConfirmUser(): void
{
$model = new UserAngelType();
$model->user()->associate($this->user);
$model->angelType()->associate($this->angeltype);
$model->confirmUser()->associate($this->confirmed);
$model->save();
/** @var UserAngelType $model */
$model = UserAngelType::find(1);
$this->assertEquals($this->confirmed->id, $model->confirmUser->id);
}
/**
* @covers \Engelsystem\Models\UserAngelType::angelType
*/
public function testAngelType(): void
{
$model = new UserAngelType();
$model->user()->associate($this->user);
$model->angelType()->associate($this->angeltype);
$model->save();
/** @var UserAngelType $model */
$model = UserAngelType::find(1);
$this->assertEquals($this->angeltype->id, $model->angelType->id);
}
/**
* @covers \Engelsystem\Models\UserAngelType::getPivotAttributes
*/
public function testGetPivotAttributes(): void
{
$attributes = UserAngelType::getPivotAttributes();
$this->assertContains('id', $attributes);
$this->assertContains('supporter', $attributes);
$this->assertContains('confirm_user_id', $attributes);
}
public function setUp(): void
{
parent::setUp();
$this->user = User::factory()->create(['id' => 42]);
$this->confirmed = User::factory()->create(['id' => 1337]);
$this->angeltype = AngelType::factory()->create(['id' => 21]);
}
}