Issues (158)

app/User.php (2 issues)

1
<?php
2
3
namespace App;
4
5
use DateTimeInterface;
6
use Illuminate\Database\Eloquent\Builder;
7
use Illuminate\Foundation\Auth\User as Authenticatable;
8
use Illuminate\Notifications\Notifiable;
9
use Illuminate\Support\MessageBag;
10
11
class User extends Authenticatable
12
{
13
14
    use Notifiable;
15
16
    /**
17
     * The attributes that are mass assignable.
18
     *
19
     * @var array
20
     */
21
    protected $fillable = ['in_alma', 'firstname', 'lastname', 'phone', 'email', 'lang'];
22
23
    /**
24
     * The attributes that should be cast to native types.
25
     *
26
     * @var array
27
     */
28
    protected $casts = [
29
        'blocks' => 'array',
30
        'fees' => 'integer',
31
    ];
32
33
   /**
34
     * The attributes that should be mutated to dates.
35
     *
36
     * @var array
37
     */
38
    protected $dates = ['last_loan_at'];
39
40
    /**
41
     * The accessors to append to the model's array form.
42
     *
43
     * @var array
44
     */
45
    protected $appends = ['name', 'url'];
46
47
    /**
48
     * Array of user-editable attributes (excluding machine-generated stuff)
49
     *
50
     * @static array
51
     */
52
    public static $editableAttributes = [
53
        'lastname', 'firstname', 'phone', 'email', 'lang', 'note'
54
    ];
55
56
    /**
57
     * Prepare a date for array / JSON serialization.
58
     *
59
     * @param  \DateTimeInterface  $date
60
     * @return string
61
     */
62
    protected function serializeDate(DateTimeInterface $date)
63
    {
64
        return $date->format('Y-m-d H:i:s');
65
    }
66
67
    /**
68
     * Find user from some identifier (Alma primary id, barcode or other).
69
     *
70
     * @param string $identifier
71
     * @return User|null
72
     */
73
    public static function fromIdentifier($identifier)
74
    {
75
        if (empty($identifier)) {
76
            return null;
77
        }
78
        $user = User::where('alma_primary_id', '=', $identifier)->first();
79
        if (is_null($user)) {
80
            $user = User::whereHas('identifiers', function (Builder $query) use ($identifier) {
81
                $query->where('value', '=', $identifier);
82
            })->first();
83
        }
84
85
        return $user;
86
    }
87
88
    public function identifiers()
89
    {
90
        return $this->hasMany(UserIdentifier::class);
91
    }
92
93
    public function getAllIdentifierValues()
94
    {
95
        $values = [];
96
        if ($this->alma_primary_id) {
97
            $values[] = $this->alma_primary_id;
98
        }
99
        foreach ($this->identifiers as $identifier) {
100
            $values[] = $identifier['value'];
101
        }
102
        return $values;
103
    }
104
105
    public function loans()
106
    {
107
        return $this->hasMany(Loan::class);
108
    }
109
110
    public function deliveredLoans()
111
    {
112
        return $this->hasMany(Loan::class)
113
            ->whereNotNull('deleted_at')
114
            ->with('item.thing')
115
            ->withTrashed()
116
            ->orderBy('created_at', 'desc');
117
    }
118
119
    public function getNameAttribute()
120
    {
121
        return $this->lastname . ', ' . $this->firstname;
122
    }
123
124
    public function getUrlAttribute()
125
    {
126
        return action('UsersController@getShow', $this->id);
127
    }
128
129
    protected function mergeAttribute($key, User $user)
130
    {
131
        return strlen($user->$key) > strlen($this->$key) ? $user->$key : $this->$key;
132
    }
133
134
    /**
135
     * Get data for merging $user into the current user. The returned
136
     * array can be passed directly to mergeWith or presented to a user
137
     * for review first.
138
     *
139
     * @param  User  $user
140
     * @return array
141
     */
142
    public function getMergeData($user)
143
    {
144
        $merged = array();
145
        foreach (static::$editableAttributes as $attr) {
146
            $merged[$attr] = $this->mergeAttribute($attr, $user);
147
        }
148
        $merged['identifiers'] = [];
149
        foreach ($this->identifiers()->get(['type', 'value']) as $identifier) {
150
            $merged['identifiers'][] = $identifier;
151
        }
152
        foreach ($user->identifiers()->get(['type', 'value']) as $identifier) {
153
            $merged['identifiers'][] = $identifier;
154
        }
155
        return $merged;
156
    }
157
158
    /**
159
     * Merge in another user $user
160
     *
161
     * @param  User  $user
162
     * @param  array  $data  An array of merged attributes (optional)
163
     * @return \Illuminate\Support\MessageBag
164
     */
165
    public function merge(User $user, array $data = null)
166
    {
167
168
        if (is_null($data)) {
169
            $data = $this->getMergeData($user);
170
        }
171
172
        // Validate
173
        $errors = new MessageBag();
174
175
        // if (!empty($ltid) && !empty($user->ltid) && ($ltid != $user->ltid)) {
176
        //  $errors->add('ltid_conflict', "Kan ikke flette nytt LTID $ltid med eksisterende $user->ltid.");
177
        // }
178
179
        // if (!empty($ltid) && !empty($this->ltid) && ($ltid != $this->ltid)) {
180
        //  $errors->add('ltid_conflict', "Kan ikke flette nytt LTID $ltid med eksisterende $this->ltid.");
181
        // }
182
183
        if ($errors->count() > 0) {
184
            return $errors;
185
        }
186
187
        \Log::info('Slo sammen to brukere (ID ' . $user->id . ' og ' . $this->id . ')');
188
189
        foreach ($user->loans as $loan) {
190
            $loan->user_id = $this->id;
191
            $loan->save();
192
            \Log::info('Lån ' . $loan->id . ' flyttet fra bruker ' . $user->id . ' til ' . $this->id);
193
        }
194
195
        // Delete other user first to avoid database integrity conflicts
196
        $user->delete();
197
198
        // Update properties of the current user with merge data
199
        foreach ($data as $key => $val) {
200
            if ($key != 'identifiers') {
201
                $this->$key = $val;
202
            }
203
        }
204
205
        $this->save();
206
207
        $this->setIdentifiers($data['identifiers']);
208
209
        return null;
210
    }
211
212
    public function hasFees()
213
    {
214
        return $this->fees !== 0;
215
    }
216
217
    /**
218
     * Update unique value. If the value clashes with another user, delete the other user if it has no loans.
219
     *
220
     * @param array $identifiers
221
     * @param bool $deleteOnConflict
222
     */
223
    public function setIdentifiers(array $identifiers, bool $deleteOnConflict = false)
224
    {
225
        $currentValues = $this->identifiers->pluck('value')->toArray();
226
227
        $newIdentifiers = [];
228
        foreach ($identifiers as $identifier) {
229
            $newIdentifiers[$identifier['value']] = $identifier['type'];
230
        }
231
232
        $newValues = array_keys($newIdentifiers);
233
234
        $valuesToRemove = array_diff($currentValues, $newValues);
235
        $valuesToAdd = array_diff($newValues, $currentValues);
236
237
        $toAdd = array_map(function ($value) use ($newIdentifiers) {
238
            return [
239
                'user_id' => $this->id,
240
                'value' => $value,
241
                'type' => $newIdentifiers[$value],
242
            ];
243
        }, $valuesToAdd);
244
245
        // Check uniqueness
246
        foreach ($toAdd as $identifier) {
247
            $model = UserIdentifier::where('value', '=', $identifier['value'])->first();
248
            if (!is_null($model) && $model->user_id !== $this->id) {
249
                if ($deleteOnConflict) {
250
                    $this->deleteOtherUserIfPossible($model->user, $identifier['value']);
251
                } else {
252
                    throw new \RuntimeException(
253
                        "ID-konflikt for verdien {$identifier['value']}, og kan ikke slette {$model->user->id}."
254
                    );
255
                }
256
            }
257
        }
258
259
        if (count($valuesToRemove) || count($valuesToAdd)) {
260
            $msg = sprintf(
261
                'Oppdaterte identifikatorer for <a href="%s">%s</a>.',
262
                action('UsersController@getShow', $this->id),
263
                $this->name
264
            );
265
266
            // Delete
267
            if (count($valuesToRemove)) {
268
                $msg .= sprintf(
269
                    ' Fjernet: %s.',
270
                    implode(', ', $valuesToRemove)
271
                );
272
                UserIdentifier::where('user_id', '=', $this->id)->whereIn('value', $valuesToRemove)->delete();
273
            }
274
275
            // Add
276
            if (count($valuesToAdd)) {
277
                $msg .= sprintf(
278
                    ' La til: %s.',
279
                    implode(', ', $valuesToAdd)
280
                );
281
                UserIdentifier::insert($toAdd);
282
            }
283
284
            \Log::info($msg);
285
        }
286
    }
287
288
    /**
289
     * Set Alma Primary Id. If the value clashes with another user, delete the other user if it has no loans.
290
     *
291
     * @param string $value
292
     * @param bool $deleteOnConflict
293
     */
294
    public function setAlmaPrimaryId(string $value, $deleteOnConflict = false)
295
    {
296
        // Check for uniqueness
297
        if (is_null($this->id)) {
0 ignored issues
show
The condition is_null($this->id) is always false.
Loading history...
298
            // Model not saved yet
299
            $otherUser = User::where('alma_primary_id', '=', $value)->first();
300
        } else {
301
            $otherUser = User::where('alma_primary_id', '=', $value)->where('id', '!=', $this->id)->first();
302
        }
303
304
        if (!is_null($otherUser)) {
305
            if ($deleteOnConflict) {
306
                $this->deleteOtherUserIfPossible($otherUser, $value);
307
            } else {
308
                throw new \RuntimeException(
309
                    "ID-konflikt for verdien {$value}, og kan ikke slette {$otherUser->id}."
310
                );
311
            }
312
        }
313
314
        $this->alma_primary_id = $value;
315
    }
316
317
    protected function deleteOtherUserIfPossible(User $otherUser, string $value)
318
    {
319
        if (!$otherUser->loans->count()) {
320
            if (!is_null($this->id)) {
0 ignored issues
show
The condition is_null($this->id) is always false.
Loading history...
321
                $localRef = "brukeren med ID {$this->id}";
322
            } else {
323
                $localRef = "(ny bruker)";
324
            }
325
            \Log::warning(
326
                "Verdien '{$value}' er i bruk som identifikator for flere brukere. " .
327
                "Sletter brukeren med ID {$otherUser->id} (som ikke hadde noen lån), beholder $localRef."
328
            );
329
            $otherUser->delete();
330
        } else {
331
            throw new \RuntimeException(
332
                "Verdien '{$value}' er i bruk som identifikator for flere brukere. ".
333
                "Kan ikke slette brukeren {$otherUser->id} fordi brukeren har lån."
334
            );
335
        }
336
    }
337
}
338