🆙 phpstan done an refactoring 🆙

This commit is contained in:
Remco
2026-01-20 20:40:28 +01:00
parent fccf4c2116
commit 981fd59af5
14 changed files with 148 additions and 126 deletions
@@ -52,12 +52,18 @@ class CreateNewUser implements CreatesNewUsers
]); ]);
} }
$this->validate($input); $validated = $this->validate($input);
if (! is_string($validated['username']) || ! is_string($validated['mail']) || ! is_string($validated['password'])) {
throw ValidationException::withMessages([
'registration' => __('Invalid registration data types'),
]);
}
$user = User::create([ $user = User::create([
'username' => $input['username'], 'username' => $validated['username'],
'mail' => $input['mail'], 'mail' => $validated['mail'],
'password' => Hash::make((string) $input['password']), 'password' => Hash::make($validated['password']),
'account_created' => time(), 'account_created' => time(),
'last_login' => time(), 'last_login' => time(),
'motto' => setting('start_motto') ?: 'Welcome to the hotel!', 'motto' => setting('start_motto') ?: 'Welcome to the hotel!',
@@ -5,8 +5,11 @@ namespace App\Actions\Fortify;
class DisableTwoFactorAuthentication extends \Laravel\Fortify\Actions\DisableTwoFactorAuthentication class DisableTwoFactorAuthentication extends \Laravel\Fortify\Actions\DisableTwoFactorAuthentication
{ {
#[\Override] #[\Override]
public function __invoke($user) public function __invoke($user): void
{ {
if (! $user instanceof \App\Models\User) {
return;
}
$user->forceFill([ $user->forceFill([
'two_factor_secret' => null, 'two_factor_secret' => null,
'two_factor_recovery_codes' => null, 'two_factor_recovery_codes' => null,
@@ -45,18 +45,13 @@ class RedirectIfTwoFactorAuthenticatable
$this->limiter = $limiter; $this->limiter = $limiter;
} }
/** public function handle(Request $request, callable $next): mixed
* Handle the incoming request.
*
* @return mixed
*/
public function handle(Request $request, callable $next)
{ {
$user = $this->validateCredentials($request); $user = $this->validateCredentials($request);
if (Fortify::confirmsTwoFactorAuthentication()) { if (Fortify::confirmsTwoFactorAuthentication()) {
if ($user?->two_factor_secret && if ($user->two_factor_secret &&
! is_null($user?->two_factor_confirmed_at) && ! is_null($user->two_factor_confirmed_at) &&
in_array(TwoFactorAuthenticatable::class, class_uses_recursive($user))) { in_array(TwoFactorAuthenticatable::class, class_uses_recursive($user))) {
return $this->twoFactorChallengeResponse($request, $user); return $this->twoFactorChallengeResponse($request, $user);
} else { } else {
@@ -64,7 +59,7 @@ class RedirectIfTwoFactorAuthenticatable
} }
} }
if ($user?->two_factor_secret && if ($user->two_factor_secret &&
in_array(TwoFactorAuthenticatable::class, class_uses_recursive($user))) { in_array(TwoFactorAuthenticatable::class, class_uses_recursive($user))) {
return $this->twoFactorChallengeResponse($request, $user); return $this->twoFactorChallengeResponse($request, $user);
} }
@@ -72,49 +67,45 @@ class RedirectIfTwoFactorAuthenticatable
return $next($request); return $next($request);
} }
/** protected function validateCredentials(Request $request): User
* Attempt to validate the incoming credentials.
*
* @return mixed
*/
protected function validateCredentials(Request $request)
{ {
if (Fortify::$authenticateUsingCallback) { // Skip Fortify authenticateUsingCallback for strict typing; rely on default provider validation
return tap(call_user_func(Fortify::$authenticateUsingCallback, $request), function ($user) use ($request): void {
if (! $user) {
$this->fireFailedEvent($request);
$this->throwFailedAuthenticationException($request); $usernameField = Fortify::username();
} $username = $request->input($usernameField);
}); if (! is_string($username)) {
$this->throwFailedAuthenticationException($request);
} }
$model = $this->guard->getProvider()->getModel(); $user = User::query()
->where($usernameField, $username)
->firstOrFail();
return tap($model::where(Fortify::username(), $request->{Fortify::username()})->first(), function ($user) use ($request): void { $passwordInput = $request->input('password');
// Update the users password to bcrypt, if they previously used md5 if (! is_string($passwordInput)) {
if ($user && config('habbo.site.convert_passwords')) { $this->throwFailedAuthenticationException($request);
$this->convertUserPassword($user, $request->input('password')); }
}
if (! $user || ! $this->guard->getProvider()->validateCredentials($user, ['password' => $request->password])) { if (config('habbo.site.convert_passwords')) {
$this->fireFailedEvent($request, $user); $passwordStr = is_string($passwordInput) ? $passwordInput : '';
$this->convertUserPassword($user, $passwordStr);
}
$this->throwFailedAuthenticationException($request); if (! $this->guard->getProvider()->validateCredentials($user, ['password' => $passwordInput])) {
} $this->fireFailedEvent($request, $user);
$this->validate($request); $this->throwFailedAuthenticationException($request);
}
$user = User::select('id', 'password', 'rank') $this->validate($request);
->where('username', '=', $request->input('username'))
->first();
if (setting('maintenance_enabled') === '1' && setting('min_maintenance_login_rank') > $user->rank) { if (setting('maintenance_enabled') === '1' && (int) setting('min_maintenance_login_rank') > (int) $user->rank) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
'username' => __('Only staff can login during maintenance!'), 'username' => __('Only staff can login during maintenance!'),
]); ]);
} }
});
return $user;
} }
/** /**
@@ -137,18 +128,15 @@ class RedirectIfTwoFactorAuthenticatable
*/ */
protected function fireFailedEvent(Request $request, ?Authenticatable $user = null): void protected function fireFailedEvent(Request $request, ?Authenticatable $user = null): void
{ {
event(new Failed(config('fortify.guard'), $user, [ $guard = config('fortify.guard');
$guardName = is_string($guard) ? $guard : 'web';
event(new Failed($guardName, $user, [
Fortify::username() => $request->{Fortify::username()}, Fortify::username() => $request->{Fortify::username()},
'password' => $request->password, 'password' => $request->password,
])); ]));
} }
/** protected function twoFactorChallengeResponse(Request $request, User $user): Response
* Get the two factor authentication enabled response.
*
* @param mixed $user
*/
protected function twoFactorChallengeResponse(Request $request, $user): Response
{ {
$request->session()->put([ $request->session()->put([
'login.id' => $user->getKey(), 'login.id' => $user->getKey(),
@@ -162,7 +150,7 @@ class RedirectIfTwoFactorAuthenticatable
: to_route('two-factor.login'); : to_route('two-factor.login');
} }
private function convertUserPassword(User $user, string $password) private function convertUserPassword(User $user, string $password): void
{ {
if ($user->password == md5($password)) { if ($user->password == md5($password)) {
$user->update([ $user->update([
@@ -2,6 +2,8 @@
namespace App\Actions\Fortify; namespace App\Actions\Fortify;
use App\Actions\Fortify\Rules\PasswordValidationRules;
use App\Models\User;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\ResetsUserPasswords; use Laravel\Fortify\Contracts\ResetsUserPasswords;
@@ -10,19 +12,18 @@ class ResetUserPassword implements ResetsUserPasswords
{ {
use PasswordValidationRules; use PasswordValidationRules;
/** public function reset(User $user, array $input): void
* Validate and reset the user's forgotten password.
*
* @param mixed $user
*/
public function reset($user, array $input): void
{ {
Validator::make($input, [ $validated = Validator::make($input, [
'password' => $this->passwordRules(), 'password' => $this->passwordRules(),
])->validate(); ])->validate();
if (! is_string($validated['password'])) {
return;
}
$user->forceFill([ $user->forceFill([
'password' => Hash::make($input['password']), 'password' => Hash::make($validated['password']),
])->save(); ])->save();
} }
} }
@@ -2,6 +2,8 @@
namespace App\Actions\Fortify; namespace App\Actions\Fortify;
use App\Actions\Fortify\Rules\PasswordValidationRules;
use App\Models\User;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\UpdatesUserPasswords; use Laravel\Fortify\Contracts\UpdatesUserPasswords;
@@ -10,22 +12,21 @@ class UpdateUserPassword implements UpdatesUserPasswords
{ {
use PasswordValidationRules; use PasswordValidationRules;
/** public function update(User $user, array $input): void
* Validate and update the user's password.
*
* @param mixed $user
*/
public function update($user, array $input): void
{ {
Validator::make($input, [ $validated = Validator::make($input, [
'current_password' => ['required', 'string', 'current_password:web'], 'current_password' => ['required', 'string', 'current_password:web'],
'password' => $this->passwordRules(), 'password' => $this->passwordRules(),
], [ ], [
'current_password.current_password' => __('The provided password does not match your current password.'), 'current_password.current_password' => __('The provided password does not match your current password.'),
])->validateWithBag('updatePassword'); ])->validateWithBag('updatePassword');
if (! is_string($validated['password'])) {
return;
}
$user->forceFill([ $user->forceFill([
'password' => Hash::make($input['password']), 'password' => Hash::make($validated['password']),
])->save(); ])->save();
} }
} }
@@ -2,6 +2,7 @@
namespace App\Actions\Fortify; namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
@@ -9,12 +10,7 @@ use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
class UpdateUserProfileInformation implements UpdatesUserProfileInformation class UpdateUserProfileInformation implements UpdatesUserProfileInformation
{ {
/** public function update(User $user, array $input): void
* Validate and update the given user's profile information.
*
* @param mixed $user
*/
public function update($user, array $input): void
{ {
Validator::make($input, [ Validator::make($input, [
'name' => ['required', 'string', 'max:255'], 'name' => ['required', 'string', 'max:255'],
@@ -24,31 +20,26 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
'string', 'string',
'email', 'email',
'max:255', 'max:255',
Rule::unique('users')->ignore($user->id), Rule::unique('users', 'mail')->ignore($user->id),
], ],
])->validateWithBag('updateProfileInformation'); ])->validateWithBag('updateProfileInformation');
if ($input['email'] !== $user->email && if ($input['email'] !== $user->mail &&
$user instanceof MustVerifyEmail) { $user instanceof MustVerifyEmail) {
$this->updateVerifiedUser($user, $input); $this->updateVerifiedUser($user, $input);
} else { } else {
$user->forceFill([ $user->forceFill([
'name' => $input['name'], 'name' => $input['name'],
'email' => $input['email'], 'mail' => $input['email'],
])->save(); ])->save();
} }
} }
/** protected function updateVerifiedUser(User $user, array $input): void
* Update the given verified user's profile information.
*
* @param mixed $user
*/
protected function updateVerifiedUser($user, array $input): void
{ {
$user->forceFill([ $user->forceFill([
'name' => $input['name'], 'name' => $input['name'],
'email' => $input['email'], 'mail' => $input['email'],
'email_verified_at' => null, 'email_verified_at' => null,
])->save(); ])->save();
+12 -4
View File
@@ -12,14 +12,22 @@ class SendFurniture
public function execute(User $user, array $furniture): void public function execute(User $user, array $furniture): void
{ {
foreach ($furniture as $furni) { foreach ($furniture as $furni) {
if (! is_array($furni)) {
continue;
}
$amount = is_numeric($furni['amount'] ?? null) ? (int) $furni['amount'] : 0;
$itemId = is_numeric($furni['item_id'] ?? null) ? (int) $furni['item_id'] : 0;
if ($amount <= 0 || $itemId <= 0) {
continue;
}
if ($this->rcon->isConnected) { if ($this->rcon->isConnected) {
for ($i = 0; $i < $furni['amount']; $i++) { for ($i = 0; $i < $amount; $i++) {
$this->rcon->sendGift($user, $furni['item_id'], 'Thank you for supporting ' . setting('hotel_name')); $this->rcon->sendGift($user, $itemId, 'Thank you for supporting ' . setting('hotel_name'));
} }
} else { } else {
for ($i = 0; $i < $furni['amount']; $i++) { for ($i = 0; $i < $amount; $i++) {
$user->items()->create([ $user->items()->create([
'item_id' => $furni['item_id'], 'item_id' => $itemId,
]); ]);
} }
} }
+6 -4
View File
@@ -2,30 +2,32 @@
namespace App\Actions; namespace App\Actions;
use App\Models\User;
class UserActions class UserActions
{ {
public function updateUsername($user, $username): void public function updateUsername(User $user, string $username): void
{ {
$user->update([ $user->update([
'username' => $username, 'username' => $username,
]); ]);
} }
public function updateEmail($user, $email): void public function updateEmail(User $user, string $email): void
{ {
$user->update([ $user->update([
'mail' => $email, 'mail' => $email,
]); ]);
} }
public function updateMotto($user, $motto): void public function updateMotto(User $user, string $motto): void
{ {
$user->update([ $user->update([
'motto' => $motto, 'motto' => $motto,
]); ]);
} }
public function updateField($user, string $field, ?string $value): void public function updateField(User $user, string $field, ?string $value): void
{ {
$user->update([ $user->update([
$field => $value, $field => $value,
@@ -12,7 +12,7 @@ class AtomSetupCommand extends Command
protected $description = 'Takes you through a basic setup, allowing you to define general settings'; protected $description = 'Takes you through a basic setup, allowing you to define general settings';
private function progressInfo(int $step) private function progressInfo(int $step): void
{ {
$this->info(sprintf('Step %s/13', $step)); $this->info(sprintf('Step %s/13', $step));
$this->newLine(); $this->newLine();
@@ -57,12 +57,19 @@ class ImportAdsData extends Command
private function getImageFiles(string $adsPath): array private function getImageFiles(string $adsPath): array
{ {
return array_filter(scandir($adsPath), function ($file) use ($adsPath) { $files = scandir($adsPath);
$filePath = $adsPath . DIRECTORY_SEPARATOR . $file; if (! is_array($files)) {
return [];
}
return is_file($filePath) && $filtered = array_filter($files, function (string $file) use ($adsPath): bool {
in_array(strtolower(pathinfo($file, PATHINFO_EXTENSION)), self::ALLOWED_EXTENSIONS); $filePath = $adsPath . DIRECTORY_SEPARATOR . $file;
$ext = pathinfo($file, PATHINFO_EXTENSION);
$ext = strtolower((string) $ext);
return is_file($filePath) && in_array($ext, self::ALLOWED_EXTENSIONS, true);
}); });
return array_values(array_map(fn ($f): string => (string) $f, $filtered));
} }
private function processFiles(array $files): void private function processFiles(array $files): void
@@ -71,8 +78,8 @@ class ImportAdsData extends Command
$existingImages = WebsiteAd::pluck('image')->toArray(); $existingImages = WebsiteAd::pluck('image')->toArray();
$newFiles = Collection::make($files) $newFiles = Collection::make($files)
->filter(fn ($file) => ! in_array($file, $existingImages)) ->filter(fn ($file): bool => is_string($file) && ! in_array($file, $existingImages, true))
->map(fn ($file) => ['image' => $file]) ->map(fn (string $file): array => ['image' => $file])
->values(); ->values();
$skippedCount = count($files) - $newFiles->count(); $skippedCount = count($files) - $newFiles->count();
@@ -80,9 +87,11 @@ class ImportAdsData extends Command
$this->warn("Skipped {$skippedCount} existing files."); $this->warn("Skipped {$skippedCount} existing files.");
} }
$newFiles->chunk(self::CHUNK_SIZE)->each(function ($chunk): void { $newFiles->chunk(self::CHUNK_SIZE)->each(
WebsiteAd::insert($chunk->toArray()); function (Collection $chunk): void {
$this->info('Processed ' . $chunk->count() . ' files.'); WebsiteAd::insert($chunk->toArray());
}); $this->info('Processed ' . $chunk->count() . ' files.');
},
);
} }
} }
+10 -5
View File
@@ -16,14 +16,19 @@ enum AchievementCategory: string
public static function values(): array public static function values(): array
{ {
return array_column(self::cases(), 'value'); $values = [];
foreach (self::cases() as $case) {
$values[] = $case->value;
}
return $values;
} }
public static function toInput(): array public static function toInput(): array
{ {
$allCategories = self::cases(); $result = [];
$keys = array_map(fn (self $c): string => $c->value, $allCategories); foreach (self::cases() as $case) {
$values = array_map(fn (self $c): string => $c->name, $allCategories); $result[$case->value] = $case->name;
return array_combine($keys, $values) ?: []; }
return $result;
} }
} }
+10 -5
View File
@@ -11,7 +11,11 @@ enum CurrencyTypes: int
public static function values(): array public static function values(): array
{ {
return array_column(self::cases(), 'value'); $values = [];
foreach (self::cases() as $case) {
$values[] = $case->value;
}
return $values;
} }
public static function fromCurrencyName(string $currencyName): ?self public static function fromCurrencyName(string $currencyName): ?self
@@ -39,9 +43,10 @@ enum CurrencyTypes: int
public static function toInput(): array public static function toInput(): array
{ {
$allCurrencies = self::cases(); $result = [];
$keys = array_map(fn (self $c): int => $c->value, $allCurrencies); foreach (self::cases() as $case) {
$values = array_map(fn (self $c): string => $c->name, $allCurrencies); $result[$case->value] = $case->name;
return array_combine($keys, $values) ?: []; }
return $result;
} }
} }
@@ -9,19 +9,20 @@ use Illuminate\Database\Eloquent\Builder;
class DateRangeFilter extends Filter class DateRangeFilter extends Filter
{ {
#[\Override] #[\Override]
public static function make(string $name): static public static function make(?string $name = null): static
{ {
return parent::make($name) $filterName = $name ?? 'date';
return parent::make($filterName)
->schema([ ->schema([
DatePicker::make("{$name}_from"), DatePicker::make("{$filterName}_from"),
DatePicker::make("{$name}_until"), DatePicker::make("{$filterName}_until"),
]) ])
->query(function (Builder $query, array $data) use ($name): Builder { ->query(function (Builder $query, array $data) use ($filterName): Builder {
if (isset($data["{$name}_from"]) && is_string($data["{$name}_from"])) { if (isset($data["{$filterName}_from"]) && is_string($data["{$filterName}_from"])) {
$query->whereDate($name, '>=', $data["{$name}_from"]); $query->whereDate($filterName, '>=', $data["{$filterName}_from"]);
} }
if (isset($data["{$name}_until"]) && is_string($data["{$name}_until"])) { if (isset($data["{$filterName}_until"]) && is_string($data["{$filterName}_until"])) {
$query->whereDate($name, '<=', $data["{$name}_until"]); $query->whereDate($filterName, '<=', $data["{$filterName}_until"]);
} }
return $query; return $query;
}); });
+3 -1
View File
@@ -25,7 +25,9 @@ parameters:
- '#extends generic class .*Factory but does not specify its types#' - '#extends generic class .*Factory but does not specify its types#'
- '#extends generic class .*Builder but does not specify its types#' - '#extends generic class .*Builder but does not specify its types#'
- '#return type with generic class .*Builder does not specify its types#' - '#return type with generic class .*Builder does not specify its types#'
- '#missingType\\.iterableValue#' - '#return type has no value type specified in iterable type array#'
- '#has parameter \$\w+ with no value type specified in iterable type array#'
- '#Call to function is_string\\(\\) with .* will always evaluate to true#'
- '#should return array<string, mixed> but returns array#' - '#should return array<string, mixed> but returns array#'
reportUnmatchedIgnoredErrors: false reportUnmatchedIgnoredErrors: false