mirror of
https://github.com/pterodactyl/panel.git
synced 2026-04-13 02:25:38 -05:00
This is a partial implementation to begin moving towards stripe-style identifiers for resources in the system. Any models with an existing `uuid` column can easily be updated to return an identifier in the format of `prfx_xyz` where `prfx` is a four character prefix, and `xyz` is the UUID, encoded using base-32. These are quite easy to use within the API layer because we just need to do one quick transformation to extract the UUID for those models. This PR implements that logic for servers in the `SubstituteClientBindings` logic. A future PR will need to come through and handle identifiers for models that _don't_ currently use UUIDs for reference that we want to expose to clients. In those cases it is easier to just generate base-32 encoded UUID7s that get stored in the database and indexed. They follow the same base approach, but you don't need to do any transformations in the code (other than stripping the prefix, unless we decide to store the prefix). There is also now a `PTERODACTYL_USE_SERVER_IDENTIFIERS` environment variable, that when set to true, updates the front-end and API response to use this new identifier in place of the `uuidShort` value.
158 lines
5.0 KiB
PHP
158 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace Pterodactyl\Models;
|
|
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Facades\Event;
|
|
use Pterodactyl\Events\ActivityLogged;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Database\Eloquent\MassPrunable;
|
|
use Pterodactyl\Contracts\Models\Identifiable;
|
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
|
use Pterodactyl\Models\Traits\HasRealtimeIdentifier;
|
|
use Illuminate\Database\Eloquent\Model as IlluminateModel;
|
|
|
|
/**
|
|
* \Pterodactyl\Models\ActivityLog.
|
|
*
|
|
* @property int $id
|
|
* @property string|null $batch
|
|
* @property string $event
|
|
* @property string $ip
|
|
* @property string|null $description
|
|
* @property string|null $actor_type
|
|
* @property int|null $actor_id
|
|
* @property int|null $api_key_id
|
|
* @property \Illuminate\Support\Collection|null $properties
|
|
* @property Carbon $timestamp
|
|
* @property IlluminateModel|\Eloquent $actor
|
|
* @property \Illuminate\Database\Eloquent\Collection<int, \Pterodactyl\Models\ActivityLogSubject> $subjects
|
|
* @property int|null $subjects_count
|
|
* @property ApiKey|null $apiKey
|
|
*
|
|
* @method static Builder|ActivityLog forActor(\Illuminate\Database\Eloquent\Model $actor)
|
|
* @method static Builder|ActivityLog forEvent(string $action)
|
|
* @method static Builder|ActivityLog newModelQuery()
|
|
* @method static Builder|ActivityLog newQuery()
|
|
* @method static Builder|ActivityLog query()
|
|
* @method static Builder|ActivityLog whereActorId($value)
|
|
* @method static Builder|ActivityLog whereActorType($value)
|
|
* @method static Builder|ActivityLog whereApiKeyId($value)
|
|
* @method static Builder|ActivityLog whereBatch($value)
|
|
* @method static Builder|ActivityLog whereDescription($value)
|
|
* @method static Builder|ActivityLog whereEvent($value)
|
|
* @method static Builder|ActivityLog whereId($value)
|
|
* @method static Builder|ActivityLog whereIp($value)
|
|
* @method static Builder|ActivityLog whereProperties($value)
|
|
* @method static Builder|ActivityLog whereTimestamp($value)
|
|
*
|
|
* @mixin \Eloquent
|
|
*/
|
|
#[Attributes\Identifiable('actl')]
|
|
class ActivityLog extends Model implements Identifiable
|
|
{
|
|
use MassPrunable;
|
|
use HasRealtimeIdentifier;
|
|
|
|
public const RESOURCE_NAME = 'activity_log';
|
|
|
|
/**
|
|
* Tracks all the events we no longer wish to display to users. These are either legacy
|
|
* events or just events where we never ended up using the associated data.
|
|
*/
|
|
public const DISABLED_EVENTS = ['server:file.upload'];
|
|
|
|
public $timestamps = false;
|
|
|
|
protected $guarded = [
|
|
'id',
|
|
'timestamp',
|
|
];
|
|
|
|
protected $casts = [
|
|
'properties' => 'collection',
|
|
'timestamp' => 'datetime',
|
|
];
|
|
|
|
protected $with = ['subjects'];
|
|
|
|
public static array $validationRules = [
|
|
'event' => ['required', 'string'],
|
|
'batch' => ['nullable', 'uuid'],
|
|
'ip' => ['required', 'string'],
|
|
'description' => ['nullable', 'string'],
|
|
'properties' => ['array'],
|
|
];
|
|
|
|
/**
|
|
* @return \Illuminate\Database\Eloquent\Relations\MorphTo<\Illuminate\Database\Eloquent\Model, $this>
|
|
*/
|
|
public function actor(): MorphTo
|
|
{
|
|
$morph = $this->morphTo();
|
|
if (method_exists($morph, 'withTrashed')) { // @phpstan-ignore function.alreadyNarrowedType
|
|
return $morph->withTrashed();
|
|
}
|
|
|
|
return $morph;
|
|
}
|
|
|
|
/**
|
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\Pterodactyl\Models\ActivityLogSubject, $this>
|
|
*/
|
|
public function subjects(): HasMany
|
|
{
|
|
return $this->hasMany(ActivityLogSubject::class);
|
|
}
|
|
|
|
/**
|
|
* @return \Illuminate\Database\Eloquent\Relations\HasOne<\Pterodactyl\Models\ApiKey, $this>
|
|
*/
|
|
public function apiKey(): HasOne
|
|
{
|
|
return $this->hasOne(ApiKey::class, 'id', 'api_key_id');
|
|
}
|
|
|
|
public function scopeForEvent(Builder $builder, string $action): Builder
|
|
{
|
|
return $builder->where('event', $action);
|
|
}
|
|
|
|
/**
|
|
* Scopes a query to only return results where the actor is a given model.
|
|
*/
|
|
public function scopeForActor(Builder $builder, IlluminateModel $actor): Builder
|
|
{
|
|
return $builder->whereMorphedTo('actor', $actor);
|
|
}
|
|
|
|
/**
|
|
* Returns models to be pruned.
|
|
*
|
|
* @see https://laravel.com/docs/9.x/eloquent#pruning-models
|
|
*/
|
|
public function prunable()
|
|
{
|
|
if (is_null(config('activity.prune_days'))) {
|
|
throw new \LogicException('Cannot prune activity logs: no "prune_days" configuration value is set.');
|
|
}
|
|
|
|
return static::where('timestamp', '<=', Carbon::now()->subDays(config('activity.prune_days')));
|
|
}
|
|
|
|
/**
|
|
* Boots the model event listeners. This will trigger an activity log event every
|
|
* time a new model is inserted which can then be captured and worked with as needed.
|
|
*/
|
|
protected static function boot()
|
|
{
|
|
parent::boot();
|
|
|
|
static::created(function (self $model) {
|
|
Event::dispatch(new ActivityLogged($model));
|
|
});
|
|
}
|
|
}
|