the browser-facing portion of osu!
at master 4.4 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6namespace App\Libraries; 7 8use App\Models\Beatmap; 9use App\Models\Beatmapset; 10use App\Models\RankHighest; 11use App\Models\User; 12use App\Models\UserBadge; 13use App\Models\UsernameChangeHistory; 14use Carbon\Carbon; 15use DB; 16use Illuminate\Support\Collection; 17 18class UsernameValidation 19{ 20 public static function validateAvailability(string $username): ValidationErrors 21 { 22 $errors = new ValidationErrors('user'); 23 24 if (($availableDate = User::checkWhenUsernameAvailable($username)) > Carbon::now()) { 25 $remaining = Carbon::now()->diff($availableDate, false); 26 27 // the times are +1 to round up the interval; e.g. 5 days, 2 hours will show 6 days 28 if ($remaining->days + 1 >= User::INACTIVE_DAYS) { 29 //no need to mention the inactivity period of the account is actively in use. 30 $errors->add('username', '.username_in_use'); 31 } elseif ($remaining->days > 0) { 32 $errors->add( 33 'username', 34 '.username_available_in', 35 ['duration' => osu_trans_choice('common.count.days', $remaining->days + 1)] 36 ); 37 } elseif ($remaining->h > 0) { 38 $errors->add( 39 'username', 40 '.username_available_in', 41 ['duration' => osu_trans_choice('common.count.hours', $remaining->h + 1)] 42 ); 43 } else { 44 $errors->add('username', '.username_available_soon'); 45 } 46 } 47 48 return $errors; 49 } 50 51 public static function validateUsername($username) 52 { 53 $errors = new ValidationErrors('user'); 54 55 if (($username ?? '') !== trim($username)) { 56 $errors->add('username', '.username_no_spaces'); 57 } 58 59 if (strlen($username) < 3) { 60 $errors->add('username', '.username_too_short'); 61 } 62 63 if (strlen($username) > 15) { 64 $errors->add('username', '.username_too_long'); 65 } 66 67 if (strpos($username, ' ') !== false || !preg_match('#^[A-Za-z0-9-\[\]_ ]+$#u', $username)) { 68 $errors->add('username', '.username_invalid_characters'); 69 } 70 71 if (strpos($username, '_') !== false && strpos($username, ' ') !== false) { 72 $errors->add('username', '.username_no_space_userscore_mix'); 73 } 74 75 foreach (model_pluck(DB::table('phpbb_disallow'), 'disallow_username') as $check) { 76 if (preg_match('#^'.str_replace('%', '.*?', preg_quote($check, '#')).'$#i', $username)) { 77 $errors->add('username', '.username_not_allowed'); 78 break; 79 } 80 } 81 82 return $errors; 83 } 84 85 public static function validateUsersOfUsername(string $username): ValidationErrors 86 { 87 $errors = new ValidationErrors('user'); 88 $userIds = static::usersOfUsername($username)->pluck('user_id'); 89 90 // Check if any of the users have been ranked in the top 100 91 $highestRank = RankHighest::whereIn('user_id', $userIds)->min('rank'); 92 if ($highestRank !== null && $highestRank <= 100) { 93 return $errors->add('username', '.username_locked'); 94 } 95 96 // Check if any of the users have badges 97 if (UserBadge::whereIn('user_id', $userIds)->exists()) { 98 return $errors->add('username', '.username_locked'); 99 } 100 101 // Check if any of the users have beatmaps or beatmapsets with 102 // leaderboards enabled 103 if ( 104 Beatmap::scoreable()->whereIn('user_id', $userIds)->exists() || 105 Beatmapset::scoreable()->whereIn('user_id', $userIds)->exists() 106 ) { 107 return $errors->add('username', '.username_locked'); 108 } 109 110 return $errors; 111 } 112 113 private static function usersOfUsername(string $username): Collection 114 { 115 $userIds = UsernameChangeHistory::where('username_last', $username)->pluck('user_id'); 116 $users = User::whereIn('user_id', $userIds)->get(); 117 $existing = User::findByUsernameForInactive($username); 118 if ($existing !== null) { 119 $users->push($existing); 120 } 121 122 return $users; 123 } 124}