• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

visavi / rotor / 28949359550

08 Jul 2026 02:12PM UTC coverage: 32.717% (-0.8%) from 33.484%
28949359550

push

github

visavi
Вынес в модуль пользовательские поля, статистику и рейтинг пользователя

5 of 23 new or added lines in 6 files covered. (21.74%)

4 existing lines in 3 files now uncovered.

1859 of 5682 relevant lines covered (32.72%)

3.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

51.45
/app/Http/Controllers/User/UserController.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace App\Http\Controllers\User;
6

7
use App\Classes\Registry;
8
use App\Classes\Validator;
9
use App\Http\Controllers\Controller;
10
use App\Models\BlackList;
11
use App\Models\Flood;
12
use App\Models\User;
13
use Illuminate\Http\JsonResponse;
14
use Illuminate\Http\RedirectResponse;
15
use Illuminate\Http\Request;
16
use Illuminate\Support\Facades\Auth;
17
use Illuminate\Support\Facades\Hash;
18
use Illuminate\Support\Str;
19
use Illuminate\View\View;
20

21
class UserController extends Controller
22
{
23
    /**
24
     * User profile
25
     */
26
    public function index(string $login): View
3✔
27
    {
28
        if (! $user = getUserByLogin($login)) {
3✔
29
            abort(404, __('validator.user'));
×
30
        }
31

32
        $user->load('lastBan');
3✔
33
        $adminGroups = User::ADMIN_GROUPS;
3✔
34

35
        return view('users/user', compact('user', 'adminGroups'));
3✔
36
    }
37

38
    /**
39
     * Registration
40
     */
41
    public function register(Request $request, Validator $validator): View|RedirectResponse
17✔
42
    {
43
        if (getUser()) {
17✔
44
            abort(403, __('users.already_registered'));
2✔
45
        }
46

47
        if (! setting('openreg')) {
15✔
48
            abort(200, __('users.registration_suspended'));
1✔
49
        }
50

51
        if ($request->isMethod('post')) {
14✔
52
            if ($request->has(['login', 'password'])) {
13✔
53
                $login = (string) $request->input('login');
13✔
54
                $password = $request->input('password');
13✔
55
                $password2 = $request->input('password2');
13✔
56
                $email = strtolower((string) $request->input('email'));
13✔
57
                $domain = Str::substr(strrchr($email, '@'), 1);
13✔
58
                $gender = $request->input('gender') === User::MALE ? User::MALE : User::FEMALE;
13✔
59

60
                $validator->true(captchaVerify(), ['protect' => __('validator.captcha')])
13✔
61
                    ->regex($login, '|^[a-z0-9\-]+$|i', ['login' => __('validator.login')])
13✔
62
                    ->regex(Str::substr($login, 0, 1), '|^[a-z0-9]+$|i', ['login' => __('users.login_begin_requirements')])
13✔
63
                    ->email($email, ['email' => __('validator.email')])
13✔
64
                    ->length($login, 3, 20, ['login' => __('users.login_length_requirements')])
13✔
65
                    ->length($password, 6, 20, ['password' => __('users.password_length_requirements')])
13✔
66
                    ->equal($password, $password2, ['password2' => __('users.passwords_different')])
13✔
67
                    ->false(ctype_digit($login), ['login' => __('users.field_characters_requirements')])
13✔
68
                    ->false(ctype_digit($password), ['password' => __('users.field_characters_requirements')])
13✔
69
                    ->false(substr_count($login, '-') > 2, ['login' => __('users.login_hyphens_requirements')]);
13✔
70

71
                if (! empty($login)) {
13✔
72
                    // Проверка логина на существование
73
                    $checkLogin = User::query()->where('login', $login)->exists();
13✔
74
                    $validator->false($checkLogin, ['login' => __('users.login_already_exists')]);
13✔
75

76
                    // Проверка логина в черном списке
77
                    $validator->false(BlackList::isBlacklisted('login', strtolower($login)), ['login' => __('users.login_is_blacklisted')]);
13✔
78
                }
79

80
                // Проверка email на существование
81
                $checkMail = User::query()->where('email', $email)->exists();
13✔
82
                $validator->false($checkMail, ['email' => __('users.email_already_exists')]);
13✔
83

84
                // Проверка домена от email и email в черном списке
85
                $validator
13✔
86
                    ->false(BlackList::isBlacklisted('domain', $domain), ['email' => __('users.domain_is_blacklisted')])
13✔
87
                    ->false(BlackList::isBlacklisted('email', $email), ['email' => __('users.email_is_blacklisted')]);
13✔
88

89
                // Подтверждение регистрации
90
                $confirmToken = null;
13✔
91
                $confirmUrl = null;
13✔
92
                if (setting('regkeys')) {
13✔
93
                    $confirmToken = Str::random(32);
1✔
94
                    $confirmUrl = route('confirm', ['token' => $confirmToken]);
1✔
95
                }
96

97
                // Регистрация аккаунта
98
                if ($validator->isValid()) {
13✔
99
                    $user = User::query()->create([
2✔
100
                        'login'         => $login,
2✔
101
                        'password'      => Hash::make($password),
2✔
102
                        'email'         => $email,
2✔
103
                        'level'         => setting('regkeys') ? User::PENDED : User::USER,
2✔
104
                        'gender'        => $gender,
2✔
105
                        'themes'        => setting('themes'),
2✔
106
                        'point'         => 0,
2✔
107
                        'language'      => setting('language'),
2✔
108
                        'money'         => setting('registermoney'),
2✔
109
                        'subscribe'     => Str::random(32),
2✔
110
                        'confirm_token' => $confirmToken,
2✔
111
                        'updated_at'    => now(),
2✔
112
                    ]);
2✔
113

114
                    // ----- Уведомление в приват ----//
115
                    $textNotice = textNotice('register', ['username' => $login]);
2✔
116
                    $user->sendMessage(null, $textNotice);
2✔
117

118
                    // --- Уведомление о регистрации на email ---//
119
                    $subject = 'Регистрация на ' . setting('title');
2✔
120
                    $data = [
2✔
121
                        'to'         => $email,
2✔
122
                        'subject'    => $subject,
2✔
123
                        'login'      => $login,
2✔
124
                        'password'   => $password,
2✔
125
                        'confirmUrl' => $confirmUrl,
2✔
126
                    ];
2✔
127

128
                    sendMail('mailer.register', $data);
2✔
129

130
                    Auth::login($user, true);
2✔
131

132
                    setFlash('success', __('users.welcome', ['login' => $login]));
2✔
133

134
                    return redirect('/');
2✔
135
                }
136

137
                setInput($request->all());
11✔
138
                setFlash('danger', $validator->getErrors());
11✔
139
            }
140
        }
141

142
        return view('users/register');
12✔
143
    }
144

145
    /**
146
     * Login
147
     */
148
    public function login(Request $request, Validator $validator, Flood $flood): View|RedirectResponse
9✔
149
    {
150
        if (Auth::check()) {
9✔
151
            return redirect('/')->with('danger', __('main.already_authorized'));
3✔
152
        }
153

154
        $isFlood = $flood->isFlood();
6✔
155

156
        if ($request->isMethod('post')) {
6✔
157
            if ($request->has(['login', 'password'])) {
5✔
158
                if ($isFlood) {
5✔
159
                    $validator->true(captchaVerify(), ['protect' => __('validator.captcha')]);
1✔
160
                }
161

162
                if ($validator->isValid()) {
5✔
163
                    $login = Str::lower((string) $request->input('login'));
5✔
164
                    $password = $request->input('password');
5✔
165
                    $remember = $request->boolean('remember');
5✔
166

167
                    $field = strpos($request->input('login'), '@') ? 'email' : 'login';
5✔
168

169
                    $credentials = [
5✔
170
                        $field     => $login,
5✔
171
                        'password' => $password,
5✔
172
                    ];
5✔
173

174
                    try {
175
                        $authorized = Auth::attempt($credentials, $remember);
5✔
176
                    } catch (\RuntimeException) {
×
177
                        setInput($request->all());
×
178
                        setFlash('danger', __('users.password_reset_required'));
×
179

180
                        return redirect('recovery');
×
181
                    }
182

183
                    if ($authorized) {
5✔
184
                        $request->session()->regenerate();
4✔
185
                        $user = Auth::user();
4✔
186

187
                        return redirect()->intended()
4✔
188
                            ->with('success', __('users.welcome', ['login' => $user->getName()], $user->language));
4✔
189
                    }
190

191
                    $flood->saveState(300);
2✔
192
                    setInput($request->all());
2✔
193
                    setFlash('danger', __('users.incorrect_login_or_password'));
2✔
194
                } else {
195
                    setInput($request->all());
1✔
196
                    setFlash('danger', $validator->getErrors());
1✔
197
                }
198

199
                return redirect('login');
2✔
200
            }
201
        }
202

203
        // Запоминаем страницу, с которой пришёл гость, для возврата после входа
204
        $previous = url()->previous();
1✔
205
        if (! Str::contains($previous, ['/login', '/register', '/recovery'])) {
1✔
206
            $request->session()->put('url.intended', $previous);
1✔
207
        }
208

209
        return view('users/login', compact('isFlood'));
1✔
210
    }
211

212
    /**
213
     * Exit
214
     */
215
    public function logout(Request $request): RedirectResponse
1✔
216
    {
217
        Auth::logout();
1✔
218

219
        $request->session()->invalidate();
1✔
220
        $request->session()->regenerateToken();
1✔
221

222
        return redirect('/');
1✔
223
    }
224

225
    /**
226
     * Profile editing
227
     */
228
    public function profile(Request $request, Validator $validator): View|RedirectResponse
3✔
229
    {
230
        if (! $user = getUser()) {
3✔
231
            abort(403, __('main.not_authorized'));
1✔
232
        }
233

234
        if ($request->isMethod('post')) {
2✔
UNCOV
235
            $info = $request->input('info');
×
236
            $name = $request->input('name');
×
237
            $country = $request->input('country');
×
238
            $city = $request->input('city');
×
239
            $phone = preg_replace('/[^\d+]/', '', $request->input('phone') ?? '');
×
240
            $site = $request->input('site');
×
241
            $birthday = $request->input('birthday');
×
242
            $gender = $request->input('gender') === User::MALE ? User::MALE : User::FEMALE;
×
243

244
            $validator
×
245
                ->url($site, ['site' => __('validator.site')], false)
×
246
                ->regex($birthday, '#^[0-9]{2}+\.[0-9]{2}+\.[0-9]{4}$#', ['birthday' => __('validator.date')], false)
×
247
                ->phone($phone, ['phone' => __('validator.phone')], false)
×
248
                ->length($info, 0, 1000, ['info' => __('users.info_yourself_long')])
×
249
                ->length($name, 3, 20, ['name' => __('users.name_short_or_long')], false);
×
250

NEW
251
            foreach (Registry::$onProfileValidate as $handler) {
×
NEW
252
                $handler($user, $request, $validator, true);
×
253
            }
254

255
            if ($validator->isValid()) {
×
256
                $country = Str::substr($country, 0, 30);
×
257
                $city = Str::substr($city, 0, 50);
×
258

259
                $user->update([
×
260
                    'name'     => $name,
×
261
                    'gender'   => $gender,
×
262
                    'country'  => $country,
×
263
                    'city'     => $city,
×
264
                    'phone'    => $phone,
×
265
                    'site'     => $site,
×
266
                    'birthday' => $birthday,
×
267
                    'info'     => $info,
×
268
                ]);
×
269

NEW
270
                foreach (Registry::$onProfileSave as $handler) {
×
NEW
271
                    $handler($user, $request);
×
272
                }
273

274
                setFlash('success', __('users.profile_success_changed'));
×
275

276
                return redirect('profile');
×
277
            }
278

279
            setInput($request->all());
×
280
            setFlash('danger', $validator->getErrors());
×
281
        }
282

283
        return view('users/profile', compact('user'));
2✔
284
    }
285

286
    /**
287
     * Verify registration
288
     */
289
    public function verify(Request $request, Validator $validator): View|RedirectResponse
3✔
290
    {
291
        if (! $user = $request->user()) {
3✔
292
            abort(403, __('main.not_authorized'));
1✔
293
        }
294

295
        if (! setting('regkeys')) {
2✔
296
            abort(200, __('users.confirm_registration_disabled'));
2✔
297
        }
298

299
        if ($user->level !== User::PENDED) {
×
300
            abort(403, __('users.profile_not_confirmation'));
×
301
        }
302

303
        /* Повторная отправка */
304
        if ($request->has('email') && $request->isMethod('post')) {
×
305
            $email = strtolower((string) $request->input('email'));
×
306
            $domain = Str::substr(strrchr($email, '@'), 1);
×
307

308
            $validator
×
309
                ->true(captchaVerify(), ['protect' => __('validator.captcha')])
×
310
                ->email($email, ['email' => __('validator.email')]);
×
311

312
            $validator
×
313
                ->false(User::query()->where('login', '<>', $user->login)->where('email', $email)->exists(), ['email' => __('users.email_already_exists')])
×
314
                ->false(BlackList::isBlacklisted('email', $email), ['email' => __('users.email_is_blacklisted')])
×
315
                ->false(BlackList::isBlacklisted('domain', $domain), ['email' => __('users.domain_is_blacklisted')]);
×
316

317
            if ($validator->isValid()) {
×
318
                $token = Str::random(32);
×
319
                $confirmUrl = route('confirm', ['token' => $token]);
×
320

321
                $user->update([
×
322
                    'email'         => $email,
×
323
                    'confirm_token' => $token,
×
324
                ]);
×
325

326
                /* Уведомление о регистрации на email */
327
                $subject = 'Регистрация на ' . setting('title');
×
328
                $data = [
×
329
                    'to'         => $email,
×
330
                    'subject'    => $subject,
×
331
                    'login'      => $user->login,
×
332
                    'password'   => '*****',
×
333
                    'confirmUrl' => $confirmUrl,
×
334
                ];
×
335

336
                sendMail('mailer.register', $data);
×
337
                setFlash('success', __('users.confirm_code_success_sent'));
×
338

339
                return redirect()->route('verify');
×
340
            }
341

342
            setInput($request->all());
×
343
            setFlash('danger', $validator->getErrors());
×
344
        }
345

346
        return view('users/verify', compact('user'));
×
347
    }
348

349
    /**
350
     * Confirm registration
351
     */
352
    public function confirm(string $token): RedirectResponse
1✔
353
    {
354
        $user = User::query()->where('confirm_token', $token)->first();
1✔
355
        if (! $user) {
1✔
356
            abort(200, __('users.confirm_code_invalid'));
×
357
        }
358

359
        $user->update([
1✔
360
            'level'         => User::USER,
1✔
361
            'confirm_token' => null,
1✔
362
        ]);
1✔
363

364
        return redirect('/')->with('success', __('users.account_success_activated'));
1✔
365
    }
366

367
    /**
368
     * Settings
369
     */
370
    public function setting(Request $request, Validator $validator): View|RedirectResponse
3✔
371
    {
372
        if (! $user = getUser()) {
3✔
373
            abort(403, __('main.not_authorized'));
1✔
374
        }
375

376
        $setting['themes'] = getAvailableThemes();
2✔
377
        $setting['languages'] = getAvailableLanguages();
2✔
378
        $setting['timezones'] = range(-12, 12);
2✔
379

380
        if ($request->isMethod('post')) {
2✔
381
            $themes = $request->input('themes');
×
382
            $timezone = $request->input('timezone', 0);
×
383
            $language = $request->input('language');
×
384
            $notifyMention = $request->input('notify_mention') ? 1 : 0;
×
385
            $notifyReply = $request->input('notify_reply') ? 1 : 0;
×
386
            $notifyComment = $request->input('notify_comment') ? 1 : 0;
×
387
            $subscribe = $request->input('subscribe') ? Str::random(32) : null;
×
388

389
            $validator
×
390
                ->regex($themes, '|^[a-z0-9_\-]+$|i', ['themes' => __('users.theme_invalid')])
×
391
                ->true(in_array($themes, $setting['themes'], true) || empty($themes), ['themes' => __('users.theme_not_installed')])
×
392
                ->regex($language, '|^[a-z]+$|', ['language' => __('users.language_invalid')])
×
393
                ->in($language, $setting['languages'], ['language' => __('users.language_not_installed')])
×
394
                ->regex($timezone, '|^[\-\+]{0,1}[0-9]{1,2}$|', ['timezone' => __('users.timezone_invalid')]);
×
395

396
            if ($validator->isValid()) {
×
397
                $user->update([
×
398
                    'themes'         => $themes,
×
399
                    'timezone'       => $timezone,
×
400
                    'notify_mention' => $notifyMention,
×
401
                    'notify_reply'   => $notifyReply,
×
402
                    'notify_comment' => $notifyComment,
×
403
                    'subscribe'      => $subscribe,
×
404
                    'language'       => $language,
×
405
                ]);
×
406

407
                if (now()->month === 4 && now()->day === 1 && ! empty($themes)) {
×
408
                    $request->session()->put('april_fools_theme', $themes);
×
409
                }
410

411
                setFlash('success', __('users.settings_success_changed'));
×
412

413
                return redirect('settings');
×
414
            }
415

416
            setInput($request->all());
×
417
            setFlash('danger', $validator->getErrors());
×
418
        }
419

420
        return view('users/settings', compact('user', 'setting'));
2✔
421
    }
422

423
    /**
424
     * Проверка доступности логина
425
     */
426
    public function checkLogin(Request $request, Validator $validator): JsonResponse
×
427
    {
428
        $login = (string) $request->input('login');
×
429

430
        $validator
×
431
            ->true($request->ajax(), __('validator.not_ajax'))
×
432
            ->regex($login, '|^[a-z0-9\-]+$|i', __('validator.login'))
×
433
            ->regex(Str::substr($login, 0, 1), '|^[a-z0-9]+$|i', __('users.login_begin_requirements'))
×
434
            ->length($login, 3, 20, __('users.login_length_requirements'))
×
435
            ->false(ctype_digit($login), __('users.field_characters_requirements'))
×
436
            ->false(substr_count($login, '-') > 2, __('users.login_hyphens_requirements'));
×
437

438
        if ($validator->isValid()) {
×
439
            $existLogin = User::query()
×
440
                ->where('login', $login)
×
441
                ->exists();
×
442

443
            $validator
×
444
                ->false($existLogin, __('users.login_already_exists'))
×
445
                ->false(BlackList::isBlacklisted('login', strtolower($login)), __('users.login_is_blacklisted'));
×
446
        }
447

448
        if ($validator->isValid()) {
×
449
            return response()->json(['success' => true]);
×
450
        }
451

452
        return response()->json([
×
453
            'success' => false,
×
454
            'message' => current($validator->getErrors()),
×
455
        ]);
×
456
    }
457

458
    /**
459
     * Поиск пользователей для упоминаний
460
     */
461
    public function searchUsers(Request $request): JsonResponse
3✔
462
    {
463
        $query = (string) $request->input('query', '');
3✔
464

465
        if (mb_strlen($query) < 2) {
3✔
466
            return response()->json();
3✔
467
        }
468

469
        $users = User::query()
×
470
            ->where(function ($q) use ($query) {
×
471
                $q->where('login', 'like', $query . '%')
×
472
                    ->orWhere('name', 'like', $query . '%');
×
473
            })
×
474
            ->orderByDesc('point')
×
475
            ->limit(10)
×
476
            ->get(['login', 'name']);
×
477

478
        return response()->json($users);
×
479
    }
480
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc