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

visavi / rotor / 27106558224

07 Jun 2026 10:21PM UTC coverage: 13.582% (-0.07%) from 13.647%
27106558224

push

github

visavi
Удалил функцию returnUrl(), механизм возврата на предыдущую страницу реализован по-другому

0 of 4 new or added lines in 1 file covered. (0.0%)

1 existing line in 1 file now uncovered.

786 of 5787 relevant lines covered (13.58%)

1.2 hits per line

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

0.0
/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\Validator;
8
use App\Http\Controllers\Controller;
9
use App\Models\BlackList;
10
use App\Models\Flood;
11
use App\Models\User;
12
use App\Models\UserField;
13
use Illuminate\Database\Query\JoinClause;
14
use Illuminate\Http\JsonResponse;
15
use Illuminate\Http\RedirectResponse;
16
use Illuminate\Http\Request;
17
use Illuminate\Support\Facades\Auth;
18
use Illuminate\Support\Facades\Hash;
19
use Illuminate\Support\Str;
20
use Illuminate\View\View;
21

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

33
        $user->load('lastBan');
×
34
        $adminGroups = User::ADMIN_GROUPS;
×
35

36
        $fields = UserField::query()->withUserData($user->id)->whereNotNull('user_data.value')->get();
×
37

38
        return view('users/user', compact('user', 'adminGroups', 'fields'));
×
39
    }
40

41
    /**
42
     * Registration
43
     */
44
    public function register(Request $request, Validator $validator): View|RedirectResponse
×
45
    {
46
        if (getUser()) {
×
47
            abort(403, __('users.already_registered'));
×
48
        }
49

50
        if (! setting('openreg')) {
×
51
            abort(200, __('users.registration_suspended'));
×
52
        }
53

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

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

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

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

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

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

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

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

118
                    // ----- Уведомление в приват ----//
119
                    $textNotice = textNotice('register', ['username' => $login]);
×
120
                    $user->sendMessage(null, $textNotice);
×
121

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

132
                    sendMail('mailer.register', $data);
×
133

134
                    Auth::login($user, true);
×
135

136
                    setFlash('success', __('users.welcome', ['login' => $login]));
×
137

138
                    return redirect('/');
×
139
                }
140

141
                setInput($request->all());
×
142
                setFlash('danger', $validator->getErrors());
×
143
            }
144
        }
145

146
        return view('users/register');
×
147
    }
148

149
    /**
150
     * Login
151
     */
152
    public function login(Request $request, Validator $validator, Flood $flood): View|RedirectResponse
×
153
    {
154
        if (Auth::check()) {
×
155
            return redirect('/')->with('danger', __('main.already_authorized'));
×
156
        }
157

158
        $isFlood = $flood->isFlood();
×
159

160
        if ($request->isMethod('post')) {
×
161
            if ($request->has(['login', 'password'])) {
×
162
                if ($isFlood) {
×
163
                    $validator->true(captchaVerify(), ['protect' => __('validator.captcha')]);
×
164
                }
165

166
                if ($validator->isValid()) {
×
167
                    $login = Str::lower((string) $request->input('login'));
×
168
                    $password = $request->input('password');
×
169
                    $remember = $request->boolean('remember');
×
170

171
                    $field = strpos($request->input('login'), '@') ? 'email' : 'login';
×
172

173
                    $credentials = [
×
174
                        $field     => $login,
×
175
                        'password' => $password,
×
176
                    ];
×
177

178
                    try {
179
                        $authorized = Auth::attempt($credentials, $remember);
×
180
                    } catch (\RuntimeException) {
×
181
                        setInput($request->all());
×
182
                        setFlash('danger', __('users.password_reset_required'));
×
183

184
                        return redirect('recovery');
×
185
                    }
186

187
                    if ($authorized) {
×
188
                        $request->session()->regenerate();
×
189
                        $user = Auth::user();
×
190

NEW
191
                        return redirect()->intended()
×
192
                            ->with('success', __('users.welcome', ['login' => $user->getName()], $user->language));
×
193
                    }
194

195
                    $flood->saveState(300);
×
196
                    setInput($request->all());
×
197
                    setFlash('danger', __('users.incorrect_login_or_password'));
×
198
                } else {
199
                    setInput($request->all());
×
200
                    setFlash('danger', $validator->getErrors());
×
201
                }
202

203
                return redirect('login');
×
204
            }
205
        }
206

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

UNCOV
213
        return view('users/login', compact('isFlood'));
×
214
    }
