<?php12namespace Pterodactyl\Models;34use Pterodactyl\Rules\Username;5use Pterodactyl\Facades\Activity;6use Illuminate\Support\Collection;7use Illuminate\Validation\Rules\In;8use Illuminate\Auth\Authenticatable;9use Illuminate\Notifications\Notifiable;10use Illuminate\Database\Eloquent\Builder;11use Pterodactyl\Models\Traits\HasAccessTokens;12use Illuminate\Auth\Passwords\CanResetPassword;13use Pterodactyl\Traits\Helpers\AvailableLanguages;14use Illuminate\Database\Eloquent\Relations\HasMany;15use Illuminate\Foundation\Auth\Access\Authorizable;16use Illuminate\Database\Eloquent\Factories\HasFactory;17use Illuminate\Database\Eloquent\Relations\MorphToMany;18use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;19use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;20use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;21use Pterodactyl\Notifications\SendPasswordReset as ResetPasswordNotification;2223/**24* Pterodactyl\Models\User.25*26* @property int $id27* @property string|null $external_id28* @property string $uuid29* @property string $username30* @property string $email31* @property string|null $name_first32* @property string|null $name_last33* @property string $password34* @property string|null $remember_token35* @property string $language36* @property bool $root_admin37* @property bool $use_totp38* @property string|null $totp_secret39* @property \Illuminate\Support\Carbon|null $totp_authenticated_at40* @property bool $gravatar41* @property \Illuminate\Support\Carbon|null $created_at42* @property \Illuminate\Support\Carbon|null $updated_at43* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\ApiKey[] $apiKeys44* @property int|null $api_keys_count45* @property string $name46* @property \Illuminate\Notifications\DatabaseNotificationCollection|\Illuminate\Notifications\DatabaseNotification[] $notifications47* @property int|null $notifications_count48* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\RecoveryToken[] $recoveryTokens49* @property int|null $recovery_tokens_count50* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Server[] $servers51* @property int|null $servers_count52* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\UserSSHKey[] $sshKeys53* @property int|null $ssh_keys_count54* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\ApiKey[] $tokens55* @property int|null $tokens_count56*57* @method static \Database\Factories\UserFactory factory(...$parameters)58* @method static Builder|User newModelQuery()59* @method static Builder|User newQuery()60* @method static Builder|User query()61* @method static Builder|User whereCreatedAt($value)62* @method static Builder|User whereEmail($value)63* @method static Builder|User whereExternalId($value)64* @method static Builder|User whereGravatar($value)65* @method static Builder|User whereId($value)66* @method static Builder|User whereLanguage($value)67* @method static Builder|User whereNameFirst($value)68* @method static Builder|User whereNameLast($value)69* @method static Builder|User wherePassword($value)70* @method static Builder|User whereRememberToken($value)71* @method static Builder|User whereRootAdmin($value)72* @method static Builder|User whereTotpAuthenticatedAt($value)73* @method static Builder|User whereTotpSecret($value)74* @method static Builder|User whereUpdatedAt($value)75* @method static Builder|User whereUseTotp($value)76* @method static Builder|User whereUsername($value)77* @method static Builder|User whereUuid($value)78*79* @mixin \Eloquent80*/81class User extends Model implements82AuthenticatableContract,83AuthorizableContract,84CanResetPasswordContract85{86use Authenticatable;87use Authorizable;88use AvailableLanguages;89use CanResetPassword;90/** @use \Pterodactyl\Models\Traits\HasAccessTokens<\Pterodactyl\Models\ApiKey> */91use HasAccessTokens;92use Notifiable;93/** @use \Illuminate\Database\Eloquent\Factories\HasFactory<\Database\Factories\UserFactory> */94use HasFactory;9596public const USER_LEVEL_USER = 0;97public const USER_LEVEL_ADMIN = 1;9899/**100* The resource name for this model when it is transformed into an101* API representation using fractal.102*/103public const RESOURCE_NAME = 'user';104105/**106* Level of servers to display when using access() on a user.107*/108protected string $accessLevel = 'all';109110/**111* The table associated with the model.112*/113protected $table = 'users';114115/**116* A list of mass-assignable variables.117*/118protected $fillable = [119'external_id',120'username',121'email',122'name_first',123'name_last',124'password',125'language',126'use_totp',127'totp_secret',128'totp_authenticated_at',129'gravatar',130'root_admin',131];132133/**134* Cast values to correct type.135*/136protected $casts = [137'root_admin' => 'boolean',138'use_totp' => 'boolean',139'gravatar' => 'boolean',140'totp_authenticated_at' => 'datetime',141];142143/**144* The attributes excluded from the model's JSON form.145*/146protected $hidden = ['password', 'remember_token', 'totp_secret', 'totp_authenticated_at'];147148/**149* Default values for specific fields in the database.150*/151protected $attributes = [152'external_id' => null,153'root_admin' => false,154'language' => 'en',155'use_totp' => false,156'totp_secret' => null,157];158159/**160* Rules verifying that the data being stored matches the expectations of the database.161*/162public static array $validationRules = [163'uuid' => 'required|string|size:36|unique:users,uuid',164'email' => 'required|email|between:1,191|unique:users,email',165'external_id' => 'sometimes|nullable|string|max:191|unique:users,external_id',166'username' => 'required|between:1,191|unique:users,username',167'name_first' => 'required|string|between:1,191',168'name_last' => 'required|string|between:1,191',169'password' => 'sometimes|nullable|string',170'root_admin' => 'boolean',171'language' => 'string',172'use_totp' => 'boolean',173'totp_secret' => 'nullable|string',174];175176/**177* Implement language verification by overriding Eloquence's gather178* rules function.179*/180public static function getRules(): array181{182$rules = parent::getRules();183184$rules['language'][] = new In(array_keys((new self())->getAvailableLanguages()));185$rules['username'][] = new Username();186187return $rules;188}189190/**191* Return the user model in a format that can be passed over to Vue templates.192*/193public function toVueObject(): array194{195return Collection::make($this->toArray())->except(['id', 'external_id'])->toArray();196}197198/**199* Send the password reset notification.200*201* @param string $token202*/203public function sendPasswordResetNotification($token)204{205Activity::event('auth:reset-password')206->withRequestMetadata()207->subject($this)208->log('sending password reset email');209210$this->notify(new ResetPasswordNotification($token));211}212213/**214* Store the username as a lowercase string.215*/216public function setUsernameAttribute(string $value)217{218$this->attributes['username'] = mb_strtolower($value);219}220221/**222* Return a concatenated result for the accounts full name.223*/224public function getNameAttribute(): string225{226return trim($this->name_first . ' ' . $this->name_last);227}228229/**230* Returns all servers that a user owns.231*232* @return \Illuminate\Database\Eloquent\Relations\HasMany<\Pterodactyl\Models\Server, $this>233*/234public function servers(): HasMany235{236return $this->hasMany(Server::class, 'owner_id');237}238239/**240* @return \Illuminate\Database\Eloquent\Relations\HasMany<\Pterodactyl\Models\ApiKey, $this>241*/242public function apiKeys(): HasMany243{244return $this->hasMany(ApiKey::class)245->where('key_type', ApiKey::TYPE_ACCOUNT);246}247248/**249* @return \Illuminate\Database\Eloquent\Relations\HasMany<\Pterodactyl\Models\RecoveryToken, $this>250*/251public function recoveryTokens(): HasMany252{253return $this->hasMany(RecoveryToken::class);254}255256/**257* @return \Illuminate\Database\Eloquent\Relations\HasMany<\Pterodactyl\Models\UserSSHKey, $this>258*/259public function sshKeys(): HasMany260{261return $this->hasMany(UserSSHKey::class);262}263264/**265* Returns all the activity logs where this user is the subject — not to266* be confused by activity logs where this user is the _actor_.267*268* @return \Illuminate\Database\Eloquent\Relations\MorphToMany<\Pterodactyl\Models\ActivityLog, $this>269*/270public function activity(): MorphToMany271{272return $this->morphToMany(ActivityLog::class, 'subject', 'activity_log_subjects');273}274275/**276* Returns all the servers that a user can access by way of being the owner of the277* server, or because they are assigned as a subuser for that server.278*279* @return \Illuminate\Database\Eloquent\Builder<\Pterodactyl\Models\Server>280*/281public function accessibleServers(): Builder282{283return Server::query()284->select('servers.*')285->leftJoin('subusers', 'subusers.server_id', '=', 'servers.id')286->where(function (Builder $builder) {287$builder->where('servers.owner_id', $this->id)->orWhere('subusers.user_id', $this->id);288})289->groupBy('servers.id');290}291}292293294