Completed
Push — master ( bae40e...a4cb2c )
by James
19:36 queued 09:47
created

UserRepository::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
/**
3
 * UserRepository.php
4
 * Copyright (c) 2017 [email protected]
5
 *
6
 * This file is part of Firefly III.
7
 *
8
 * Firefly III is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * Firefly III is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
20
 */
21
declare(strict_types=1);
22
23
namespace FireflyIII\Repositories\User;
24
25
use FireflyIII\Models\BudgetLimit;
26
use FireflyIII\Models\Role;
27
use FireflyIII\User;
28
use Illuminate\Database\QueryException;
29
use Illuminate\Support\Collection;
30
use Log;
31
32
/**
33
 * Class UserRepository.
34
 *
35
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
36
 */
37
class UserRepository implements UserRepositoryInterface
38
{
39
    /**
40
     * Constructor.
41
     */
42
    public function __construct()
43
    {
44
        if ('testing' === env('APP_ENV')) {
45
            Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
46
        }
47
    }
48
49
    /**
50
     * @return Collection
51
     */
52
    public function all(): Collection
53
    {
54
        return User::orderBy('id', 'DESC')->get(['users.*']);
55
    }
56
57
    /**
58
     * @param User   $user
59
     * @param string $role
60
     *
61
     * @return bool
62
     */
63
    public function attachRole(User $user, string $role): bool
64
    {
65
        $roleObject = Role::where('name', $role)->first();
66
        if (null === $roleObject) {
67
            Log::error(sprintf('Could not find role "%s" in attachRole()', $role));
68
69
            return false;
70
        }
71
72
        try {
73
            $user->roles()->attach($roleObject);
74
        } catch (QueryException $e) {
75
            // don't care
76
            Log::error(sprintf('Query exception when giving user a role: %s', $e->getMessage()));
77
        }
78
79
        return true;
80
    }
81
82
    /**
83
     * This updates the users email address and records some things so it can be confirmed or undone later.
84
     * The user is blocked until the change is confirmed.
85
     *
86
     * @param User   $user
87
     * @param string $newEmail
88
     *
89
     * @see updateEmail
90
     *
91
     * @return bool
92
     * @throws \Exception
93
     */
94
    public function changeEmail(User $user, string $newEmail): bool
95
    {
96
        $oldEmail = $user->email;
97
98
        // save old email as pref
99
        app('preferences')->setForUser($user, 'previous_email_latest', $oldEmail);
100
        app('preferences')->setForUser($user, 'previous_email_' . date('Y-m-d-H-i-s'), $oldEmail);
101
102
        // set undo and confirm token:
103
        app('preferences')->setForUser($user, 'email_change_undo_token', bin2hex(random_bytes(16)));
104
        app('preferences')->setForUser($user, 'email_change_confirm_token', bin2hex(random_bytes(16)));
105
        // update user
106
107
        $user->email        = $newEmail;
108
        $user->blocked      = 1;
109
        $user->blocked_code = 'email_changed';
110
        $user->save();
111
112
        return true;
113
    }
114
115
    /**
116
     * @param User   $user
117
     * @param string $password
118
     *
119
     * @return bool
120
     */
121
    public function changePassword(User $user, string $password): bool
122
    {
123
        $user->password = bcrypt($password);
124
        $user->save();
125
126
        return true;
127
    }
128
129
    /**
130
     * @param User   $user
131
     * @param bool   $isBlocked
132
     * @param string $code
133
     *
134
     * @return bool
135
     */
136
    public function changeStatus(User $user, bool $isBlocked, string $code): bool
137
    {
138
        // change blocked status and code:
139
        $user->blocked      = $isBlocked;
140
        $user->blocked_code = $code;
141
        $user->save();
142
143
        return true;
144
    }
145
146
    /**
147
     * @return int
148
     */
149
    public function count(): int
150
    {
151
        return $this->all()->count();
152
    }
153
154
    /**
155
     * @param string $name
156
     * @param string $displayName
157
     * @param string $description
158
     *
159
     * @return Role
160
     */
161
    public function createRole(string $name, string $displayName, string $description): Role
162
    {
163
        return Role::create(['name' => $name, 'display_name' => $displayName, 'description' => $description]);
164
    }
165
166
    /**
167
     * @param User $user
168
     *
169
     * @return bool
170
     * @throws \Exception
171
     */
172
    public function destroy(User $user): bool
173
    {
174
        Log::debug(sprintf('Calling delete() on user %d', $user->id));
175
        $user->delete();
176
177
        return true;
178
    }
179
180
    /**
181
     * @param string $email
182
     *
183
     * @return User|null
184
     */
185
    public function findByEmail(string $email): ?User
186
    {
187
        return User::where('email', $email)->first();
188
    }
189
190
    /**
191
     * @param int $userId
192
     *
193
     * @return User|null
194
     */
195
    public function findNull(int $userId): ?User
196
    {
197
        return User::find($userId);
198
    }
199
200
    /**
201
     * Returns the first user in the DB. Generally only works when there is just one.
202
     *
203
     * @return null|User
204
     */
205
    public function first(): ?User
206
    {
207
        return User::orderBy('id', 'ASC')->first();
208
    }
209
210
    /**
211
     * @param string $role
212
     *
213
     * @return Role|null
214
     */
215
    public function getRole(string $role): ?Role
216
    {
217
        return Role::where('name', $role)->first();
218
    }
219
220
    /**
221
     * Return basic user information.
222
     *
223
     * @param User $user
224
     *
225
     * @return array
226
     */
227
    public function getUserData(User $user): array
228
    {
229
        $return = [];
230
231
        // two factor:
232
        $is2faEnabled      = app('preferences')->getForUser($user, 'twoFactorAuthEnabled', false)->data;
233
        $has2faSecret      = null !== app('preferences')->getForUser($user, 'twoFactorAuthSecret');
234
        $return['has_2fa'] = false;
235
        if ($is2faEnabled && $has2faSecret) {
236
            $return['has_2fa'] = true;
237
        }
238
239
        $return['is_admin']            = $this->hasRole($user, 'owner');
240
        $return['blocked']             = 1 === (int)$user->blocked;
241
        $return['blocked_code']        = $user->blocked_code;
242
        $return['accounts']            = $user->accounts()->count();
243
        $return['journals']            = $user->transactionJournals()->count();
244
        $return['transactions']        = $user->transactions()->count();
245
        $return['attachments']         = $user->attachments()->count();
246
        $return['attachments_size']    = $user->attachments()->sum('size');
247
        $return['bills']               = $user->bills()->count();
248
        $return['categories']          = $user->categories()->count();
249
        $return['budgets']             = $user->budgets()->count();
250
        $return['budgets_with_limits'] = BudgetLimit::distinct()
251
                                                    ->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
252
                                                    ->where('amount', '>', 0)
253
                                                    ->whereNull('budgets.deleted_at')
254
                                                    ->where('budgets.user_id', $user->id)->get(['budget_limits.budget_id'])->count();
255
        $return['export_jobs']         = $user->exportJobs()->count();
256
        $return['export_jobs_success'] = $user->exportJobs()->where('status', 'export_downloaded')->count();
257
        $return['import_jobs']         = $user->importJobs()->count();
258
        $return['import_jobs_success'] = $user->importJobs()->where('status', 'finished')->count();
259
        $return['rule_groups']         = $user->ruleGroups()->count();
260
        $return['rules']               = $user->rules()->count();
261
        $return['tags']                = $user->tags()->count();
262
263
        return $return;
264
    }
265
266
    /**
267
     * @param User   $user
268
     * @param string $role
269
     *
270
     * @return bool
271
     */
272
    public function hasRole(User $user, string $role): bool
273
    {
274
        /** @var Role $userRole */
275
        foreach ($user->roles as $userRole) {
276
            if ($userRole->name === $role) {
277
                return true;
278
            }
279
        }
280
281
        return false;
282
    }
283
284
    /**
285
     * @param array $data
286
     *
287
     * @return User
288
     */
289
    public function store(array $data): User
290
    {
291
        return User::create(
292
            [
293
                'blocked'      => $data['blocked'] ?? false,
294
                'blocked_code' => $data['blocked_code'] ?? null,
295
                'email'        => $data['email'],
296
                'password'     => str_random(24),
297
            ]
298
        );
299
    }
300
301
    /**
302
     * @param User $user
303
     */
304
    public function unblockUser(User $user): void
305
    {
306
        $user->blocked      = 0;
307
        $user->blocked_code = '';
308
        $user->save();
309
310
    }
311
312
    /**
313
     * Update user info.
314
     *
315
     * @param User  $user
316
     * @param array $data
317
     *
318
     * @return User
319
     */
320
    public function update(User $user, array $data): User
321
    {
322
        $this->updateEmail($user, $data['email']);
323
        $user->blocked      = $data['blocked'] ?? false;
324
        $user->blocked_code = $data['blocked_code'] ?? null;
325
        $user->save();
326
327
        return $user;
328
    }
329
330
    /**
331
     * This updates the users email address. Same as changeEmail just without most logging. This makes sure that the undo/confirm routine can't catch this one.
332
     * The user is NOT blocked.
333
     *
334
     * @param User   $user
335
     * @param string $newEmail
336
     *
337
     * @see changeEmail
338
     *
339
     * @return bool
340
     */
341
    public function updateEmail(User $user, string $newEmail): bool
342
    {
343
        $oldEmail = $user->email;
344
345
        // save old email as pref
346
        app('preferences')->setForUser($user, 'admin_previous_email_latest', $oldEmail);
347
        app('preferences')->setForUser($user, 'admin_previous_email_' . date('Y-m-d-H-i-s'), $oldEmail);
348
349
        $user->email = $newEmail;
350
        $user->save();
351
352
        return true;
353
    }
354
}
355