Add Laravel Data package, also some small fixes (#1065)

* Simplify

* Update these

* Add Laravel Data

* Remove unused imports

* Quick fix

* Fix double array

* Update app/Console/Commands/Egg/CheckEggUpdatesCommand.php
This commit is contained in:
Lance Pioch 2025-03-08 19:56:06 -05:00 committed by GitHub
parent 05d74232af
commit 0179ade557
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 1587 additions and 398 deletions

View File

@ -34,15 +34,19 @@ class CheckEggUpdatesCommand extends Command
$currentJson = json_decode($exporterService->handle($egg->id)); $currentJson = json_decode($exporterService->handle($egg->id));
unset($currentJson->exported_at); unset($currentJson->exported_at);
$updatedJson = json_decode(file_get_contents($egg->update_url)); $updatedEgg = file_get_contents($egg->update_url);
assert($updatedEgg !== false);
$updatedJson = json_decode($updatedEgg);
unset($updatedJson->exported_at); unset($updatedJson->exported_at);
if (md5(json_encode($currentJson)) === md5(json_encode($updatedJson))) { if (md5(json_encode($currentJson, JSON_THROW_ON_ERROR)) === md5(json_encode($updatedJson, JSON_THROW_ON_ERROR))) {
$this->info("$egg->name: Up-to-date"); $this->info("$egg->name: Up-to-date");
cache()->put("eggs.$egg->uuid.update", false, now()->addHour()); cache()->put("eggs.$egg->uuid.update", false, now()->addHour());
} else {
return;
}
$this->warn("$egg->name: Found update"); $this->warn("$egg->name: Found update");
cache()->put("eggs.$egg->uuid.update", true, now()->addHour()); cache()->put("eggs.$egg->uuid.update", true, now()->addHour());
} }
} }
}

View File

@ -59,12 +59,12 @@ final class AuthentikProvider extends OAuthProvider
public function getName(): string public function getName(): string
{ {
return env('OAUTH_AUTHENTIK_DISPLAY_NAME') ?? 'Authentik'; return env('OAUTH_AUTHENTIK_DISPLAY_NAME', 'Authentik');
} }
public function getHexColor(): string public function getHexColor(): string
{ {
return env('OAUTH_AUTHENTIK_DISPLAY_COLOR') ?? '#fd4b2d'; return env('OAUTH_AUTHENTIK_DISPLAY_COLOR', '#fd4b2d');
} }
public static function register(Application $app): self public static function register(Application $app): self

View File

@ -72,7 +72,7 @@ class ActivityLog extends Model implements HasIcon, HasLabel
protected $with = ['subjects']; protected $with = ['subjects'];
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'event' => ['required', 'string'], 'event' => ['required', 'string'],
'batch' => ['nullable', 'uuid'], 'batch' => ['nullable', 'uuid'],

View File

@ -57,7 +57,7 @@ class Allocation extends Model
*/ */
protected $guarded = ['id', 'created_at', 'updated_at']; protected $guarded = ['id', 'created_at', 'updated_at'];
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'node_id' => ['required', 'exists:nodes,id'], 'node_id' => ['required', 'exists:nodes,id'],
'ip' => ['required', 'ip'], 'ip' => ['required', 'ip'],

View File