215

216
    /**
217
     * Exit
218
     */
219
    public function logout(Request $request): RedirectResponse
×
220
    {
221
        Auth::logout();
×
222

223
        $request->session()->invalidate();
×
224
        $request->session()->regenerateToken();
×
225

226
        return redirect('/');
×
227
    }
228

229
    /**
230
     * Profile editing
231
     */
232
    public function profile(Request $request, Validator $validator): View|RedirectResponse
×
233
    {
234
        if (! $user = getUser()) {
×
235
            abort(403, __('main.not_authorized'));
×
236
        }
237

238
        $fields = UserField::query()
×
239
            ->select('uf.*', 'ud.value')
×
240
            ->from('user_fields as uf')
×
241
            ->leftJoin('user_data as ud', static function (JoinClause $join) use ($user) {
×
242
                $join->on('uf.id', 'ud.field_id')
×
243
                    ->where('ud.user_id', $user->id);
×
244
            })
×
245
            ->orderBy('uf.sort')
×
246
            ->get();
×
247

248
        if ($request->isMethod('post')) {
×
249
            $info = $request->input('info');
×
250
            $name = $request->input('name');
×
251
            $country = $request->input('country');
×
252
            $city = $request->input('city');
×
253
            $phone = preg_replace('/[^\d+]/', '', $request->input('phone') ?? '');
×
254
            $site = $request->input('site');
×
255
            $birthday = $request->input('birthday');
×
256
            $gender = $request->input('gender') === User::MALE ? User::MALE : User::FEMALE;
×
257

258
            $validator
×
259
                ->url($site, ['site' => __('validator.site')], false)
×
260
                ->regex($birthday, '#^[0-9]{2}+\.[0-9]{2}+\.[0-9]{4}$#', ['birthday' => __('validator.date')], false)
×
261
                ->phone($phone, ['phone' => __('validator.phone')], false)
×
262
                ->length($info, 0, 1000, ['info' => __('users.info_yourself_long')])
×
263
                ->length($name, 3, 20, ['name' => __('users.name_short_or_long')], false);
×
264

265
            foreach ($fields as $field) {
×
266
                $validator->length(
×
267
                    $request->input('field' . $field->id),
×
268
                    $field->min,
×
269
                    $field->max,
×
270
                    ['field' . $field->id => __('validator.text')],
×
271
                    $field->required
×
272
                );
×
273
            }
274

275
            if ($validator->isValid()) {
×
276
                $country = Str::substr($country, 0, 30);
×
277
                $city = Str::substr($city, 0, 50);
×
278

279
                $user->update([
×
280
                    'name'     => $name,
×
281
                    'gender'   => $gender,
×
282
                    'country'  => $country,
×
283
                    'city'     => $city,
×
284
                    'phone'    => $phone,
×
285
                    'site'     => $site,
×
286
                    'birthday' => $birthday,
×
287
                    'info'     => $info,
×
288
                ]);
×
289

290
                foreach ($fields as $field) {
×
291
                    $user->data()
×
292
                        ->updateOrCreate([
×
293
                            'field_id' => $field->id,
×
294
                        ], [
×
295
                            'value' => $field->sanitizeValue($request->input('field' . $field->id)),
×
296
                        ]);
×
297
                }
298

299
                setFlash('success', __('users.profile_success_changed'));
×
300

301
                return redirect('profile');
×
302
            }
303

304
            setInput($request->all());
×
305
            setFlash('danger', $validator->getErrors());
×
306
        }
307

308
        return view('users/profile', compact('user', 'fields'));
×
309
    }
