<?php12namespace Pterodactyl\Models;34use Carbon\Carbon;5use Illuminate\Support\Facades\Event;6use Pterodactyl\Events\ActivityLogged;7use Illuminate\Database\Eloquent\Builder;8use Illuminate\Database\Eloquent\MassPrunable;9use Pterodactyl\Contracts\Models\Identifiable;10use Illuminate\Database\Eloquent\Relations\HasOne;11use Illuminate\Database\Eloquent\Relations\HasMany;12use Illuminate\Database\Eloquent\Relations\MorphTo;13use Pterodactyl\Models\Traits\HasRealtimeIdentifier;14use Illuminate\Database\Eloquent\Model as IlluminateModel;1516/**17* \Pterodactyl\Models\ActivityLog.18*19* @property int $id20* @property string|null $batch21* @property string $event22* @property string $ip23* @property string|null $description24* @property string|null $actor_type25* @property int|null $actor_id26* @property int|null $api_key_id27* @property \Illuminate\Support\Collection|null $properties28* @property Carbon $timestamp29* @property IlluminateModel|\Eloquent $actor30* @property \Illuminate\Database\Eloquent\Collection<int, \Pterodactyl\Models\ActivityLogSubject> $subjects31* @property int|null $subjects_count32* @property ApiKey|null $apiKey33*34* @method static Builder|ActivityLog forActor(\Illuminate\Database\Eloquent\Model $actor)35* @method static Builder|ActivityLog forEvent(string $action)36* @method static Builder|ActivityLog newModelQuery()37* @method static Builder|ActivityLog newQuery()38* @method static Builder|ActivityLog query()39* @method static Builder|ActivityLog whereActorId($value)40* @method static Builder|ActivityLog whereActorType($value)41* @method static Builder|ActivityLog whereApiKeyId($value)42* @method static Builder|ActivityLog whereBatch($value)43* @method static Builder|ActivityLog whereDescription($value)44* @method static Builder|ActivityLog whereEvent($value)45* @method static Builder|ActivityLog whereId($value)46* @method static Builder|ActivityLog whereIp($value)47* @method static Builder|ActivityLog whereProperties($value)48* @method static Builder|ActivityLog whereTimestamp($value)49*50* @mixin \Eloquent51*/52#[Attributes\Identifiable('actl')]53class ActivityLog extends Model implements Identifiable54{55use MassPrunable;56use HasRealtimeIdentifier;5758public const RESOURCE_NAME = 'activity_log';5960/**61* Tracks all the events we no longer wish to display to users. These are either legacy62* events or just events where we never ended up using the associated data.63*/64public const DISABLED_EVENTS = ['server:file.upload'];6566public $timestamps = false;6768protected $guarded = [69'id',70'timestamp',71];7273protected $casts = [74'properties' => 'collection',75'timestamp' => 'datetime',76];7778protected $with = ['subjects'];7980public static array $validationRules = [81'event' => ['required', 'string'],82'batch' => ['nullable', 'uuid'],83'ip' => ['required', 'string'],84'description' => ['nullable', 'string'],85'properties' => ['array'],86];8788/**89* @return \Illuminate\Database\Eloquent\Relations\MorphTo<\Illuminate\Database\Eloquent\Model, $this>90*/91public function actor(): MorphTo92{93$morph = $this->morphTo();94if (method_exists($morph, 'withTrashed')) { // @phpstan-ignore function.alreadyNarrowedType95return $morph->withTrashed();96}9798return $morph;99}100101/**102* @return \Illuminate\Database\Eloquent\Relations\HasMany<\Pterodactyl\Models\ActivityLogSubject, $this>103*/104public function subjects(): HasMany105{106return $this->hasMany(ActivityLogSubject::class);107}108109/**110* @return \Illuminate\Database\Eloquent\Relations\HasOne<\Pterodactyl\Models\ApiKey, $this>111*/112public function apiKey(): HasOne113{114return $this->hasOne(ApiKey::class, 'id', 'api_key_id');115}116117public function scopeForEvent(Builder $builder, string $action): Builder118{119return $builder->where('event', $action);120}121122/**123* Scopes a query to only return results where the actor is a given model.124*/125public function scopeForActor(Builder $builder, IlluminateModel $actor): Builder126{127return $builder->whereMorphedTo('actor', $actor);128}129130/**131* Returns models to be pruned.132*133* @see https://laravel.com/docs/9.x/eloquent#pruning-models134*/135public function prunable()136{137if (is_null(config('activity.prune_days'))) {138throw new \LogicException('Cannot prune activity logs: no "prune_days" configuration value is set.');139}140141return static::where('timestamp', '<=', Carbon::now()->subDays(config('activity.prune_days')));142}143144/**145* Boots the model event listeners. This will trigger an activity log event every146* time a new model is inserted which can then be captured and worked with as needed.147*/148protected static function boot()149{150parent::boot();151152static::created(function (self $model) {153Event::dispatch(new ActivityLogged($model));154});155}156}157158159