Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
72 / 72 |
|
100.00% |
28 / 28 |
CRAP | |
100.00% |
1 / 1 |
User | |
100.00% |
72 / 72 |
|
100.00% |
28 / 28 |
30 | |
100.00% |
1 / 1 |
contact | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
groups | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isFreeloader | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
siftEntriesMarkedFreeloaded | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
license | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
privileges | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
getPrivilegesAttribute | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
personalData | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
settings | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
state | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
userAngelTypes | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
isAngelTypeSupporter | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
logs | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
news | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
newsComments | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
oauth | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
shiftEntries | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
worklogs | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
worklogsCreated | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
sessions | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
questionsAsked | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
questionsAnswered | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
messagesSent | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
messagesReceived | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
messages | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
shiftsCreated | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
shiftsUpdated | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getDisplayNameAttribute | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace Engelsystem\Models\User; |
6 | |
7 | use Carbon\Carbon; |
8 | use Engelsystem\Models\AngelType; |
9 | use Engelsystem\Models\BaseModel; |
10 | use Engelsystem\Models\Group; |
11 | use Engelsystem\Models\LogEntry; |
12 | use Engelsystem\Models\Message; |
13 | use Engelsystem\Models\News; |
14 | use Engelsystem\Models\NewsComment; |
15 | use Engelsystem\Models\OAuth; |
16 | use Engelsystem\Models\Privilege; |
17 | use Engelsystem\Models\Question; |
18 | use Engelsystem\Models\Session; |
19 | use Engelsystem\Models\Shifts\Shift; |
20 | use Engelsystem\Models\Shifts\ShiftEntry; |
21 | use Engelsystem\Models\UserAngelType; |
22 | use Engelsystem\Models\Worklog; |
23 | use Illuminate\Database\Eloquent\Builder; |
24 | use Illuminate\Database\Eloquent\Collection; |
25 | use Illuminate\Database\Eloquent\Factories\HasFactory; |
26 | use Illuminate\Database\Eloquent\Relations\BelongsToMany; |
27 | use Illuminate\Database\Eloquent\Relations\HasMany; |
28 | use Illuminate\Database\Eloquent\Relations\HasOne; |
29 | use Illuminate\Database\Query\Builder as QueryBuilder; |
30 | use Illuminate\Support\Collection as SupportCollection; |
31 | |
32 | /** |
33 | * @property int $id |
34 | * @property string $name |
35 | * @property string $email |
36 | * @property string $password |
37 | * @property string $api_key |
38 | * @property Carbon|null $last_login_at |
39 | * @property Carbon|null $created_at |
40 | * @property Carbon|null $updated_at |
41 | * |
42 | * @property-read QueryBuilder|Contact $contact |
43 | * @property-read QueryBuilder|License $license |
44 | * @property-read QueryBuilder|PersonalData $personalData |
45 | * @property-read QueryBuilder|Settings $settings |
46 | * @property-read QueryBuilder|State $state |
47 | * @property-read string $displayName |
48 | * |
49 | * @property-read Collection|Group[] $groups |
50 | * @property-read Collection|LogEntry[] $logs |
51 | * @property-read Collection|News[] $news |
52 | * @property-read Collection|NewsComment[] $newsComments |
53 | * @property-read Collection|OAuth[] $oauth |
54 | * @property-read SupportCollection|Privilege[] $privileges |
55 | * @property-read Collection|AngelType[] $userAngelTypes |
56 | * @property-read UserAngelType $pivot |
57 | * @property-read Collection|ShiftEntry[] $shiftEntries |
58 | * @property-read Collection|ShiftEntry[] $siftEntriesMarkedFreeloaded |
59 | * @property-read Collection|Session[] $sessions |
60 | * @property-read Collection|Worklog[] $worklogs |
61 | * @property-read Collection|Worklog[] $worklogsCreated |
62 | * @property-read Collection|Question[] $questionsAsked |
63 | * @property-read Collection|Question[] $questionsAnswered |
64 | * @property-read Collection|Message[] $messagesReceived |
65 | * @property-read Collection|Message[] $messagesSent |
66 | * @property-read Collection|Message[] $messages |
67 | * @property-read Collection|Shift[] $shiftsCreated |
68 | * @property-read Collection|Shift[] $shiftsUpdated |
69 | * |
70 | * @method static QueryBuilder|User[] whereId($value) |
71 | * @method static QueryBuilder|User[] whereName($value) |
72 | * @method static QueryBuilder|User[] whereEmail($value) |
73 | * @method static QueryBuilder|User[] wherePassword($value) |
74 | * @method static QueryBuilder|User[] whereApiKey($value) |
75 | * @method static QueryBuilder|User[] whereLastLoginAt($value) |
76 | * @method static QueryBuilder|User[] whereCreatedAt($value) |
77 | * @method static QueryBuilder|User[] whereUpdatedAt($value) |
78 | */ |
79 | class User extends BaseModel |
80 | { |
81 | use HasFactory; |
82 | |
83 | /** @var bool enable timestamps */ |
84 | public $timestamps = true; // phpcs:ignore |
85 | |
86 | /** @var array<string, null> default attributes */ |
87 | protected $attributes = [ // phpcs:ignore |
88 | 'last_login_at' => null, |
89 | ]; |
90 | |
91 | /** |
92 | * The attributes that are mass assignable. |
93 | * |
94 | * @var array<string> |
95 | */ |
96 | protected $fillable = [ // phpcs:ignore |
97 | 'name', |
98 | 'password', |
99 | 'email', |
100 | 'api_key', |
101 | 'last_login_at', |
102 | ]; |
103 | |
104 | /** @var array<string> The attributes that should be hidden for serialization */ |
105 | protected $hidden = [ // phpcs:ignore |
106 | 'api_key', |
107 | 'password', |
108 | ]; |
109 | |
110 | /** @var array<string, string> */ |
111 | protected $casts = [ // phpcs:ignore |
112 | 'last_login_at' => 'datetime', |
113 | ]; |
114 | |
115 | public function contact(): HasOne |
116 | { |
117 | return $this |
118 | ->hasOne(Contact::class) |
119 | ->withDefault(); |
120 | } |
121 | |
122 | public function groups(): BelongsToMany |
123 | { |
124 | return $this->belongsToMany(Group::class, 'users_groups'); |
125 | } |
126 | |
127 | public function isFreeloader(): bool |
128 | { |
129 | return $this->shiftEntries() |
130 | ->whereNotNull('freeloaded_by') |
131 | ->count() |
132 | >= config('max_freeloadable_shifts'); |
133 | } |
134 | |
135 | public function siftEntriesMarkedFreeloaded(): HasMany |
136 | { |
137 | return $this->hasMany(ShiftEntry::class, 'freeloaded_by'); |
138 | } |
139 | |
140 | public function license(): HasOne |
141 | { |
142 | return $this |
143 | ->hasOne(License::class) |
144 | ->withDefault(); |
145 | } |
146 | |
147 | public function privileges(): Builder |
148 | { |
149 | /** @var Builder $builder */ |
150 | $builder = Privilege::query() |
151 | ->whereIn('id', function ($query): void { |
152 | /** @var QueryBuilder $query */ |
153 | $query->select('privilege_id') |
154 | ->from('group_privileges') |
155 | ->join('users_groups', 'users_groups.group_id', '=', 'group_privileges.group_id') |
156 | ->where('users_groups.user_id', '=', $this->id) |
157 | ->distinct(); |
158 | }); |
159 | |
160 | return $builder; |
161 | } |
162 | |
163 | public function getPrivilegesAttribute(): SupportCollection |
164 | { |
165 | return $this->privileges()->get(); |
166 | } |
167 | |
168 | public function personalData(): HasOne |
169 | { |
170 | return $this |
171 | ->hasOne(PersonalData::class) |
172 | ->withDefault(); |
173 | } |
174 | |
175 | public function settings(): HasOne |
176 | { |
177 | return $this |
178 | ->hasOne(Settings::class) |
179 | ->withDefault(); |
180 | } |
181 | |
182 | public function state(): HasOne |
183 | { |
184 | return $this |
185 | ->hasOne(State::class) |
186 | ->withDefault(); |
187 | } |
188 | |
189 | public function userAngelTypes(): BelongsToMany |
190 | { |
191 | return $this |
192 | ->belongsToMany(AngelType::class, 'user_angel_type') |
193 | ->using(UserAngelType::class) |
194 | ->withPivot(UserAngelType::getPivotAttributes()); |
195 | } |
196 | |
197 | public function isAngelTypeSupporter(AngelType $angelType): bool |
198 | { |
199 | return $this->userAngelTypes() |
200 | ->wherePivot('angel_type_id', $angelType->id) |
201 | ->wherePivot('supporter', true) |
202 | ->exists(); |
203 | } |
204 | |
205 | public function logs(): HasMany |
206 | { |
207 | return $this->hasMany(LogEntry::class); |
208 | } |
209 | |
210 | public function news(): HasMany |
211 | { |
212 | return $this->hasMany(News::class); |
213 | } |
214 | |
215 | public function newsComments(): HasMany |
216 | { |
217 | return $this->hasMany(NewsComment::class); |
218 | } |
219 | |
220 | public function oauth(): HasMany |
221 | { |
222 | return $this->hasMany(OAuth::class); |
223 | } |
224 | |
225 | public function shiftEntries(): HasMany |
226 | { |
227 | return $this->hasMany(ShiftEntry::class); |
228 | } |
229 | |
230 | public function worklogs(): HasMany |
231 | { |
232 | return $this->hasMany(Worklog::class); |
233 | } |
234 | |
235 | public function worklogsCreated(): HasMany |
236 | { |
237 | return $this->hasMany(Worklog::class, 'creator_id'); |
238 | } |
239 | |
240 | public function sessions(): HasMany |
241 | { |
242 | return $this->hasMany(Session::class); |
243 | } |
244 | |
245 | public function questionsAsked(): HasMany |
246 | { |
247 | return $this->hasMany(Question::class, 'user_id') |
248 | ->where('user_id', $this->id); |
249 | } |
250 | |
251 | public function questionsAnswered(): HasMany |
252 | { |
253 | return $this->hasMany(Question::class, 'answerer_id') |
254 | ->where('answerer_id', $this->id); |
255 | } |
256 | |
257 | public function messagesSent(): HasMany |
258 | { |
259 | return $this->hasMany(Message::class, 'user_id') |
260 | ->orderBy('created_at', 'DESC') |
261 | ->orderBy('id', 'DESC'); |
262 | } |
263 | |
264 | public function messagesReceived(): HasMany |
265 | { |
266 | return $this->hasMany(Message::class, 'receiver_id') |
267 | ->orderBy('read') |
268 | ->orderBy('created_at', 'DESC') |
269 | ->orderBy('id', 'DESC'); |
270 | } |
271 | |
272 | /** |
273 | * Returns a HasMany relation for all messages sent or received by the user. |
274 | */ |
275 | public function messages(): HasMany |
276 | { |
277 | return $this->messagesSent() |
278 | ->union($this->messagesReceived()) |
279 | ->orderBy('read') |
280 | ->orderBy('id', 'DESC'); |
281 | } |
282 | |
283 | public function shiftsCreated(): HasMany |
284 | { |
285 | return $this->hasMany(Shift::class, 'created_by'); |
286 | } |
287 | |
288 | public function shiftsUpdated(): HasMany |
289 | { |
290 | return $this->hasMany(Shift::class, 'updated_by'); |
291 | } |
292 | |
293 | public function getDisplayNameAttribute(): string |
294 | { |
295 | if ( |
296 | config('display_full_name') |
297 | && !empty(trim($this->personalData->first_name . $this->personalData->last_name)) |
298 | ) { |
299 | return trim( |
300 | trim((string) $this->personalData->first_name) |
301 | . ' ' . |
302 | trim((string) $this->personalData->last_name) |
303 | ); |
304 | } |
305 | |
306 | return $this->name; |
307 | } |
308 | } |