310

311
    /**
312
     * Verify registration
313
     */
314
    public function verify(Request $request, Validator $validator): View|RedirectResponse
×
315
    {
316
        if (! $user = $request->user()) {
×
317
            abort(403, __('main.not_authorized'));
×
318
        }
319

320
        if (! setting('regkeys')) {
×
321
            abort(200, __('users.confirm_registration_disabled'));
×
322
        }
323

324
        if ($user->level !== User::PENDED) {
×
325
            abort(403, __('users.profile_not_confirmation'));
×
326
        }
327

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

333
            $validator
×
334
                ->true(captchaVerify(), ['protect' => __('validator.captcha')])
×
335
                ->email($email, ['email' => __('validator.email')]);
×
336

337
            $validator
×
338
                ->false(User::query()->where('login', '<>', $user->login)->where('email', $email)->exists(), ['email' => __('users.email_already_exists')])
×
339
                ->false(BlackList::isBlacklisted('email', $email), ['email' => __('users.email_is_blacklisted')])
×
340
                ->false(BlackList::isBlacklisted('domain', $domain), ['email' => __('users.domain_is_blacklisted')]);
×
341

342
            if ($validator->isValid()) {
×
343
                $token = Str::random(32);
×
344
                $confirmUrl = route('confirm', ['token' => $token]);
×
345

346
                $user->update([
×
347
                    'email'         => $email,
×
348
                    'confirm_token' => $token,
×
349
                ]);
×
350

351
                /* Уведомление о регистрации на email */
352
                $subject = 'Регистрация на ' . setting('title');
×
353
                $data = [
×
354
                    'to'         => $email,
×
355
                    'subject'    => $subject,
×
356
                    'login'      => $user->login,
×
357
                    'password'   => '*****',
×
358
                    'confirmUrl' => $confirmUrl,
×
359
                ];
×
360

361
                sendMail('mailer.register', $data);
×
362
                setFlash('success', __('users.confirm_code_success_sent'));
×
363

364
                return redirect()->route('verify');
×
365
            }
366

367
            setInput($request->all());
×
368
            setFlash('danger', $validator->getErrors());
×
369
        }
370

371
        return view('users/verify', compact('user'));
×
372
    }
373

374
    /**
375
     * Confirm registration
376
     */
377
    public function confirm(string $token): RedirectResponse
×
378
    {
379
        $user = User::query()->where('confirm_token', $token)->first();
×
380
        if (! $user) {
×
381
            abort(200, __('users.confirm_code_invalid'));
×
382
        }
383

384
        $user->update([
×
385
            'level'         => User::USER,
×
386
            'confirm_token' => null,
×
387
        ]);
×
388

389
        return redirect('/')->with('success', __('users.account_success_activated'));
×
390
    }
391

392
    /**
393
     * Settings
394
     */
395
    public function setting(Request $request, Validator $validator): View|RedirectResponse