@ -110,19 +110,19 @@ class ApiKey extends PersonalAccessToken
*/ */
protected $hidden = ['token']; protected $hidden = ['token'];
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'user_id' => 'required|exists:users,id', 'user_id' => ['required', 'exists:users,id'],
'key_type' => 'present|integer|min:0|max:2', 'key_type' => ['present', 'integer', 'min:0', 'max:2'],
'identifier' => 'required|string|size:16|unique:api_keys,identifier', 'identifier' => ['required', 'string', 'size:16', 'unique:api_keys,identifier'],
'token' => 'required|string', 'token' => ['required', 'string'],
'permissions' => 'array', 'permissions' => ['array'],
'permissions.*' => 'integer|min:0|max:3', 'permissions.*' => ['integer', 'min:0', 'max:3'],
'memo' => 'required|nullable|string|max:500', 'memo' => ['required', 'nullable', 'string', 'max:500'],
'allowed_ips' => 'array', 'allowed_ips' => ['array'],
'allowed_ips.*' => 'string', 'allowed_ips.*' => ['string'],
'last_used_at' => 'nullable|date', 'last_used_at' => ['nullable', 'date'],
'expires_at' => 'nullable|date', 'expires_at' => ['nullable', 'date'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -50,18 +50,18 @@ class Backup extends Model implements Validatable
protected $guarded = ['id', 'created_at', 'updated_at', 'deleted_at']; protected $guarded = ['id', 'created_at', 'updated_at', 'deleted_at'];
/** @var array<string, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'server_id' => 'bail|required|numeric|exists:servers,id', 'server_id' => ['bail', 'required', 'numeric', 'exists:servers,id'],
'uuid' => 'required|uuid', 'uuid' => ['required', 'uuid'],
'is_successful' => 'boolean', 'is_successful' => ['boolean'],
'is_locked' => 'boolean', 'is_locked' => ['boolean'],
'name' => 'required|string', 'name' => ['required', 'string'],
'ignored_files' => 'array', 'ignored_files' => ['array'],
'disk' => 'required|string', 'disk' => ['required', 'string'],
'checksum' => 'nullable|string', 'checksum' => ['nullable', 'string'],
'bytes' => 'numeric', 'bytes' => ['numeric'],
'upload_id' => 'nullable|string', 'upload_id' => ['nullable', 'string'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -50,15 +50,15 @@ class Database extends Model implements Validatable
'server_id', 'database_host_id', 'database', 'username', 'password', 'remote', 'max_connections', 'server_id', 'database_host_id', 'database', 'username', 'password', 'remote', 'max_connections',
]; ];
/** @var array<string, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'server_id' => 'required|numeric|exists:servers,id', 'server_id' => ['required', 'numeric', 'exists:servers,id'],
'database_host_id' => 'required|exists:database_hosts,id', 'database_host_id' => ['required', 'exists:database_hosts,id'],
'database' => 'required|string|alpha_dash|between:3,48', 'database' => ['required', 'string', 'alpha_dash', 'between:3,48'],
'username' => 'string|alpha_dash|between:3,100', 'username' => ['string', 'alpha_dash', 'between:3,100'],
'max_connections' => 'nullable|integer', 'max_connections' => ['nullable', 'integer'],
'remote' => 'required|string|regex:/^[\w\-\/.%:]+$/', 'remote' => ['required', 'string', 'regex:/^[\w\-\/.%:]+$/'],
'password' => 'string', 'password' => ['string'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -48,15 +48,15 @@ class DatabaseHost extends Model implements Validatable
'name', 'host', 'port', 'username', 'password', 'max_databases', 'name', 'host', 'port', 'username', 'password', 'max_databases',
]; ];
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'name' => 'required|string|max:255', 'name' => ['required', 'string', 'max:255'],
'host' => 'required|string', 'host' => ['required', 'string'],
'port' => 'required|numeric|between:1,65535', 'port' => ['required', 'numeric', 'between:1,65535'],
'username' => 'required|string|max:32', 'username' => ['required', 'string', 'max:32'],
'password' => 'nullable|string', 'password' => ['nullable', 'string'],
'node_ids' => 'nullable|array', 'node_ids' => ['nullable', 'array'],
'node_ids.*' => 'required|integer,exists:nodes,id', 'node_ids.*' => ['required', 'integer,exists:nodes,id'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -109,25 +109,25 @@ class Egg extends Model implements Validatable
'tags', 'tags',
]; ];
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'uuid' => 'required|string|size:36', 'uuid' => ['required', 'string', 'size:36'],
'name' => 'required|string|max:255', 'name' => ['required', 'string', 'max:255'],
'description' => 'string|nullable', 'description' => ['string', 'nullable'],
'features' => 'array|nullable', 'features' => ['array', 'nullable'],
'author' => 'required|string|email', 'author' => ['required', 'string', 'email'],
'file_denylist' => 'array|nullable', 'file_denylist' => ['array', 'nullable'],
'file_denylist.*' => 'string', 'file_denylist.*' => ['string'],
'docker_images' => 'required|array|min:1', 'docker_images' => ['required', 'array', 'min:1'],
'docker_images.*' => 'required|string', 'docker_images.*' => ['required', 'string'],
'startup' => 'required|nullable|string', 'startup' => ['required', 'nullable', 'string'],
'config_from' => 'sometimes|bail|nullable|numeric|exists:eggs,id', 'config_from' => ['sometimes', 'bail', 'nullable', 'numeric', 'exists:eggs,id'],
'config_stop' => 'required_without:config_from|nullable|string|max:255', 'config_stop' => ['required_without:config_from', 'nullable', 'string', 'max:255'],
'config_startup' => 'required_without:config_from|nullable|json', 'config_startup' => ['required_without:config_from', 'nullable', 'json'],
'config_logs' => 'required_without:config_from|nullable|json', 'config_logs' => ['required_without:config_from', 'nullable', 'json'],
'config_files' => 'required_without:config_from|nullable|json', 'config_files' => ['required_without:config_from', 'nullable', 'json'],
'update_url' => 'sometimes|nullable|string', 'update_url' => ['sometimes', 'nullable', 'string'],
'force_outgoing_ip' => 'sometimes|boolean', 'force_outgoing_ip' => ['sometimes', 'boolean'],
]; ];
protected $attributes = [ protected $attributes = [

View File

@ -51,18 +51,18 @@ class EggVariable extends Model implements Validatable
*/ */
protected $guarded = ['id', 'created_at', 'updated_at']; protected $guarded = ['id', 'created_at', 'updated_at'];
/** @var array<string, string|string[]> */ /** @var array<string, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'egg_id' => 'exists:eggs,id', 'egg_id' => ['exists:eggs,id'],
'sort' => 'nullable', 'sort' => ['nullable'],
'name' => 'required|string|between:1,255', 'name' => ['required', 'string', 'between:1,255'],
'description' => 'string', 'description' => ['string'],
'env_variable' => 'required|alphaDash|between:1,255|notIn:' . self::RESERVED_ENV_NAMES, 'env_variable' => ['required', 'alphaDash', 'between:1,255', 'notIn:' . self::RESERVED_ENV_NAMES],
'default_value' => 'string', 'default_value' => ['string'],
'user_viewable' => 'boolean', 'user_viewable' => ['boolean'],
'user_editable' => 'boolean', 'user_editable' => ['boolean'],
'rules' => 'array', 'rules' => ['array'],
'rules.*' => 'string', 'rules.*' => ['string'],
]; ];
protected $attributes = [ protected $attributes = [

View File

@ -5,7 +5,6 @@ namespace App\Models;
use App\Contracts\Validatable; use App\Contracts\Validatable;
use App\Traits\HasValidation; use App\Traits\HasValidation;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Validation\Rules\NotIn;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
/** /**
@ -41,28 +40,27 @@ class Mount extends Model implements Validatable
/** /**
* Rules verifying that the data being stored matches the expectations of the database. * Rules verifying that the data being stored matches the expectations of the database.
* *
* @var array<array-key, string|array<array-key, string>> * @var array<array-key, string[]>
*/ */
public static array $validationRules = [ public static array $validationRules = [
'name' => 'required|string|min:2|max:64|unique:mounts,name', 'name' => ['required', 'string', 'min:2', 'max:64', 'unique:mounts,name'],
'description' => 'nullable|string|max:255', 'description' => ['nullable', 'string', 'max:255'],
'source' => 'required|string', 'source' => ['required', 'string'],
'target' => 'required|string', 'target' => ['required', 'string'],
'read_only' => 'sometimes|boolean', 'read_only' => ['sometimes', 'boolean'],
'user_mountable' => 'sometimes|boolean', 'user_mountable' => ['sometimes', 'boolean'],
]; ];
/** /**
* Implement language verification by overriding Eloquence's gather rules function. * Implement language verification by overriding Eloquence's gather rules function.
* *
* @return array<string|string[]> * @return array<array-key, string[]>
*/ */
public static function getRules(): array public static function getRules(): array
{ {
$rules = self::getValidationRules(); $rules = self::getValidationRules();
$rules['source'][] = 'not_in:' . implode(',', Mount::$invalidSourcePaths);
$rules['source'][] = new NotIn(Mount::$invalidSourcePaths); $rules['target'][] = 'not_in:' . implode(',', Mount::$invalidTargetPaths);
$rules['target'][] = new NotIn(Mount::$invalidTargetPaths);
return $rules; return $rules;
} }

View File

@ -13,7 +13,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Symfony\Component\Yaml\Yaml; use Symfony\Component\Yaml\Yaml;
@ -85,26 +84,26 @@ class Node extends Model implements Validatable
'description', 'maintenance_mode', 'tags', 'description', 'maintenance_mode', 'tags',
]; ];
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'name' => 'required|string|min:1|max:100', 'name' => ['required', 'string', 'min:1', 'max:100'],
'description' => 'string|nullable', 'description' => ['string', 'nullable'],
'public' => 'boolean', 'public' => ['boolean'],
'fqdn' => 'required|string', 'fqdn' => ['required', 'string'],
'scheme' => 'required|string|in:http,https', 'scheme' => ['required', 'string', 'in:http,https'],
'behind_proxy' => 'boolean', 'behind_proxy' => ['boolean'],
'memory' => 'required|numeric|min:0', 'memory' => ['required', 'numeric', 'min:0'],
'memory_overallocate' => 'required|numeric|min:-1', 'memory_overallocate' => ['required', 'numeric', 'min:-1'],
'disk' => 'required|numeric|min:0', 'disk' => ['required', 'numeric', 'min:0'],
'disk_overallocate' => 'required|numeric|min:-1', 'disk_overallocate' => ['required', 'numeric', 'min:-1'],
'cpu' => 'required|numeric|min:0', 'cpu' => ['required', 'numeric', 'min:0'],
'cpu_overallocate' => 'required|numeric|min:-1', 'cpu_overallocate' => ['required', 'numeric', 'min:-1'],
'daemon_base' => 'sometimes|required|regex:/^([\/][\d\w.\-\/]+)$/', 'daemon_base' => ['sometimes', 'required', 'regex:/^([\/][\d\w.\-\/]+)$/'],
'daemon_sftp' => 'required|numeric|between:1,65535', 'daemon_sftp' => ['required', 'numeric', 'between:1,65535'],
'daemon_sftp_alias' => 'nullable|string', 'daemon_sftp_alias' => ['nullable', 'string'],
'daemon_listen' => 'required|numeric|between:1,65535', 'daemon_listen' => ['required', 'numeric', 'between:1,65535'],
'maintenance_mode' => 'boolean', 'maintenance_mode' => ['boolean'],
'upload_size' => 'int|between:1,1024', 'upload_size' => ['int', 'between:1,1024'],
]; ];
/** /**
@ -297,28 +296,6 @@ class Node extends Model implements Validatable
return true; return true;
} }
public static function getForServerCreation(): Collection
{
return self::with('allocations')->get()->map(function (Node $item) {
$filtered = $item->getRelation('allocations')->where('server_id', null)->map(function ($map) {
return collect($map)->only(['id', 'ip', 'port']);
});
$ports = $filtered->map(function ($map) {
return [
'id' => $map['id'],
'text' => sprintf('%s:%s', $map['ip'], $map['port']),
];
})->values();
return [
'id' => $item->id,
'text' => $item->name,
'allocations' => $ports,
];
})->values();
}
/** @return array<mixed> */ /** @return array<mixed> */
public function systemInformation(): array public function systemInformation(): array
{ {

View File

@ -107,10 +107,10 @@ class Permission extends Model implements Validatable
*/ */
protected $guarded = ['id', 'created_at', 'updated_at']; protected $guarded = ['id', 'created_at', 'updated_at'];
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'subuser_id' => 'required|numeric|min:1', 'subuser_id' => ['required', 'numeric', 'min:1'],
'permission' => 'required|string', 'permission' => ['required', 'string'],
]; ];
/** /**

View File

@ -25,9 +25,9 @@ class RecoveryToken extends Model implements Validatable
public $timestamps = true; public $timestamps = true;
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'token' => 'required|string', 'token' => ['required', 'string'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -75,20 +75,20 @@ class Schedule extends Model implements Validatable
'only_when_online' => false, 'only_when_online' => false,
]; ];
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'server_id' => 'required|exists:servers,id', 'server_id' => ['required', 'exists:servers,id'],
'name' => 'required|string|max:255', 'name' => ['required', 'string', 'max:255'],
'cron_day_of_week' => 'required|string', 'cron_day_of_week' => ['required', 'string'],
'cron_month' => 'required|string', 'cron_month' => ['required', 'string'],
'cron_day_of_month' => 'required|string', 'cron_day_of_month' => ['required', 'string'],
'cron_hour' => 'required|string', 'cron_hour' => ['required', 'string'],
'cron_minute' => 'required|string', 'cron_minute' => ['required', 'string'],
'is_active' => 'boolean', 'is_active' => ['boolean'],
'is_processing' => 'boolean', 'is_processing' => ['boolean'],
'only_when_online' => 'boolean', 'only_when_online' => ['boolean'],
'last_run_at' => 'nullable|date', 'last_run_at' => ['nullable', 'date'],
'next_run_at' => 'nullable|date', 'next_run_at' => ['nullable', 'date'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -157,29 +157,29 @@ class Server extends Model implements Validatable
*/ */
protected $guarded = ['id', self::CREATED_AT, self::UPDATED_AT, 'deleted_at', 'installed_at']; protected $guarded = ['id', self::CREATED_AT, self::UPDATED_AT, 'deleted_at', 'installed_at'];
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'external_id' => 'sometimes|nullable|string|between:1,255|unique:servers', 'external_id' => ['sometimes', 'nullable', 'string', 'between:1,255', 'unique:servers'],
'owner_id' => 'required|integer|exists:users,id', 'owner_id' => ['required', 'integer', 'exists:users,id'],
'name' => 'required|string|min:1|max:255', 'name' => ['required', 'string', 'min:1', 'max:255'],
'node_id' => 'required|exists:nodes,id', 'node_id' => ['required', 'exists:nodes,id'],
'description' => 'string', 'description' => ['string'],
'status' => 'nullable|string', 'status' => ['nullable', 'string'],
'memory' => 'required|numeric|min:0', 'memory' => ['required', 'numeric', 'min:0'],
'swap' => 'required|numeric|min:-1', 'swap' => ['required', 'numeric', 'min:-1'],
'io' => 'required|numeric|between:0,1000', 'io' => ['required', 'numeric', 'between:0,1000'],
'cpu' => 'required|numeric|min:0', 'cpu' => ['required', 'numeric', 'min:0'],
'threads' => 'nullable|regex:/^[0-9-,]+$/', 'threads' => ['nullable', 'regex:/^[0-9-,]+$/'],
'oom_killer' => 'sometimes|boolean', 'oom_killer' => ['sometimes', 'boolean'],
'disk' => 'required|numeric|min:0', 'disk' => ['required', 'numeric', 'min:0'],
'allocation_id' => 'required|bail|unique:servers|exists:allocations,id', 'allocation_id' => ['required', 'bail', 'unique:servers', 'exists:allocations,id'],
'egg_id' => 'required|exists:eggs,id', 'egg_id' => ['required', 'exists:eggs,id'],
'startup' => 'required|string', 'startup' => ['required', 'string'],
'skip_scripts' => 'sometimes|boolean', 'skip_scripts' => ['sometimes', 'boolean'],
'image' => 'required|string|max:255', 'image' => ['required', 'string', 'max:255'],
'database_limit' => 'present|nullable|integer|min:0', 'database_limit' => ['present', 'nullable', 'integer', 'min:0'],
'allocation_limit' => 'sometimes|nullable|integer|min:0', 'allocation_limit' => ['sometimes', 'nullable', 'integer', 'min:0'],
'backup_limit' => 'present|nullable|integer|min:0', 'backup_limit' => ['present', 'nullable', 'integer', 'min:0'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -40,18 +40,18 @@ class ServerTransfer extends Model implements Validatable
*/ */
protected $guarded = ['id', 'created_at', 'updated_at']; protected $guarded = ['id', 'created_at', 'updated_at'];
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'server_id' => 'required|numeric|exists:servers,id', 'server_id' => ['required', 'numeric', 'exists:servers,id'],
'old_node' => 'required|numeric', 'old_node' => ['required', 'numeric'],
'new_node' => 'required|numeric', 'new_node' => ['required', 'numeric'],
'old_allocation' => 'required|numeric', 'old_allocation' => ['required', 'numeric'],
'new_allocation' => 'required|numeric', 'new_allocation' => ['required', 'numeric'],
'old_additional_allocations' => 'nullable|array', 'old_additional_allocations' => ['nullable', 'array'],
'old_additional_allocations.*' => 'numeric', 'old_additional_allocations.*' => ['numeric'],
'new_additional_allocations' => 'nullable|array', 'new_additional_allocations' => ['nullable', 'array'],
'new_additional_allocations.*' => 'numeric', 'new_additional_allocations.*' => ['numeric'],
'successful' => 'sometimes|nullable|boolean', 'successful' => ['sometimes', 'nullable', 'boolean'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -29,11 +29,11 @@ class ServerVariable extends Model implements Validatable
protected $guarded = ['id', 'created_at', 'updated_at']; protected $guarded = ['id', 'created_at', 'updated_at'];
/** @var array<string, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'server_id' => 'required|int', 'server_id' => ['required', 'int'],
'variable_id' => 'required|int', 'variable_id' => ['required', 'int'],
'variable_value' => 'string', 'variable_value' => ['string'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -37,12 +37,12 @@ class Subuser extends Model implements Validatable
*/ */
protected $guarded = ['id', 'created_at', 'updated_at']; protected $guarded = ['id', 'created_at', 'updated_at'];
/** @var array<string, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'user_id' => 'required|numeric|exists:users,id', 'user_id' => ['required', 'numeric', 'exists:users,id'],
'server_id' => 'required|numeric|exists:servers,id', 'server_id' => ['required', 'numeric', 'exists:servers,id'],
'permissions' => 'nullable|array', 'permissions' => ['nullable', 'array'],
'permissions.*' => 'string', 'permissions.*' => ['string'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -74,15 +74,15 @@ class Task extends Model implements Validatable
'continue_on_failure' => false, 'continue_on_failure' => false,
]; ];
/** @var array<string, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'schedule_id' => 'required|numeric|exists:schedules,id', 'schedule_id' => ['required', 'numeric', 'exists:schedules,id'],
'sequence_id' => 'required|numeric|min:1', 'sequence_id' => ['required', 'numeric', 'min:1'],
'action' => 'required|string', 'action' => ['required', 'string'],
'payload' => 'required_unless:action,backup|string', 'payload' => ['required_unless:action,backup', 'string'],
'time_offset' => 'required|numeric|between:0,900', 'time_offset' => ['required', 'numeric', 'between:0,900'],
'is_queued' => 'boolean', 'is_queued' => ['boolean'],
'continue_on_failure' => 'boolean', 'continue_on_failure' => ['boolean'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -145,18 +145,18 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
'oauth' => '[]', 'oauth' => '[]',
]; ];
/** @var array<array-key, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'uuid' => 'nullable|string|size:36|unique:users,uuid', 'uuid' => ['nullable', 'string', 'size:36', 'unique:users,uuid'],
'email' => 'required|email|between:1,255|unique:users,email', 'email' => ['required', 'email', 'between:1,255', 'unique:users,email'],
'external_id' => 'sometimes|nullable|string|max:255|unique:users,external_id', 'external_id' => ['sometimes', 'nullable', 'string', 'max:255', 'unique:users,external_id'],
'username' => 'required|between:1,255|unique:users,username', 'username' => ['required', 'between:1,255', 'unique:users,username'],
'password' => 'sometimes|nullable|string', 'password' => ['sometimes', 'nullable', 'string'],
'language' => 'string', 'language' => ['string'],
'timezone' => 'string', 'timezone' => ['string'],
'use_totp' => 'boolean', 'use_totp' => ['boolean'],
'totp_secret' => 'nullable|string', 'totp_secret' => ['nullable', 'string'],
'oauth' => 'array|nullable', 'oauth' => ['array', 'nullable'],
]; ];
protected function casts(): array protected function casts(): array

View File

@ -53,7 +53,7 @@ class UserSSHKey extends Model
'fingerprint', 'fingerprint',
]; ];
/** @var array<string, string|string[]> */ /** @var array<array-key, string[]> */
public static array $validationRules = [ public static array $validationRules = [
'name' => ['required', 'string'], 'name' => ['required', 'string'],
'fingerprint' => ['required', 'string'], 'fingerprint' => ['required', 'string'],

View File

@ -12,7 +12,7 @@ class StartupCommandService
public function handle(Server $server, bool $hideAllValues = false): string public function handle(Server $server, bool $hideAllValues = false): string
{ {
$find = ['{{SERVER_MEMORY}}', '{{SERVER_IP}}', '{{SERVER_PORT}}']; $find = ['{{SERVER_MEMORY}}', '{{SERVER_IP}}', '{{SERVER_PORT}}'];
$replace = [$server->memory, $server->allocation->ip, $server->allocation->port]; $replace = [(string) $server->memory, $server->allocation->ip, (string) $server->allocation->port];
foreach ($server->variables as $variable) { foreach ($server->variables as $variable) {
$find[] = '{{' . $variable->env_variable . '}}'; $find[] = '{{' . $variable->env_variable . '}}';

View File

@ -77,8 +77,7 @@ class StartupModificationService
$eggId = Arr::get($data, 'egg_id'); $eggId = Arr::get($data, 'egg_id');
if (is_digit($eggId) && $server->egg_id !== (int) $eggId) { if (is_digit($eggId) && $server->egg_id !== (int) $eggId) {
/** @var \App\Models\Egg $egg */ $egg = Egg::findOrFail($data['egg_id']);
$egg = Egg::query()->findOrFail($data['egg_id']);
$server = $server->forceFill([ $server = $server->forceFill([
'egg_id' => $egg->id, 'egg_id' => $egg->id,

View File

@ -42,7 +42,8 @@ class SubuserCreationService
if (!$user) { if (!$user) {
// Just cap the username generated at 64 characters at most and then append a random string // Just cap the username generated at 64 characters at most and then append a random string
// to the end to make it "unique"... // to the end to make it "unique"...
$username = substr(preg_replace('/([^\w\.-]+)/', '', strtok($email, '@')), 0, 64) . Str::random(3); [$beforeDomain] = explode('@', $email, 1);
$username = substr(preg_replace('/([^\w.-]+)/', '', $beforeDomain), 0, 64) . Str::random(3);
$user = $this->userCreationService->handle([ $user = $this->userCreationService->handle([
'email' => $email, 'email' => $email,

View File

@ -35,6 +35,10 @@ trait EnvironmentWriterTrait
} }
$saveContents = file_get_contents($path); $saveContents = file_get_contents($path);
if ($saveContents === false) {
$saveContents = '';
}
collect($values)->each(function ($value, $key) use (&$saveContents) { collect($values)->each(function ($value, $key) use (&$saveContents) {
$key = strtoupper($key); $key = strtoupper($key);
$saveValue = sprintf('%s=%s', $key, $this->escapeEnvironmentValue($value ?? '')); $saveValue = sprintf('%s=%s', $key, $this->escapeEnvironmentValue($value ?? ''));

View File

@ -32,16 +32,11 @@ trait HasValidation
/** /**
* Returns the rules associated with this model. * Returns the rules associated with this model.
* *
* @return array<array-key, string|ValidationRule|array<array-key, string|ValidationRule>> * @return array<array-key, string[]>
*/ */
public static function getRules(): array public static function getRules(): array
{ {
$rules = static::$validationRules; return static::$validationRules;
foreach ($rules as &$rule) {
$rule = is_array($rule) ? $rule : explode('|', $rule);
}
return $rules;
} }
/** /**

View File

@ -34,6 +34,7 @@
"socialiteproviders/authentik": "^5.2", "socialiteproviders/authentik": "^5.2",
"socialiteproviders/discord": "^4.2", "socialiteproviders/discord": "^4.2",
"socialiteproviders/steam": "^4.3", "socialiteproviders/steam": "^4.3",
"spatie/laravel-data": "^4.13",
"spatie/laravel-fractal": "^6.3", "spatie/laravel-fractal": "^6.3",
"spatie/laravel-health": "^1.32", "spatie/laravel-health": "^1.32",
"spatie/laravel-permission": "^6.16", "spatie/laravel-permission": "^6.16",

1562
composer.lock generated

File diff suppressed because it is too large Load Diff