<?php12namespace Pterodactyl\Models;34use Illuminate\Database\Eloquent\Relations\HasMany;5use Illuminate\Database\Eloquent\Relations\BelongsTo;6use Illuminate\Database\Eloquent\Factories\HasFactory;78/**9* @property int $id10* @property string $uuid11* @property int $nest_id12* @property string $author13* @property string $name14* @property string|null $description15* @property array|null $features16* @property string $docker_image -- deprecated, use $docker_images17* @property array<string, string> $docker_images18* @property string $update_url19* @property bool $force_outgoing_ip20* @property array|null $file_denylist21* @property string|null $config_files22* @property string|null $config_startup23* @property string|null $config_logs24* @property string|null $config_stop25* @property int|null $config_from26* @property string|null $startup27* @property bool $script_is_privileged28* @property string|null $script_install29* @property string $script_entry30* @property string $script_container31* @property int|null $copy_script_from32* @property \Carbon\Carbon $created_at33* @property \Carbon\Carbon $updated_at34* @property string|null $copy_script_install35* @property string $copy_script_entry36* @property string $copy_script_container37* @property string|null $inherit_config_files38* @property string|null $inherit_config_startup39* @property string|null $inherit_config_logs40* @property string|null $inherit_config_stop41* @property string $inherit_file_denylist42* @property array|null $inherit_features43* @property Nest $nest44* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Server[] $servers45* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\EggVariable[] $variables46* @property Egg|null $scriptFrom47* @property Egg|null $configFrom48*/49class Egg extends Model50{51/** @use HasFactory<\Database\Factories\EggFactory> */52use HasFactory;5354/**55* The resource name for this model when it is transformed into an56* API representation using fractal.57*/58public const RESOURCE_NAME = 'egg';5960/**61* Defines the current egg export version.62*/63public const EXPORT_VERSION = 'PTDL_v2';6465/**66* Different features that can be enabled on any given egg. These are used internally67* to determine which types of frontend functionality should be shown to the user. Eggs68* will automatically inherit features from a parent egg if they are already configured69* to copy configuration values from said egg.70*71* To skip copying the features, an empty array value should be passed in ("[]") rather72* than leaving it null.73*/74public const FEATURE_EULA_POPUP = 'eula';75public const FEATURE_FASTDL = 'fastdl';7677/**78* The table associated with the model.79*/80protected $table = 'eggs';8182/**83* Fields that are not mass assignable.84*/85protected $fillable = [86'name',87'description',88'features',89'docker_images',90'force_outgoing_ip',91'file_denylist',92'config_files',93'config_startup',94'config_logs',95'config_stop',96'config_from',97'startup',98'script_is_privileged',99'script_install',100'script_entry',101'script_container',102'copy_script_from',103];104105/**106* Cast values to correct type.107*/108protected $casts = [109'nest_id' => 'integer',110'config_from' => 'integer',111'script_is_privileged' => 'boolean',112'force_outgoing_ip' => 'boolean',113'copy_script_from' => 'integer',114'features' => 'array',115'docker_images' => 'array',116'file_denylist' => 'array',117];118119public static array $validationRules = [120'nest_id' => 'required|bail|numeric|exists:nests,id',121'uuid' => 'required|string|size:36',122'name' => 'required|string|max:191',123'description' => 'string|nullable',124'features' => 'array|nullable',125'author' => 'required|string|email',126'file_denylist' => 'array|nullable',127'file_denylist.*' => 'string',128'docker_images' => 'required|array|min:1',129'docker_images.*' => ['required', 'string', 'max:191', 'regex:/^[\w#\.\/\- ]*\|?~?[\w\.\/\-:@ ]*$/'],130'startup' => 'required|nullable|string',131'config_from' => 'sometimes|bail|nullable|numeric|exists:eggs,id',132'config_stop' => 'required_without:config_from|nullable|string|max:191',133'config_startup' => 'required_without:config_from|nullable|json',134'config_logs' => 'required_without:config_from|nullable|json',135'config_files' => 'required_without:config_from|nullable|json',136'update_url' => 'sometimes|nullable|string',137'force_outgoing_ip' => 'sometimes|boolean',138];139140protected $attributes = [141'features' => null,142'file_denylist' => null,143'config_stop' => null,144'config_startup' => null,145'config_logs' => null,146'config_files' => null,147'update_url' => null,148];149150/**151* Returns the install script for the egg; if egg is copying from another152* it will return the copied script.153*/154public function getCopyScriptInstallAttribute(): ?string155{156if (!is_null($this->script_install) || is_null($this->copy_script_from)) {157return $this->script_install;158}159160return $this->scriptFrom->script_install;161}162163/**164* Returns the entry command for the egg; if egg is copying from another165* it will return the copied entry command.166*/167public function getCopyScriptEntryAttribute(): string168{169if (!is_null($this->script_entry) || is_null($this->copy_script_from)) {170return $this->script_entry;171}172173return $this->scriptFrom->script_entry;174}175176/**177* Returns the install container for the egg; if egg is copying from another178* it will return the copied install container.179*/180public function getCopyScriptContainerAttribute(): string181{182if (!is_null($this->script_container) || is_null($this->copy_script_from)) {183return $this->script_container;184}185186return $this->scriptFrom->script_container;187}188189/**190* Return the file configuration for an egg.191*/192public function getInheritConfigFilesAttribute(): ?string193{194if (!is_null($this->config_files) || is_null($this->config_from)) {195return $this->config_files;196}197198return $this->configFrom->config_files;199}200201/**202* Return the startup configuration for an egg.203*/204public function getInheritConfigStartupAttribute(): ?string205{206if (!is_null($this->config_startup) || is_null($this->config_from)) {207return $this->config_startup;208}209210return $this->configFrom->config_startup;211}212213/**214* Return the log reading configuration for an egg.215*/216public function getInheritConfigLogsAttribute(): ?string217{218if (!is_null($this->config_logs) || is_null($this->config_from)) {219return $this->config_logs;220}221222return $this->configFrom->config_logs;223}224225/**226* Return the stop command configuration for an egg.227*/228public function getInheritConfigStopAttribute(): ?string229{230if (!is_null($this->config_stop) || is_null($this->config_from)) {231return $this->config_stop;232}233234return $this->configFrom->config_stop;235}236237/**238* Returns the features available to this egg from the parent configuration if there are239* no features defined for this egg specifically and there is a parent egg configured.240*/241public function getInheritFeaturesAttribute(): ?array242{243if (!is_null($this->features) || is_null($this->config_from)) {244return $this->features;245}246247return $this->configFrom->features;248}249250/**251* Returns the features available to this egg from the parent configuration if there are252* no features defined for this egg specifically and there is a parent egg configured.253*/254public function getInheritFileDenylistAttribute(): ?array255{256if (is_null($this->config_from)) {257return $this->file_denylist;258}259260return $this->configFrom->file_denylist;261}262263/**264* Gets nest associated with an egg.265*/266public function nest(): BelongsTo267{268return $this->belongsTo(Nest::class);269}270271/**272* Gets all servers associated with this egg.273*/274public function servers(): HasMany275{276return $this->hasMany(Server::class, 'egg_id');277}278279/**280* Gets all variables associated with this egg.281*/282public function variables(): HasMany283{284return $this->hasMany(EggVariable::class, 'egg_id');285}286287/**288* Get the parent egg from which to copy scripts.289*/290public function scriptFrom(): BelongsTo291{292return $this->belongsTo(self::class, 'copy_script_from');293}294295/**296* Get the parent egg from which to copy configuration settings.297*/298public function configFrom(): BelongsTo299{300return $this->belongsTo(self::class, 'config_from');301}302}303304305