×
396
    {
397
        if (! $user = getUser()) {
×
398
            abort(403, __('main.not_authorized'));
×
399
        }
400

401
        $setting['themes'] = getAvailableThemes();
×
402
        $setting['languages'] = getAvailableLanguages();
×
403
        $setting['timezones'] = range(-12, 12);
×
404

405
        if ($request->isMethod('post')) {
×
406
            $themes = $request->input('themes');
×
407
            $timezone = $request->input('timezone', 0);
×
408
            $language = $request->input('language');
×
409
            $notifyMention = $request->input('notify_mention') ? 1 : 0;
×
410
            $notifyReply = $request->input('notify_reply') ? 1 : 0;
×
411
            $notifyComment = $request->input('notify_comment') ? 1 : 0;
×
412
            $subscribe = $request->input('subscribe') ? Str::random(32) : null;
×
413

414
            $validator
×
415
                ->regex($themes, '|^[a-z0-9_\-]+$|i', ['themes' => __('users.theme_invalid')])
×
416
                ->true(in_array($themes, $setting['themes'], true) || empty($themes), ['themes' => __('users.theme_not_installed')])
×
417
                ->regex($language, '|^[a-z]+$|', ['language' => __('users.language_invalid')])
×
418
                ->in($language, $setting['languages'], ['language' => __('users.language_not_installed')])
×
419
                ->regex($timezone, '|^[\-\+]{0,1}[0-9]{1,2}$|', ['timezone' => __('users.timezone_invalid')]);
×
420

421
            if ($validator->isValid()) {
×
422
                $user->update([
×
423
                    'themes'         => $themes,
×
424
                    'timezone'       => $timezone,
×
425
                    'notify_mention' => $notifyMention,
×
426
                    'notify_reply'   => $notifyReply,
×
427
                    'notify_comment' => $notifyComment,
×
428
                    'subscribe'      => $subscribe,
×
429
                    'language'       => $language,
×
430
                ]);
×
431

432
                if (now()->month === 4 && now()->day === 1 && ! empty($themes)) {
×
433
                    $request->session()->put('april_fools_theme', $themes);
×
434
                }
435

436
                setFlash('success', __('users.settings_success_changed'));
×
437

438
                return redirect('settings');
×
439
            }
440

441
            setInput($request->all());
×
442
            setFlash('danger', $validator->getErrors());
×
443
        }
444

445
        return view('users/settings', compact('user', 'setting'));
×
446
    }
447

448
    /**
449
     * Проверка доступности логина
450
     */
451
    public function checkLogin(Request $request, Validator $validator): JsonResponse
×
452
    {
453
        $login = (string) $request->input('login');
×
454

455
        $validator
×
456
            ->true($request->ajax(), __('validator.not_ajax'))
×
457
            ->regex($login, '|^[a-z0-9\-]+$|i', __('validator.login'))
×
458
            ->regex(Str::substr($login, 0, 1), '|^[a-z0-9]+$|i', __('users.login_begin_requirements'))
×
459
            ->length($login, 3, 20, __('users.login_length_requirements'))
×
460
            ->false(ctype_digit($login), __('users.field_characters_requirements'))
×
461
            ->false(substr_count($login, '-') > 2, __('users.login_hyphens_requirements'));
×
462

463
        if ($validator->isValid()) {
×
464
            $existLogin = User::query()
×
465
                ->where('login', $login)
×
466
                ->exists();
×
467

468
            $validator
×
469
                ->false($existLogin, __('users.login_already_exists'))
×
470
                ->false(BlackList::isBlacklisted('login', strtolower($login)), __('users.login_is_blacklisted'));
×
471
        }
472

473
        if ($validator->isValid()) {
×
474
            return response()->json(['success' => true]);
×
475
        }
476

477
        return response()->json([
×
478
            'success' => false,
×
479
            'message' => current($validator->getErrors()),
×
480
        ]);
×
481
    }
482

483
    /**
484
     * Поиск пользователей для упоминаний
485
     */
486
    public function searchUsers(Request $request): JsonResponse
×
487
    {
488
        $query = (string) $request->input('query', '');
×
489

490
        if (mb_strlen($query) < 2) {
×
491
            return response()->json();
×
492
        }
493

494
        $users = User::query()
×
495
            ->where(function ($q) use ($query) {
×
496
                $q->where('login', 'like', $query . '%')
×
497
                    ->orWhere('name', 'like', $query . '%');
×
498
            })
×
499
            ->orderByDesc('point')
×
500
            ->limit(10)
×
501
            ->get(['login', 'name']);
×
502

503
        return response()->json($users);
×
504
    }
505
}
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