diff --git a/app/Data/Api/ApiResource.php b/app/Data/Api/ApiResource.php new file mode 100644 index 0000000000..e6166a8452 --- /dev/null +++ b/app/Data/Api/ApiResource.php @@ -0,0 +1,61 @@ +> + */ + public static function includes(): array + { + return []; + } + + /** + * Return an ISO-8601 formatted timestamp to use in the API response. + */ + protected static function formatTimestamp(string $timestamp): string + { + return CarbonImmutable::createFromFormat(CarbonInterface::DEFAULT_TO_STRING_FORMAT, $timestamp) + ->setTimezone(self::RESPONSE_TIMEZONE) + ->toAtomString(); + } +} diff --git a/app/Data/Api/Application/AllocationData.php b/app/Data/Api/Application/AllocationData.php new file mode 100644 index 0000000000..9e008c24f4 --- /dev/null +++ b/app/Data/Api/Application/AllocationData.php @@ -0,0 +1,61 @@ +id, + ip: $model->ip, + alias: $model->ip_alias, + port: $model->port, + notes: $model->notes, + assigned: !is_null($model->server_id), + ); + } + + public static function includes(): array + { + return [ + 'node' => function (Allocation $allocation, IncludeContext $context): array { + if (!$context->allowsAdmin(Node::RESOURCE_NAME)) { + return $context->null(); + } + + return $context->item($allocation->node, NodeData::class); + }, + 'server' => function (Allocation $allocation, IncludeContext $context): array { + if (!$context->allowsAdmin(Server::RESOURCE_NAME) || !$allocation->server) { + return $context->null(); + } + + return $context->item($allocation->server, ServerData::class); + }, + ]; + } +} diff --git a/app/Data/Api/Application/DatabaseHostData.php b/app/Data/Api/Application/DatabaseHostData.php new file mode 100644 index 0000000000..5c6cda45ea --- /dev/null +++ b/app/Data/Api/Application/DatabaseHostData.php @@ -0,0 +1,70 @@ +id, + name: $model->name, + host: $model->host, + port: $model->port, + username: $model->username, + created_at: $model->created_at->toAtomString(), + updated_at: $model->updated_at->toAtomString(), + ); + } + + public static function includes(): array + { + return [ + 'databases' => function (DatabaseHost $host, IncludeContext $context): array { + if (!$context->allowsAdmin(Database::RESOURCE_NAME)) { + return $context->null(); + } + + $host->loadMissing('databases'); + + return $context->collection($host->getRelation('databases'), ServerDatabaseData::class); + }, + 'nodes' => function (DatabaseHost $host, IncludeContext $context): array { + if (!$context->allowsAdmin(Node::RESOURCE_NAME)) { + return $context->null(); + } + + $host->loadMissing('nodes'); + + return $context->collection($host->getRelation('nodes'), NodeData::class); + }, + ]; + } +} diff --git a/app/Data/Api/Application/EggData.php b/app/Data/Api/Application/EggData.php new file mode 100644 index 0000000000..432673ccdc --- /dev/null +++ b/app/Data/Api/Application/EggData.php @@ -0,0 +1,112 @@ + $config + * @param array $script + */ + public function __construct( + public int $id, + public string $uuid, + public string $name, + public ?string $author, + public ?string $description, + public ?string $icon, + public mixed $features, + public mixed $tags, + public string $docker_image, + public mixed $docker_images, + public array $config, + public string $startup, + public mixed $startup_commands, + public array $script, + public string $created_at, + public string $updated_at, + ) {} + + public static function getResourceName(): string + { + return Egg::RESOURCE_NAME; + } + + public static function fromModel(Egg $model): static + { + $model->loadMissing('configFrom'); + + $files = json_decode($model->inherit_config_files ?: '{}', true, 512, JSON_THROW_ON_ERROR); + + $model->loadMissing('scriptFrom'); + + return new self( + id: $model->id, + uuid: $model->uuid, + name: $model->name, + author: $model->author, + description: $model->description, + icon: $model->icon, + features: $model->features, + tags: $model->tags, + docker_image: Arr::first($model->docker_images, default: ''), // deprecated, use docker_images + docker_images: $model->docker_images, + config: [ + 'files' => $files, + 'startup' => json_decode($model->inherit_config_startup ?: '{}', true), + 'stop' => $model->inherit_config_stop, + 'logs' => json_decode($model->inherit_config_logs ?: '{}', true), + 'file_denylist' => $model->inherit_file_denylist, + 'extends' => $model->config_from, + ], + startup: Arr::first($model->startup_commands, default: ''), // deprecated, use startup_commands + startup_commands: $model->startup_commands, + script: [ + 'privileged' => $model->script_is_privileged, + 'install' => $model->copy_script_install, + 'entry' => $model->copy_script_entry, + 'container' => $model->copy_script_container, + 'extends' => $model->copy_script_from, + ], + created_at: self::formatTimestamp($model->created_at), + updated_at: self::formatTimestamp($model->updated_at), + ); + } + + public static function includes(): array + { + return [ + 'servers' => function (Egg $egg, IncludeContext $context): array { + if (!$context->allowsAdmin(Server::RESOURCE_NAME)) { + return $context->null(); + } + + $egg->loadMissing('servers'); + + return $context->collection($egg->getRelation('servers'), ServerData::class); + }, + 'variables' => function (Egg $egg, IncludeContext $context): array { + if (!$context->allowsAdmin(Egg::RESOURCE_NAME)) { + return $context->null(); + } + + $egg->loadMissing('variables'); + + return $context->collection($egg->getRelation('variables'), EggVariableData::class, EggVariable::RESOURCE_NAME); + }, + ]; + } +} diff --git a/app/Data/Api/Application/EggVariableData.php b/app/Data/Api/Application/EggVariableData.php new file mode 100644 index 0000000000..b7f71c36a1 --- /dev/null +++ b/app/Data/Api/Application/EggVariableData.php @@ -0,0 +1,33 @@ + $attributes + */ + public function __construct(public array $attributes) {} + + public static function getResourceName(): string + { + return Egg::RESOURCE_NAME; + } + + public static function fromModel(EggVariable $model): static + { + return new self($model->toArray()); + } + + /** + * @return array + */ + public function toArray(): array + { + return $this->attributes; + } +} diff --git a/app/Data/Api/Application/MountData.php b/app/Data/Api/Application/MountData.php new file mode 100644 index 0000000000..7489d7399a --- /dev/null +++ b/app/Data/Api/Application/MountData.php @@ -0,0 +1,72 @@ + $attributes + */ + public function __construct(public array $attributes) {} + + public static function getResourceName(): string + { + return Mount::RESOURCE_NAME; + } + + public static function fromModel(Mount $model): static + { + return new self($model->toArray()); + } + + /** + * @return array + */ + public function toArray(): array + { + return $this->attributes; + } + + public static function includes(): array + { + return [ + 'eggs' => function (Mount $mount, IncludeContext $context): array { + if (!$context->allowsAdmin(Egg::RESOURCE_NAME)) { + return $context->null(); + } + + $mount->loadMissing('eggs'); + + return $context->collection($mount->getRelation('eggs'), EggData::class); + }, + 'nodes' => function (Mount $mount, IncludeContext $context): array { + if (!$context->allowsAdmin(Node::RESOURCE_NAME)) { + return $context->null(); + } + + $mount->loadMissing('nodes'); + + return $context->collection($mount->getRelation('nodes'), NodeData::class); + }, + 'servers' => function (Mount $mount, IncludeContext $context): array { + if (!$context->allowsAdmin(Server::RESOURCE_NAME)) { + return $context->null(); + } + + $mount->loadMissing('servers'); + + return $context->collection($mount->getRelation('servers'), ServerData::class); + }, + ]; + } +} diff --git a/app/Data/Api/Application/NodeData.php b/app/Data/Api/Application/NodeData.php new file mode 100644 index 0000000000..6a8025646d --- /dev/null +++ b/app/Data/Api/Application/NodeData.php @@ -0,0 +1,77 @@ + $attributes + */ + public function __construct(public array $attributes) {} + + public static function getResourceName(): string + { + return Node::RESOURCE_NAME; + } + + public static function fromModel(Node $model): static + { + $attributes = collect($model->toArray()) + ->mapWithKeys(fn ($value, $key) => [snake_case($key) => $value]) + ->toArray(); + + $attributes[$model->getUpdatedAtColumn()] = self::formatTimestamp($model->updated_at); + $attributes[$model->getCreatedAtColumn()] = self::formatTimestamp($model->created_at); + + $resources = $model->servers()->select(['memory', 'disk', 'cpu'])->get(); + + $attributes['allocated_resources'] = [ + 'memory' => $resources->sum('memory'), + 'disk' => $resources->sum('disk'), + 'cpu' => $resources->sum('cpu'), + ]; + + return new self($attributes); + } + + /** + * @return array + */ + public function toArray(): array + { + return $this->attributes; + } + + public static function includes(): array + { + return [ + 'allocations' => function (Node $node, IncludeContext $context): array { + if (!$context->allowsAdmin(Allocation::RESOURCE_NAME)) { + return $context->null(); + } + + $node->loadMissing('allocations'); + + return $context->collection($node->getRelation('allocations'), AllocationData::class); + }, + 'servers' => function (Node $node, IncludeContext $context): array { + if (!$context->allowsAdmin(Server::RESOURCE_NAME)) { + return $context->null(); + } + + $node->loadMissing('servers'); + + return $context->collection($node->getRelation('servers'), ServerData::class); + }, + ]; + } +} diff --git a/app/Data/Api/Application/PluginData.php b/app/Data/Api/Application/PluginData.php new file mode 100644 index 0000000000..50d4d3a387 --- /dev/null +++ b/app/Data/Api/Application/PluginData.php @@ -0,0 +1,63 @@ + $meta + * @param string[]|null $panels + */ + public function __construct( + public string $id, + public string $name, + public string $author, + public string $version, + public ?string $description, + public mixed $category, + public ?string $url, + public ?string $update_url, + public string $namespace, + public string $class, + public ?array $panels, + public ?string $panel_version, + public mixed $composer_packages, + public array $meta, + ) {} + + public static function getResourceName(): string + { + return Plugin::RESOURCE_NAME; + } + + public static function fromModel(Plugin $model): static + { + return new self( + id: $model->id, + name: $model->name, + author: $model->author, + version: $model->version, + description: $model->description, + category: $model->category, + url: $model->url, + update_url: $model->update_url, + namespace: $model->namespace, + class: $model->class, + panels: $model->panels ? explode(',', $model->panels) : null, + panel_version: $model->panel_version, + composer_packages: $model->composer_packages ? json_decode($model->composer_packages, true, 512, JSON_THROW_ON_ERROR) : null, + meta: [ + 'status' => $model->status, + 'status_message' => $model->status_message, + 'load_order' => $model->load_order, + 'is_compatible' => $model->isCompatible(), + 'update_available' => $model->isUpdateAvailable(), + 'can_enable' => $model->canEnable(), + 'can_disable' => $model->canDisable(), + ], + ); + } +} diff --git a/app/Data/Api/Application/RoleData.php b/app/Data/Api/Application/RoleData.php new file mode 100644 index 0000000000..8c71656285 --- /dev/null +++ b/app/Data/Api/Application/RoleData.php @@ -0,0 +1,46 @@ +id, + name: $model->name, + created_at: $model->created_at->toAtomString(), + updated_at: $model->updated_at->toAtomString(), + ); + } + + public static function includes(): array + { + return [ + 'permissions' => function (Role $role, IncludeContext $context): array { + $role->loadMissing('permissions'); + + return $context->collection($role->getRelation('permissions'), RolePermissionData::class); + }, + ]; + } +} diff --git a/app/Data/Api/Application/RolePermissionData.php b/app/Data/Api/Application/RolePermissionData.php new file mode 100644 index 0000000000..e6860ea9d3 --- /dev/null +++ b/app/Data/Api/Application/RolePermissionData.php @@ -0,0 +1,29 @@ +name, + created_at: $model->created_at->toAtomString(), + updated_at: $model->updated_at->toAtomString(), + ); + } +} diff --git a/app/Data/Api/Application/ServerData.php b/app/Data/Api/Application/ServerData.php new file mode 100644 index 0000000000..4de8126783 --- /dev/null +++ b/app/Data/Api/Application/ServerData.php @@ -0,0 +1,170 @@ + $limits + * @param array $feature_limits + * @param array $container + */ + public function __construct( + public int $id, + public ?string $external_id, + public string $uuid, + public string $identifier, + public string $name, + public ?string $description, + public mixed $status, + public bool $suspended, + public array $limits, + public array $feature_limits, + public int $user, + public int $node, + public ?int $allocation, + public int $egg, + public array $container, + public string $updated_at, + public string $created_at, + ) {} + + public static function getResourceName(): string + { + return Server::RESOURCE_NAME; + } + + public static function fromModel(Server $model, EnvironmentService $environmentService): static + { + return new self( + id: $model->getKey(), + external_id: $model->external_id, + uuid: $model->uuid, + identifier: $model->uuid_short, + name: $model->name, + description: $model->description, + status: $model->status, + // This field is deprecated, please use "status". + suspended: $model->isSuspended(), + limits: [ + 'memory' => $model->memory, + 'swap' => $model->swap, + 'disk' => $model->disk, + 'io' => $model->io, + 'cpu' => $model->cpu, + 'threads' => $model->threads, + // This field is deprecated, please use "oom_killer". + 'oom_disabled' => !$model->oom_killer, + 'oom_killer' => $model->oom_killer, + ], + feature_limits: [ + 'databases' => $model->database_limit, + 'allocations' => $model->allocation_limit, + 'backups' => $model->backup_limit, + ], + user: $model->owner_id, + node: $model->node_id, + allocation: $model->allocation_id, + egg: $model->egg_id, + container: [ + 'startup_command' => $model->startup, + 'image' => $model->image, + // This field is deprecated, please use "status". + 'installed' => $model->isInstalled() ? 1 : 0, + 'environment' => $environmentService->handle($model), + ], + updated_at: self::formatTimestamp($model->updated_at), + created_at: self::formatTimestamp($model->created_at), + ); + } + + public static function includes(): array + { + return [ + 'allocations' => function (Server $server, IncludeContext $context): array { + if (!$context->allowsAdmin(Allocation::RESOURCE_NAME)) { + return $context->null(); + } + + $server->loadMissing('allocations'); + + return $context->collection($server->getRelation('allocations'), AllocationData::class); + }, + 'user' => function (Server $server, IncludeContext $context): array { + if (!$context->allowsAdmin(User::RESOURCE_NAME)) { + return $context->null(); + } + + $server->loadMissing('user'); + + return $context->item($server->getRelation('user'), UserData::class); + }, + 'subusers' => function (Server $server, IncludeContext $context): array { + if (!$context->allowsAdmin(User::RESOURCE_NAME)) { + return $context->null(); + } + + $server->loadMissing('subusers'); + + return $context->collection($server->getRelation('subusers'), SubuserData::class, 'subuser'); + }, + 'egg' => function (Server $server, IncludeContext $context): array { + if (!$context->allowsAdmin(Egg::RESOURCE_NAME)) { + return $context->null(); + } + + $server->loadMissing('egg'); + + return $context->item($server->getRelation('egg'), EggData::class); + }, + 'variables' => function (Server $server, IncludeContext $context): array { + if (!$context->allowsAdmin(Server::RESOURCE_NAME)) { + return $context->null(); + } + + $server->loadMissing('variables'); + + return $context->collection($server->getRelation('variables'), ServerVariableData::class, 'server_variable'); + }, + 'node' => function (Server $server, IncludeContext $context): array { + if (!$context->allowsAdmin(Node::RESOURCE_NAME)) { + return $context->null(); + } + + $server->loadMissing('node'); + + return $context->item($server->getRelation('node'), NodeData::class); + }, + 'databases' => function (Server $server, IncludeContext $context): array { + if (!$context->allowsAdmin(Database::RESOURCE_NAME)) { + return $context->null(); + } + + $server->loadMissing('databases'); + + return $context->collection($server->getRelation('databases'), ServerDatabaseData::class, 'databases'); + }, + ]; + } +} diff --git a/app/Data/Api/Application/ServerDatabaseData.php b/app/Data/Api/Application/ServerDatabaseData.php new file mode 100644 index 0000000000..c0227c0946 --- /dev/null +++ b/app/Data/Api/Application/ServerDatabaseData.php @@ -0,0 +1,66 @@ +id, + server: $model->server_id, + host: $model->database_host_id, + database: $model->database, + username: $model->username, + remote: $model->remote, + max_connections: $model->max_connections, + created_at: $model->created_at->toAtomString(), + updated_at: $model->updated_at->toAtomString(), + ); + } + + public static function includes(): array + { + return [ + 'password' => function (Database $database, IncludeContext $context): array { + return $context->rawItem([ + 'password' => $database->password, + ], 'database_password'); + }, + 'host' => function (Database $database, IncludeContext $context): array { + if (!$context->allowsAdmin(DatabaseHost::RESOURCE_NAME)) { + return $context->null(); + } + + $database->loadMissing('host'); + + return $context->item($database->getRelation('host'), DatabaseHostData::class); + }, + ]; + } +} diff --git a/app/Data/Api/Application/ServerVariableData.php b/app/Data/Api/Application/ServerVariableData.php new file mode 100644 index 0000000000..ae06ebf98d --- /dev/null +++ b/app/Data/Api/Application/ServerVariableData.php @@ -0,0 +1,52 @@ + $attributes + */ + public function __construct(public array $attributes) {} + + public static function getResourceName(): string + { + return EggVariable::RESOURCE_NAME; + } + + public static function fromModel(EggVariable $model): static + { + return new self($model->toArray()); + } + + /** + * @return array + */ + public function toArray(): array + { + return $this->attributes; + } + + public static function includes(): array + { + return [ + 'parent' => function (EggVariable $variable, IncludeContext $context): array { + if (!$context->allowsAdmin(Egg::RESOURCE_NAME)) { + return $context->null(); + } + + $variable->loadMissing('variable'); + + return $context->item($variable->getRelation('variable'), EggVariableData::class, 'variable'); + }, + ]; + } +} diff --git a/app/Data/Api/Application/SubuserData.php b/app/Data/Api/Application/SubuserData.php new file mode 100644 index 0000000000..723df7dbb6 --- /dev/null +++ b/app/Data/Api/Application/SubuserData.php @@ -0,0 +1,65 @@ +id, + user_id: $model->user_id, + server_id: $model->server_id, + permissions: $model->permissions, + created_at: self::formatTimestamp($model->created_at), + updated_at: self::formatTimestamp($model->updated_at), + ); + } + + public static function includes(): array + { + return [ + 'user' => function (Subuser $subuser, IncludeContext $context): array { + if (!$context->allowsAdmin(User::RESOURCE_NAME)) { + return $context->null(); + } + + $subuser->loadMissing('user'); + + return $context->item($subuser->getRelation('user'), UserData::class); + }, + 'server' => function (Subuser $subuser, IncludeContext $context): array { + if (!$context->allowsAdmin(Server::RESOURCE_NAME)) { + return $context->null(); + } + + $subuser->loadMissing('server'); + + return $context->item($subuser->getRelation('server'), ServerData::class); + }, + ]; + } +} diff --git a/app/Data/Api/Application/UserData.php b/app/Data/Api/Application/UserData.php new file mode 100644 index 0000000000..6f690fa708 --- /dev/null +++ b/app/Data/Api/Application/UserData.php @@ -0,0 +1,83 @@ +id, + external_id: $model->external_id, + is_managed_externally: $model->is_managed_externally, + uuid: $model->uuid, + username: $model->username, + email: $model->email, + language: $model->language, + root_admin: $model->isRootAdmin(), + twoFactorEnabled: filled($model->mfa_app_secret), + twoFactorLegacy: filled($model->mfa_app_secret), // deprecated, use "2fa_enabled" + created_at: self::formatTimestamp($model->created_at), + updated_at: self::formatTimestamp($model->updated_at), + ); + } + + public static function includes(): array + { + return [ + 'servers' => function (User $user, IncludeContext $context): array { + if (!$context->allowsAdmin(Server::RESOURCE_NAME)) { + return $context->null(); + } + + $user->loadMissing('servers'); + + return $context->collection($user->getRelation('servers'), ServerData::class); + }, + 'roles' => function (User $user, IncludeContext $context): array { + if (!$context->allowsAdmin(Role::RESOURCE_NAME)) { + return $context->null(); + } + + $user->loadMissing('roles'); + + return $context->collection($user->getRelation('roles'), RoleData::class); + }, + ]; + } +} diff --git a/app/Data/Api/Client/ActivityLogData.php b/app/Data/Api/Client/ActivityLogData.php new file mode 100644 index 0000000000..6ded8f6dd3 --- /dev/null +++ b/app/Data/Api/Client/ActivityLogData.php @@ -0,0 +1,68 @@ + $properties + */ + public function __construct( + public string $id, + public string $event, + public bool $is_api, + public ?string $ip, + public ?string $description, + public array $properties, + public bool $has_additional_metadata, + public string $timestamp, + ) {} + + public static function getResourceName(): string + { + return ActivityLog::RESOURCE_NAME; + } + + public static function fromModel(ActivityLog $model, Request $request): static + { + // Whether the user can view the IP address in the output, either because they are + // the actor that performed the action or because they are an administrator. + $canViewIp = $model->actor?->is($request->user()) || $request->user()->can('seeIps activityLog'); + + return new self( + // This is not for security, it is only to provide a unique identifier to + // the front-end for each entry to improve rendering performance since there + // is nothing else sufficiently unique to key off at this point. + id: sha1((string) $model->id), + event: $model->event, + is_api: !is_null($model->api_key_id), + ip: $canViewIp ? $model->ip : null, + description: $model->description, + properties: $model->wrapProperties(), + has_additional_metadata: $model->hasAdditionalMetadata(), + timestamp: $model->timestamp->toAtomString(), + ); + } + + public static function includes(): array + { + return [ + 'actor' => function (ActivityLog $model, IncludeContext $context): array { + if (!$model->actor instanceof User) { + return $context->null(); + } + + return $context->item($model->actor, UserData::class); + }, + ]; + } +} diff --git a/app/Data/Api/Client/AllocationData.php b/app/Data/Api/Client/AllocationData.php new file mode 100644 index 0000000000..f2af32cdf9 --- /dev/null +++ b/app/Data/Api/Client/AllocationData.php @@ -0,0 +1,35 @@ +id, + ip: $model->ip, + ip_alias: $model->ip_alias, + port: $model->port, + notes: $model->notes, + is_default: $model->server->allocation_id === $model->id, + ); + } +} diff --git a/app/Data/Api/Client/ApiKeyData.php b/app/Data/Api/Client/ApiKeyData.php new file mode 100644 index 0000000000..693eab2e24 --- /dev/null +++ b/app/Data/Api/Client/ApiKeyData.php @@ -0,0 +1,36 @@ +identifier, + description: $model->memo, + allowed_ips: $model->allowed_ips, + last_used_at: $model->last_used_at ? $model->last_used_at->toAtomString() : null, + created_at: $model->created_at->toAtomString(), + ); + } +} diff --git a/app/Data/Api/Client/BackupData.php b/app/Data/Api/Client/BackupData.php new file mode 100644 index 0000000000..577acab4f6 --- /dev/null +++ b/app/Data/Api/Client/BackupData.php @@ -0,0 +1,46 @@ +uuid, + is_successful: $model->is_successful, + is_locked: $model->is_locked, + is_scheduled: $model->is_scheduled, + name: $model->name, + ignored_files: $model->ignored_files, + checksum: $model->checksum, + bytes: $model->bytes, + created_at: $model->created_at->toAtomString(), + completed_at: $model->completed_at ? $model->completed_at->toAtomString() : null, + ); + } +} diff --git a/app/Data/Api/Client/DatabaseData.php b/app/Data/Api/Client/DatabaseData.php new file mode 100644 index 0000000000..c7e740f8f1 --- /dev/null +++ b/app/Data/Api/Client/DatabaseData.php @@ -0,0 +1,63 @@ +loadMissing('host'); + + return new self( + id: $model->id, + host: [ + 'address' => $model->getRelation('host')->host, + 'port' => $model->getRelation('host')->port, + ], + name: $model->database, + username: $model->username, + connections_from: $model->remote, + max_connections: $model->max_connections, + ); + } + + public static function includes(): array + { + return [ + 'password' => function (Database $database, IncludeContext $context): array { + if (!$context->allowsClient(SubuserPermission::DatabaseViewPassword->value, $database->server)) { + return $context->null(); + } + + return $context->rawItem([ + 'password' => $database->password, + ], 'database_password'); + }, + ]; + } +} diff --git a/app/Data/Api/Client/EggData.php b/app/Data/Api/Client/EggData.php new file mode 100644 index 0000000000..e5cd90ad31 --- /dev/null +++ b/app/Data/Api/Client/EggData.php @@ -0,0 +1,27 @@ +uuid, + name: $model->name, + ); + } +} diff --git a/app/Data/Api/Client/EggVariableData.php b/app/Data/Api/Client/EggVariableData.php new file mode 100644 index 0000000000..889cdd2d55 --- /dev/null +++ b/app/Data/Api/Client/EggVariableData.php @@ -0,0 +1,43 @@ +user_viewable, new BadMethodCallException('Cannot transform a hidden egg variable in a client transformer.')); + + return new self( + name: $model->name, + description: $model->description, + env_variable: $model->env_variable, + default_value: $model->default_value, + server_value: $model->server_value, + is_editable: $model->user_editable, + rules: implode('|', $model->rules), + ); + } +} diff --git a/app/Data/Api/Client/FileObjectData.php b/app/Data/Api/Client/FileObjectData.php new file mode 100644 index 0000000000..3405a3605b --- /dev/null +++ b/app/Data/Api/Client/FileObjectData.php @@ -0,0 +1,45 @@ + $model + */ + public static function fromModel(array $model): static + { + return new self( + name: Arr::get($model, 'name'), + mode: Arr::get($model, 'mode'), + mode_bits: Arr::get($model, 'mode_bits'), + size: Arr::get($model, 'size'), + is_file: Arr::get($model, 'file', true), + is_symlink: Arr::get($model, 'symlink', false), + mimetype: Arr::get($model, 'mime', 'application/octet-stream'), + created_at: Carbon::parse(Arr::get($model, 'created', ''))->toAtomString(), + modified_at: Carbon::parse(Arr::get($model, 'modified', ''))->toAtomString(), + ); + } +} diff --git a/app/Data/Api/Client/ScheduleData.php b/app/Data/Api/Client/ScheduleData.php new file mode 100644 index 0000000000..67e5bffee7 --- /dev/null +++ b/app/Data/Api/Client/ScheduleData.php @@ -0,0 +1,68 @@ +id, + name: $model->name, + cron: [ + 'day_of_week' => $model->cron_day_of_week, + 'day_of_month' => $model->cron_day_of_month, + 'month' => $model->cron_month, + 'hour' => $model->cron_hour, + 'minute' => $model->cron_minute, + ], + is_active: $model->is_active, + is_processing: $model->is_processing, + only_when_online: $model->only_when_online, + last_run_at: $model->last_run_at?->toAtomString(), + next_run_at: $model->next_run_at?->toAtomString(), + created_at: $model->created_at->toAtomString(), + updated_at: $model->updated_at->toAtomString(), + ); + } + + public static function includes(): array + { + return [ + 'tasks' => function (Schedule $model, IncludeContext $context): array { + return $context->collection($model->tasks, TaskData::class); + }, + ]; + } +} diff --git a/app/Data/Api/Client/ServerData.php b/app/Data/Api/Client/ServerData.php new file mode 100644 index 0000000000..282ee32f97 --- /dev/null +++ b/app/Data/Api/Client/ServerData.php @@ -0,0 +1,136 @@ + $limits + * @param string[]|null $egg_features + * @param array $feature_limits + */ + public function __construct( + public bool $server_owner, + public string $identifier, + public int $internal_id, + public string $uuid, + public string $name, + public string $node, + public bool $is_node_under_maintenance, + public array $sftp_details, + public string|null|Optional $description, + public array $limits, + public string $invocation, + public string $docker_image, + public ?array $egg_features, + public array $feature_limits, + public ?ServerState $status, + public bool $is_suspended, + public bool $is_installing, + public bool $is_transferring, + ) {} + + public static function getResourceName(): string + { + return Server::RESOURCE_NAME; + } + + public static function fromModel(Server $model, StartupCommandService $service, Request $request): static + { + $user = $request->user(); + + return new self( + server_owner: $user->id === $model->owner_id, + identifier: $model->uuid_short, + internal_id: $model->id, + uuid: $model->uuid, + name: $model->name, + node: $model->node->name, + is_node_under_maintenance: $model->node->isUnderMaintenance(), + sftp_details: [ + 'ip' => $model->node->fqdn, + 'alias' => $model->node->daemon_sftp_alias, + 'port' => $model->node->daemon_sftp, + ], + description: config('panel.editable_server_descriptions') ? $model->description : Optional::create(), + limits: [ + 'memory' => $model->memory, + 'swap' => $model->swap, + 'disk' => $model->disk, + 'io' => $model->io, + 'cpu' => $model->cpu, + 'threads' => $model->threads, + // This field is deprecated, please use "oom_killer". + 'oom_disabled' => !$model->oom_killer, + 'oom_killer' => $model->oom_killer, + ], + invocation: $service->handle($model, hideAllValues: !$user->can(SubuserPermission::StartupRead, $model)), + docker_image: $model->image, + egg_features: $model->egg->inherit_features, + feature_limits: [ + 'databases' => $model->database_limit, + 'allocations' => $model->allocation_limit, + 'backups' => $model->backup_limit, + ], + status: $model->status, + // This field is deprecated, please use "status". + is_suspended: $model->isSuspended(), + // This field is deprecated, please use "status". + is_installing: !$model->isInstalled(), + is_transferring: !is_null($model->transfer), + ); + } + + public static function includes(): array + { + return [ + // If the user doesn't have read permissions for the allocations we only return + // the primary server allocation, and any notes associated with it are hidden. + // This avoids permission regression without hiding information the frontend + // needs to make sense when browsing or searching results. + 'allocations' => function (Server $server, IncludeContext $context): array { + if (!$context->allowsClient(SubuserPermission::AllocationRead->value, $server)) { + $primary = clone $server->allocation; + $primary->notes = null; + + return $context->collection([$primary], AllocationData::class); + } + + return $context->collection($server->allocations, AllocationData::class); + }, + 'variables' => function (Server $server, IncludeContext $context): array { + if (!$context->allowsClient(SubuserPermission::StartupRead->value, $server)) { + return $context->null(); + } + + return $context->collection($server->variables->where('user_viewable', true), EggVariableData::class); + }, + 'egg' => function (Server $server, IncludeContext $context): array { + return $context->item($server->egg, EggData::class); + }, + 'subusers' => function (Server $server, IncludeContext $context): array { + if (!$context->allowsClient(SubuserPermission::UserRead->value, $server)) { + return $context->null(); + } + + return $context->collection($server->subusers, SubuserData::class); + }, + ]; + } +} diff --git a/app/Data/Api/Client/StatsData.php b/app/Data/Api/Client/StatsData.php new file mode 100644 index 0000000000..bf33e1728c --- /dev/null +++ b/app/Data/Api/Client/StatsData.php @@ -0,0 +1,42 @@ + $resources + */ + public function __construct( + public string $current_state, + public bool $is_suspended, + public array $resources, + ) {} + + public static function getResourceName(): string + { + return 'stats'; + } + + /** + * @param array $model + */ + public static function fromModel(array $model): static + { + return new self( + current_state: Arr::get($model, 'state', 'stopped'), + is_suspended: Arr::get($model, 'is_suspended', false), + resources: [ + 'memory_bytes' => Arr::get($model, 'utilization.memory_bytes', 0), + 'cpu_absolute' => Arr::get($model, 'utilization.cpu_absolute', 0), + 'disk_bytes' => Arr::get($model, 'utilization.disk_bytes', 0), + 'network_rx_bytes' => Arr::get($model, 'utilization.network.rx_bytes', 0), + 'network_tx_bytes' => Arr::get($model, 'utilization.network.tx_bytes', 0), + 'uptime' => Arr::get($model, 'utilization.uptime', 0), + ], + ); + } +} diff --git a/app/Data/Api/Client/SubuserData.php b/app/Data/Api/Client/SubuserData.php new file mode 100644 index 0000000000..4c701ec3e4 --- /dev/null +++ b/app/Data/Api/Client/SubuserData.php @@ -0,0 +1,52 @@ +user); + + return new self( + uuid: $user->uuid, + username: $user->username, + email: $user->email, + language: $user->language, + image: $user->image, + admin: $user->admin, + root_admin: $user->root_admin, + two_factor_enabled: $user->two_factor_enabled, + created_at: $user->created_at, + updated_at: $user->updated_at, + permissions: $model->permissions, + ); + } +} diff --git a/app/Data/Api/Client/TaskData.php b/app/Data/Api/Client/TaskData.php new file mode 100644 index 0000000000..5feaeec57b --- /dev/null +++ b/app/Data/Api/Client/TaskData.php @@ -0,0 +1,41 @@ +id, + sequence_id: $model->sequence_id, + action: $model->action, + payload: $model->payload, + time_offset: $model->time_offset, + is_queued: $model->is_queued, + continue_on_failure: $model->continue_on_failure, + created_at: $model->created_at->toAtomString(), + updated_at: $model->updated_at->toAtomString(), + ); + } +} diff --git a/app/Data/Api/Client/UserData.php b/app/Data/Api/Client/UserData.php new file mode 100644 index 0000000000..faa2edc361 --- /dev/null +++ b/app/Data/Api/Client/UserData.php @@ -0,0 +1,46 @@ +uuid, + username: $model->username, + email: $model->email, + language: $model->language, + image: 'https://gravatar.com/avatar/' . md5(Str::lower($model->email)), // deprecated + admin: $model->isRootAdmin(), // deprecated, use "root_admin" + root_admin: $model->isRootAdmin(), + two_factor_enabled: filled($model->mfa_app_secret), + created_at: self::formatTimestamp($model->created_at), + updated_at: self::formatTimestamp($model->updated_at), + ); + } +} diff --git a/app/Data/Api/Client/UserSSHKeyData.php b/app/Data/Api/Client/UserSSHKeyData.php new file mode 100644 index 0000000000..ea7a1dc047 --- /dev/null +++ b/app/Data/Api/Client/UserSSHKeyData.php @@ -0,0 +1,31 @@ +name, + fingerprint: $model->fingerprint, + public_key: $model->public_key, + created_at: $model->created_at->toAtomString(), + ); + } +} diff --git a/app/Data/Api/Envelope.php b/app/Data/Api/Envelope.php new file mode 100644 index 0000000000..fa4fb42aaf --- /dev/null +++ b/app/Data/Api/Envelope.php @@ -0,0 +1,89 @@ + $dataClass + * @return array + */ + public static function item(mixed $model, string $dataClass, IncludeContext $context, ?string $resourceKey = null): array + { + if (is_null($model)) { + return $context->null(); + } + + return [ + 'object' => $resourceKey ?? $dataClass::getResourceName(), + 'attributes' => self::attributes($model, $dataClass, $context), + ]; + } + + /** + * @param iterable $models + * @param class-string $dataClass + * @return array{object: string, data: array} + */ + public static function collection(iterable $models, string $dataClass, IncludeContext $context, ?string $resourceKey = null): array + { + $key = $resourceKey ?? $dataClass::getResourceName(); + + $data = []; + foreach ($models as $model) { + $data[] = [ + 'object' => $key, + 'attributes' => self::attributes($model, $dataClass, $context), + ]; + } + + return [ + 'object' => 'list', + 'data' => $data, + ]; + } + + /** + * Hydrate the resource through the container so fromModel can take extra typed + * dependencies, then attach default includes and any requested includes that the + * resource declares available. + * + * @param class-string $dataClass + * @return array + */ + private static function attributes(mixed $model, string $dataClass, IncludeContext $context): array + { + $resource = Container::getInstance()->call([$dataClass, 'fromModel'], ['model' => $model]); + + $attributes = $resource->toArray(); + + $names = $dataClass::$defaultIncludes; + foreach ($dataClass::$availableIncludes as $name) { + if (!in_array($name, $names, true) && $context->isRequested($name)) { + $names[] = $name; + } + } + + $relationships = []; + $resolvers = $names === [] ? [] : $dataClass::includes(); + foreach ($names as $name) { + if (isset($resolvers[$name])) { + $relationships[$name] = $resolvers[$name]($model, $context->descend($name)); + } + } + + if ($relationships !== []) { + $attributes['relationships'] = $relationships; + } + + return $attributes; + } +} diff --git a/app/Data/Api/IncludeContext.php b/app/Data/Api/IncludeContext.php new file mode 100644 index 0000000000..a473617237 --- /dev/null +++ b/app/Data/Api/IncludeContext.php @@ -0,0 +1,114 @@ +request->user(); + } + + /** + * Whether the API key on the request may touch the given resource, mirroring + * what BaseTransformer::authorize did for application API includes. + */ + public function allowsAdmin(string $resource): bool + { + $token = $this->user()?->currentAccessToken(); + if (!$token instanceof ApiKey || !in_array($token->key_type, [ApiKey::TYPE_ACCOUNT, ApiKey::TYPE_APPLICATION])) { + return false; + } + + if ($token->key_type === ApiKey::TYPE_ACCOUNT) { + return $this->user()->isRootAdmin(); + } + + return AdminAcl::check($token, $resource); + } + + /** + * Whether the requesting user holds the given ability on the server, mirroring + * BaseClientTransformer::authorize for client API includes. + */ + public function allowsClient(string $ability, ?Server $server = null): bool + { + return (bool) $this->user()?->can($ability, [$server]); + } + + public function isRequested(string $include): bool + { + return in_array(implode('.', [...$this->path, $include]), $this->requestedIncludes, true); + } + + public function descend(string $include): self + { + return new self($this->request, $this->requestedIncludes, [...$this->path, $include]); + } + + /** + * @param class-string $dataClass + * @return array + */ + public function item(mixed $model, string $dataClass, ?string $resourceKey = null): array + { + return Envelope::item($model, $dataClass, $this, $resourceKey); + } + + /** + * @param iterable $models + * @param class-string $dataClass + * @return array + */ + public function collection(iterable $models, string $dataClass, ?string $resourceKey = null): array + { + return Envelope::collection($models, $dataClass, $this, $resourceKey); + } + + /** + * Wrap already transformed attributes, for includes that have no backing model + * like the database password. + * + * @param array $attributes + * @return array + */ + public function rawItem(array $attributes, string $resourceKey): array + { + return [ + 'object' => $resourceKey, + 'attributes' => $attributes, + ]; + } + + /** + * @return array{object: string, attributes: null} + */ + public function null(): array + { + return [ + 'object' => 'null_resource', + 'attributes' => null, + ]; + } +} diff --git a/app/Data/Api/PanelResponse.php b/app/Data/Api/PanelResponse.php new file mode 100644 index 0000000000..725aad29a1 --- /dev/null +++ b/app/Data/Api/PanelResponse.php @@ -0,0 +1,183 @@ +|null */ + protected ?string $dataClass = null; + + /** @var string[] */ + protected array $rawIncludes = []; + + protected int $recursionLimit = 10; + + /** @var array */ + protected array $meta = []; + + public function __construct(protected Request $request) {} + + public function item(mixed $data): static + { + $this->data = $data; + $this->isCollection = false; + + return $this; + } + + public function collection(mixed $data): static + { + $this->data = $data; + $this->isCollection = true; + + return $this; + } + + /** + * @param class-string $dataClass + */ + public function transformWith(string $dataClass): static + { + $this->dataClass = $dataClass; + + return $this; + } + + /** + * @param string[]|string $includes + */ + public function parseIncludes(array|string $includes): static + { + $includes = is_string($includes) ? explode(',', $includes) : $includes; + + $this->rawIncludes = array_merge($this->rawIncludes, $includes); + + return $this; + } + + public function limitRecursion(int $limit): static + { + $this->recursionLimit = $limit; + + return $this; + } + + /** + * Union semantics matching Fractalistic: a key set by an earlier call is not + * overwritten by a later one. + * + * @param array ...$blocks + */ + public function addMeta(array ...$blocks): static + { + foreach ($blocks as $block) { + $this->meta += $block; + } + + return $this; + } + + /** + * @return array + */ + public function toArray(): array + { + $context = new IncludeContext($this->request, $this->requestedIncludes()); + + $meta = $this->meta; + + if ($this->data instanceof LengthAwarePaginator) { + $envelope = Envelope::collection($this->data->items(), $this->dataClass, $context); + $meta['pagination'] = $this->pagination($this->data); + } elseif (is_null($this->data)) { + $envelope = $context->null(); + } elseif ($this->isCollection) { + $envelope = Envelope::collection($this->data, $this->dataClass, $context); + } else { + $envelope = Envelope::item($this->data, $this->dataClass, $context); + } + + if ($meta !== []) { + $envelope['meta'] = $meta; + } + + return $envelope; + } + + public function respond(int $status = 200): JsonResponse + { + return new JsonResponse($this->toArray(), $status); + } + + /** + * Normalize the raw include names the way League parsed them: strip parameter + * suffixes, trim each dot path to the recursion limit, and imply every parent + * of a nested path. + * + * @return string[] + */ + protected function requestedIncludes(): array + { + $paths = []; + + foreach ($this->rawIncludes as $include) { + $name = trim(explode(':', $include, 2)[0]); + if ($name === '') { + continue; + } + + $segments = array_slice(explode('.', $name), 0, $this->recursionLimit); + for ($depth = 1; $depth <= count($segments); $depth++) { + $paths[] = implode('.', array_slice($segments, 0, $depth)); + } + } + + return array_values(array_unique($paths)); + } + + /** + * The exact meta.pagination block League's ArraySerializer produced, including + * the empty object when there are no previous or next links. + * + * @return array + */ + protected function pagination(LengthAwarePaginator $paginator): array + { + $pagination = [ + 'total' => $paginator->total(), + 'count' => count($paginator->items()), + 'per_page' => $paginator->perPage(), + 'current_page' => $paginator->currentPage(), + 'total_pages' => $paginator->lastPage(), + ]; + + $links = []; + if ($paginator->currentPage() > 1) { + $links['previous'] = $paginator->url($paginator->currentPage() - 1); + } + if ($paginator->currentPage() < $paginator->lastPage()) { + $links['next'] = $paginator->url($paginator->currentPage() + 1); + } + + $pagination['links'] = $links === [] ? (object) [] : $links; + + return $pagination; + } +} diff --git a/app/Http/Controllers/Api/Application/ApplicationApiController.php b/app/Http/Controllers/Api/Application/ApplicationApiController.php index 9caac19822..e435f13a3e 100644 --- a/app/Http/Controllers/Api/Application/ApplicationApiController.php +++ b/app/Http/Controllers/Api/Application/ApplicationApiController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Application; +use App\Data\Api\PanelResponse; use App\Extensions\Spatie\Fractalistic\Fractal; use App\Http\Controllers\Controller; use App\Transformers\Api\Application\BaseTransformer; @@ -17,6 +18,8 @@ abstract class ApplicationApiController extends Controller protected Fractal $fractal; + protected PanelResponse $response; + /** * ApplicationApiController constructor. */ @@ -34,15 +37,19 @@ public function __construct() $this->fractal->parseIncludes($includes); $this->fractal->limitRecursion(2); + + $this->response->parseIncludes($includes); + $this->response->limitRecursion(2); } /** * Perform dependency injection of certain classes needed for core functionality * without littering the constructors of classes that extend this abstract. */ - public function loadDependencies(Fractal $fractal, Request $request): void + public function loadDependencies(Fractal $fractal, PanelResponse $response, Request $request): void { $this->fractal = $fractal; + $this->response = $response; $this->request = $request; } diff --git a/app/Http/Controllers/Api/Application/DatabaseHosts/DatabaseHostController.php b/app/Http/Controllers/Api/Application/DatabaseHosts/DatabaseHostController.php index 08e01a3545..d682b5bb03 100644 --- a/app/Http/Controllers/Api/Application/DatabaseHosts/DatabaseHostController.php +++ b/app/Http/Controllers/Api/Application/DatabaseHosts/DatabaseHostController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Application\DatabaseHosts; +use App\Data\Api\Application\DatabaseHostData; use App\Http\Controllers\Api\Application\ApplicationApiController; use App\Http\Requests\Api\Application\DatabaseHosts\DeleteDatabaseHostRequest; use App\Http\Requests\Api\Application\DatabaseHosts\GetDatabaseHostRequest; @@ -10,7 +11,6 @@ use App\Models\DatabaseHost; use App\Services\Databases\Hosts\HostCreationService; use App\Services\Databases\Hosts\HostUpdateService; -use App\Transformers\Api\Application\DatabaseHostTransformer; use Exception; use Illuminate\Http\JsonResponse; use Illuminate\Http\Response; @@ -43,8 +43,8 @@ public function index(GetDatabaseHostRequest $request): array ->allowedSorts(['id', 'name', 'host']) ->paginate($request->query('per_page') ?? 10); - return $this->fractal->collection($databases) - ->transformWith($this->getTransformer(DatabaseHostTransformer::class)) + return $this->response->collection($databases) + ->transformWith(DatabaseHostData::class) ->toArray(); } @@ -57,8 +57,8 @@ public function index(GetDatabaseHostRequest $request): array */ public function view(GetDatabaseHostRequest $request, DatabaseHost $databaseHost): array { - return $this->fractal->item($databaseHost) - ->transformWith($this->getTransformer(DatabaseHostTransformer::class)) + return $this->response->item($databaseHost) + ->transformWith(DatabaseHostData::class) ->toArray(); } @@ -74,8 +74,8 @@ public function store(StoreDatabaseHostRequest $request): JsonResponse { $databaseHost = $this->creationService->handle($request->validated()); - return $this->fractal->item($databaseHost) - ->transformWith($this->getTransformer(DatabaseHostTransformer::class)) + return $this->response->item($databaseHost) + ->transformWith(DatabaseHostData::class) ->addMeta([ 'resource' => route('api.application.databasehosts.view', [ 'database_host' => $databaseHost->id, @@ -97,8 +97,8 @@ public function update(UpdateDatabaseHostRequest $request, DatabaseHost $databas { $databaseHost = $this->updateService->handle($databaseHost->id, $request->validated()); - return $this->fractal->item($databaseHost) - ->transformWith($this->getTransformer(DatabaseHostTransformer::class)) + return $this->response->item($databaseHost) + ->transformWith(DatabaseHostData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Application/Eggs/EggController.php b/app/Http/Controllers/Api/Application/Eggs/EggController.php index c3ce0c0266..9cb70e329d 100644 --- a/app/Http/Controllers/Api/Application/Eggs/EggController.php +++ b/app/Http/Controllers/Api/Application/Eggs/EggController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Application\Eggs; +use App\Data\Api\Application\EggData; use App\Enums\EggFormat; use App\Http\Controllers\Api\Application\ApplicationApiController; use App\Http\Requests\Api\Application\Eggs\ExportEggRequest; @@ -11,7 +12,6 @@ use App\Models\Egg; use App\Services\Eggs\Sharing\EggExporterService; use App\Services\Eggs\Sharing\EggImporterService; -use App\Transformers\Api\Application\EggTransformer; use Exception; use Illuminate\Http\JsonResponse; use Illuminate\Http\Response; @@ -36,8 +36,8 @@ public function __construct( */ public function index(GetEggsRequest $request): array { - return $this->fractal->collection(Egg::all()) - ->transformWith($this->getTransformer(EggTransformer::class)) + return $this->response->collection(Egg::all()) + ->transformWith(EggData::class) ->toArray(); } @@ -50,8 +50,8 @@ public function index(GetEggsRequest $request): array */ public function view(GetEggRequest $request, Egg $egg): array { - return $this->fractal->item($egg) - ->transformWith($this->getTransformer(EggTransformer::class)) + return $this->response->item($egg) + ->transformWith(EggData::class) ->toArray(); } @@ -98,8 +98,8 @@ public function import(ImportEggRequest $request): JsonResponse { $egg = $this->importService->fromContent($request->getContent()); - return $this->fractal->item($egg) - ->transformWith($this->getTransformer(EggTransformer::class)) + return $this->response->item($egg) + ->transformWith(EggData::class) ->respond(201); } } diff --git a/app/Http/Controllers/Api/Application/Mounts/MountController.php b/app/Http/Controllers/Api/Application/Mounts/MountController.php index 27600253d8..f99ac80cc5 100644 --- a/app/Http/Controllers/Api/Application/Mounts/MountController.php +++ b/app/Http/Controllers/Api/Application/Mounts/MountController.php @@ -2,6 +2,10 @@ namespace App\Http\Controllers\Api\Application\Mounts; +use App\Data\Api\Application\EggData; +use App\Data\Api\Application\MountData; +use App\Data\Api\Application\NodeData; +use App\Data\Api\Application\ServerData; use App\Exceptions\Model\DataValidationException; use App\Exceptions\Service\HasActiveServersException; use App\Http\Controllers\Api\Application\ApplicationApiController; @@ -17,10 +21,6 @@ use App\Http\Requests\Api\Application\Nodes\GetNodesRequest; use App\Http\Requests\Api\Application\Servers\GetServerRequest; use App\Models\Mount; -use App\Transformers\Api\Application\EggTransformer; -use App\Transformers\Api\Application\MountTransformer; -use App\Transformers\Api\Application\NodeTransformer; -use App\Transformers\Api\Application\ServerTransformer; use Illuminate\Http\JsonResponse; use Ramsey\Uuid\Uuid; use Spatie\QueryBuilder\QueryBuilder; @@ -42,8 +42,8 @@ public function index(GetMountRequest $request): array ->allowedSorts(['id', 'uuid']) ->paginate($request->query('per_page') ?? 50); - return $this->fractal->collection($mounts) - ->transformWith($this->getTransformer(MountTransformer::class)) + return $this->response->collection($mounts) + ->transformWith(MountData::class) ->toArray(); } @@ -56,8 +56,8 @@ public function index(GetMountRequest $request): array */ public function view(GetMountRequest $request, Mount $mount): array { - return $this->fractal->item($mount) - ->transformWith($this->getTransformer(MountTransformer::class)) + return $this->response->item($mount) + ->transformWith(MountData::class) ->toArray(); } @@ -77,8 +77,8 @@ public function store(StoreMountRequest $request): JsonResponse $model->saveOrFail(); $mount = $model->fresh(); - return $this->fractal->item($mount) - ->transformWith($this->getTransformer(MountTransformer::class)) + return $this->response->item($mount) + ->transformWith(MountData::class) ->addMeta([ 'resource' => route('api.application.mounts.view', [ 'mount' => $mount->id, @@ -100,8 +100,8 @@ public function update(UpdateMountRequest $request, Mount $mount): array { $mount->forceFill($request->validated())->save(); - return $this->fractal->item($mount) - ->transformWith($this->getTransformer(MountTransformer::class)) + return $this->response->item($mount) + ->transformWith(MountData::class) ->toArray(); } @@ -132,8 +132,8 @@ public function delete(DeleteMountRequest $request, Mount $mount): JsonResponse */ public function getEggs(GetEggsRequest $request, Mount $mount): array { - return $this->fractal->collection($mount->eggs) - ->transformWith($this->getTransformer(EggTransformer::class)) + return $this->response->collection($mount->eggs) + ->transformWith(EggData::class) ->toArray(); } @@ -147,8 +147,8 @@ public function getEggs(GetEggsRequest $request, Mount $mount): array */ public function getNodes(GetNodesRequest $request, Mount $mount): array { - return $this->fractal->collection($mount->nodes) - ->transformWith($this->getTransformer(NodeTransformer::class)) + return $this->response->collection($mount->nodes) + ->transformWith(NodeData::class) ->toArray(); } @@ -161,8 +161,8 @@ public function getNodes(GetNodesRequest $request, Mount $mount): array */ public function getServers(GetServerRequest $request, Mount $mount): array { - return $this->fractal->collection($mount->servers) - ->transformWith($this->getTransformer(ServerTransformer::class)) + return $this->response->collection($mount->servers) + ->transformWith(ServerData::class) ->toArray(); } @@ -177,8 +177,8 @@ public function addEggs(UpdateMountEggsRequest $request, Mount $mount): array { $mount->eggs()->attach($request->validated('eggs')); - return $this->fractal->item($mount) - ->transformWith($this->getTransformer(MountTransformer::class)) + return $this->response->item($mount) + ->transformWith(MountData::class) ->toArray(); } @@ -193,8 +193,8 @@ public function addNodes(UpdateMountNodesRequest $request, Mount $mount): array { $mount->nodes()->attach($request->validated('nodes')); - return $this->fractal->item($mount) - ->transformWith($this->getTransformer(MountTransformer::class)) + return $this->response->item($mount) + ->transformWith(MountData::class) ->toArray(); } @@ -209,8 +209,8 @@ public function addServers(UpdateMountServersRequest $request, Mount $mount): ar { $mount->servers()->attach($request->validated('servers')); - return $this->fractal->item($mount) - ->transformWith($this->getTransformer(MountTransformer::class)) + return $this->response->item($mount) + ->transformWith(MountData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Application/Nodes/AllocationController.php b/app/Http/Controllers/Api/Application/Nodes/AllocationController.php index 2654dd0a4e..89f5e067bf 100644 --- a/app/Http/Controllers/Api/Application/Nodes/AllocationController.php +++ b/app/Http/Controllers/Api/Application/Nodes/AllocationController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Application\Nodes; +use App\Data\Api\Application\AllocationData; use App\Exceptions\DisplayException; use App\Exceptions\Service\Allocation\CidrOutOfRangeException; use App\Exceptions\Service\Allocation\InvalidPortMappingException; @@ -14,7 +15,6 @@ use App\Models\Allocation; use App\Models\Node; use App\Services\Allocations\AssignmentService; -use App\Transformers\Api\Application\AllocationTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\JsonResponse; @@ -57,8 +57,8 @@ public function index(GetAllocationsRequest $request, Node $node): array ]) ->paginate($request->query('per_page') ?? 50); - return $this->fractal->collection($allocations) - ->transformWith($this->getTransformer(AllocationTransformer::class)) + return $this->response->collection($allocations) + ->transformWith(AllocationData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Application/Nodes/NodeController.php b/app/Http/Controllers/Api/Application/Nodes/NodeController.php index cda25179e1..666da7c918 100644 --- a/app/Http/Controllers/Api/Application/Nodes/NodeController.php +++ b/app/Http/Controllers/Api/Application/Nodes/NodeController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Application\Nodes; +use App\Data\Api\Application\NodeData; use App\Exceptions\Model\DataValidationException; use App\Exceptions\Service\HasActiveServersException; use App\Http\Controllers\Api\Application\ApplicationApiController; @@ -13,7 +14,6 @@ use App\Models\Node; use App\Services\Nodes\NodeDeletionService; use App\Services\Nodes\NodeUpdateService; -use App\Transformers\Api\Application\NodeTransformer; use Dedoc\Scramble\Attributes\Group; use Exception; use Illuminate\Http\JsonResponse; @@ -47,8 +47,8 @@ public function index(GetNodesRequest $request): array ->allowedSorts(['id', 'uuid', 'memory', 'disk', 'cpu']) ->paginate($request->query('per_page') ?? 50); - return $this->fractal->collection($nodes) - ->transformWith($this->getTransformer(NodeTransformer::class)) + return $this->response->collection($nodes) + ->transformWith(NodeData::class) ->toArray(); } @@ -61,8 +61,8 @@ public function index(GetNodesRequest $request): array */ public function view(GetNodeRequest $request, Node $node): array { - return $this->fractal->item($node) - ->transformWith($this->getTransformer(NodeTransformer::class)) + return $this->response->item($node) + ->transformWith(NodeData::class) ->toArray(); } @@ -78,8 +78,8 @@ public function store(StoreNodeRequest $request): JsonResponse { $node = Node::create($request->validated()); - return $this->fractal->item($node) - ->transformWith($this->getTransformer(NodeTransformer::class)) + return $this->response->item($node) + ->transformWith(NodeData::class) ->addMeta([ 'resource' => route('api.application.nodes.view', [ 'node' => $node->id, @@ -109,8 +109,8 @@ public function update(UpdateNodeRequest $request, Node $node): array report($exception); } - return $this->fractal->item($node) - ->transformWith($this->getTransformer(NodeTransformer::class)) + return $this->response->item($node) + ->transformWith(NodeData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php b/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php index b61d079f98..e9559687a2 100644 --- a/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php +++ b/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php @@ -2,10 +2,10 @@ namespace App\Http\Controllers\Api\Application\Nodes; +use App\Data\Api\Application\NodeData; use App\Http\Controllers\Api\Application\ApplicationApiController; use App\Http\Requests\Api\Application\Nodes\GetDeployableNodesRequest; use App\Services\Deployment\FindViableNodesService; -use App\Transformers\Api\Application\NodeTransformer; use Dedoc\Scramble\Attributes\Group; #[Group('Node', weight: 2)] @@ -36,8 +36,8 @@ public function __invoke(GetDeployableNodesRequest $request): array $data['tags'] ?? $data['location_ids'] ?? [], ); - return $this->fractal->collection($nodes) - ->transformWith($this->getTransformer(NodeTransformer::class)) + return $this->response->collection($nodes) + ->transformWith(NodeData::class) ->toArray(); } } diff --git a/app/Http/Controllers/Api/Application/Plugins/PluginController.php b/app/Http/Controllers/Api/Application/Plugins/PluginController.php index ed921f4e91..3542c68f2f 100644 --- a/app/Http/Controllers/Api/Application/Plugins/PluginController.php +++ b/app/Http/Controllers/Api/Application/Plugins/PluginController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Application\Plugins; +use App\Data\Api\Application\PluginData; use App\Enums\PluginStatus; use App\Exceptions\PanelException; use App\Http\Controllers\Api\Application\ApplicationApiController; @@ -11,7 +12,6 @@ use App\Http\Requests\Api\Application\Plugins\WritePluginRequest; use App\Models\Plugin; use App\Services\Helpers\PluginService; -use App\Transformers\Api\Application\PluginTransformer; use Exception; use Illuminate\Http\Response; use Spatie\QueryBuilder\QueryBuilder; @@ -40,8 +40,8 @@ public function index(ReadPluginRequest $request): array ->allowedSorts(['id', 'name', 'author', 'category']) ->paginate($request->query('per_page') ?? 10); - return $this->fractal->collection($plugins) - ->transformWith($this->getTransformer(PluginTransformer::class)) + return $this->response->collection($plugins) + ->transformWith(PluginData::class) ->toArray(); } @@ -54,8 +54,8 @@ public function index(ReadPluginRequest $request): array */ public function view(ReadPluginRequest $request, Plugin $plugin): array { - return $this->fractal->item($plugin) - ->transformWith($this->getTransformer(PluginTransformer::class)) + return $this->response->item($plugin) + ->transformWith(PluginData::class) ->toArray(); } @@ -104,8 +104,8 @@ public function install(WritePluginRequest $request, Plugin $plugin): array $this->pluginService->installPlugin($plugin); - return $this->fractal->item($plugin) - ->transformWith($this->getTransformer(PluginTransformer::class)) + return $this->response->item($plugin) + ->transformWith(PluginData::class) ->toArray(); } @@ -124,8 +124,8 @@ public function update(WritePluginRequest $request, Plugin $plugin): array $this->pluginService->updatePlugin($plugin); - return $this->fractal->item($plugin) - ->transformWith($this->getTransformer(PluginTransformer::class)) + return $this->response->item($plugin) + ->transformWith(PluginData::class) ->toArray(); } @@ -144,8 +144,8 @@ public function uninstall(UninstallPluginRequest $request, Plugin $plugin): arra $this->pluginService->uninstallPlugin($plugin, $request->boolean('delete')); - return $this->fractal->item($plugin) - ->transformWith($this->getTransformer(PluginTransformer::class)) + return $this->response->item($plugin) + ->transformWith(PluginData::class) ->toArray(); } @@ -164,8 +164,8 @@ public function enable(WritePluginRequest $request, Plugin $plugin): array $this->pluginService->enablePlugin($plugin); - return $this->fractal->item($plugin) - ->transformWith($this->getTransformer(PluginTransformer::class)) + return $this->response->item($plugin) + ->transformWith(PluginData::class) ->toArray(); } @@ -184,8 +184,8 @@ public function disable(WritePluginRequest $request, Plugin $plugin): array $this->pluginService->disablePlugin($plugin); - return $this->fractal->item($plugin) - ->transformWith($this->getTransformer(PluginTransformer::class)) + return $this->response->item($plugin) + ->transformWith(PluginData::class) ->toArray(); } } diff --git a/app/Http/Controllers/Api/Application/Roles/RoleController.php b/app/Http/Controllers/Api/Application/Roles/RoleController.php index 076279d980..033ea3255a 100644 --- a/app/Http/Controllers/Api/Application/Roles/RoleController.php +++ b/app/Http/Controllers/Api/Application/Roles/RoleController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Application\Roles; +use App\Data\Api\Application\RoleData; use App\Exceptions\PanelException; use App\Http\Controllers\Api\Application\ApplicationApiController; use App\Http\Requests\Api\Application\Roles\DeleteRoleRequest; @@ -9,7 +10,6 @@ use App\Http\Requests\Api\Application\Roles\StoreRoleRequest; use App\Http\Requests\Api\Application\Roles\UpdateRoleRequest; use App\Models\Role; -use App\Transformers\Api\Application\RoleTransformer; use Exception; use Illuminate\Http\JsonResponse; use Illuminate\Http\Response; @@ -32,8 +32,8 @@ public function index(GetRoleRequest $request): array ->allowedSorts(['id', 'name']) ->paginate($request->query('per_page') ?? 10); - return $this->fractal->collection($roles) - ->transformWith($this->getTransformer(RoleTransformer::class)) + return $this->response->collection($roles) + ->transformWith(RoleData::class) ->toArray(); } @@ -46,8 +46,8 @@ public function index(GetRoleRequest $request): array */ public function view(GetRoleRequest $request, Role $role): array { - return $this->fractal->item($role) - ->transformWith($this->getTransformer(RoleTransformer::class)) + return $this->response->item($role) + ->transformWith(RoleData::class) ->toArray(); } @@ -63,8 +63,8 @@ public function store(StoreRoleRequest $request): JsonResponse { $role = Role::create($request->validated()); - return $this->fractal->item($role) - ->transformWith($this->getTransformer(RoleTransformer::class)) + return $this->response->item($role) + ->transformWith(RoleData::class) ->addMeta([ 'resource' => route('api.application.roles.view', [ 'role' => $role->id, @@ -88,8 +88,8 @@ public function update(UpdateRoleRequest $request, Role $role): array $role->update($request->validated()); - return $this->fractal->item($role) - ->transformWith($this->getTransformer(RoleTransformer::class)) + return $this->response->item($role) + ->transformWith(RoleData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Application/Servers/DatabaseController.php b/app/Http/Controllers/Api/Application/Servers/DatabaseController.php index f65c420bbb..cc7a140ed3 100644 --- a/app/Http/Controllers/Api/Application/Servers/DatabaseController.php +++ b/app/Http/Controllers/Api/Application/Servers/DatabaseController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Application\Servers; +use App\Data\Api\Application\ServerDatabaseData; use App\Http\Controllers\Api\Application\ApplicationApiController; use App\Http\Requests\Api\Application\Servers\Databases\GetServerDatabaseRequest; use App\Http\Requests\Api\Application\Servers\Databases\GetServerDatabasesRequest; @@ -10,7 +11,6 @@ use App\Models\Database; use App\Models\Server; use App\Services\Databases\DatabaseManagementService; -use App\Transformers\Api\Application\ServerDatabaseTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Http\JsonResponse; use Illuminate\Http\Response; @@ -37,8 +37,8 @@ public function __construct( */ public function index(GetServerDatabasesRequest $request, Server $server): array { - return $this->fractal->collection($server->databases) - ->transformWith($this->getTransformer(ServerDatabaseTransformer::class)) + return $this->response->collection($server->databases) + ->transformWith(ServerDatabaseData::class) ->toArray(); } @@ -51,8 +51,8 @@ public function index(GetServerDatabasesRequest $request, Server $server): array */ public function view(GetServerDatabaseRequest $request, Server $server, Database $database): array { - return $this->fractal->item($database) - ->transformWith($this->getTransformer(ServerDatabaseTransformer::class)) + return $this->response->item($database) + ->transformWith(ServerDatabaseData::class) ->toArray(); } @@ -83,8 +83,8 @@ public function store(StoreServerDatabaseRequest $request, Server $server): Json 'database' => $request->databaseName(), ])); - return $this->fractal->item($database) - ->transformWith($this->getTransformer(ServerDatabaseTransformer::class)) + return $this->response->item($database) + ->transformWith(ServerDatabaseData::class) ->addMeta([ 'resource' => route('api.application.servers.databases.view', [ 'server' => $server->id, diff --git a/app/Http/Controllers/Api/Application/Servers/ExternalServerController.php b/app/Http/Controllers/Api/Application/Servers/ExternalServerController.php index 0130212a63..a48c0860fc 100644 --- a/app/Http/Controllers/Api/Application/Servers/ExternalServerController.php +++ b/app/Http/Controllers/Api/Application/Servers/ExternalServerController.php @@ -2,10 +2,10 @@ namespace App\Http\Controllers\Api\Application\Servers; +use App\Data\Api\Application\ServerData; use App\Http\Controllers\Api\Application\ApplicationApiController; use App\Http\Requests\Api\Application\Servers\GetExternalServerRequest; use App\Models\Server; -use App\Transformers\Api\Application\ServerTransformer; use Dedoc\Scramble\Attributes\Group; #[Group('Server', weight: 1)] @@ -22,8 +22,8 @@ public function index(GetExternalServerRequest $request, string $external_id): a { $server = Server::query()->where('external_id', $external_id)->firstOrFail(); - return $this->fractal->item($server) - ->transformWith($this->getTransformer(ServerTransformer::class)) + return $this->response->item($server) + ->transformWith(ServerData::class) ->toArray(); } } diff --git a/app/Http/Controllers/Api/Application/Servers/ServerController.php b/app/Http/Controllers/Api/Application/Servers/ServerController.php index 096f034467..84b7c40100 100644 --- a/app/Http/Controllers/Api/Application/Servers/ServerController.php +++ b/app/Http/Controllers/Api/Application/Servers/ServerController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Application\Servers; +use App\Data\Api\Application\ServerData; use App\Exceptions\DisplayException; use App\Exceptions\Model\DataValidationException; use App\Exceptions\Service\Deployment\NoViableAllocationException; @@ -13,7 +14,6 @@ use App\Models\Server; use App\Services\Servers\ServerCreationService; use App\Services\Servers\ServerDeletionService; -use App\Transformers\Api\Application\ServerTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Http\JsonResponse; use Illuminate\Http\Response; @@ -48,8 +48,8 @@ public function index(GetServersRequest $request): array ->allowedSorts(['id', 'uuid']) ->paginate($request->query('per_page') ?? 50); - return $this->fractal->collection($servers) - ->transformWith($this->getTransformer(ServerTransformer::class)) + return $this->response->collection($servers) + ->transformWith(ServerData::class) ->toArray(); } @@ -68,8 +68,8 @@ public function store(StoreServerRequest $request): JsonResponse { $server = $this->creationService->handle($request->validated(), $request->getDeploymentObject()); - return $this->fractal->item($server) - ->transformWith($this->getTransformer(ServerTransformer::class)) + return $this->response->item($server) + ->transformWith(ServerData::class) ->respond(201); } @@ -82,8 +82,8 @@ public function store(StoreServerRequest $request): JsonResponse */ public function view(GetServerRequest $request, Server $server): array { - return $this->fractal->item($server) - ->transformWith($this->getTransformer(ServerTransformer::class)) + return $this->response->item($server) + ->transformWith(ServerData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Application/Servers/ServerDetailsController.php b/app/Http/Controllers/Api/Application/Servers/ServerDetailsController.php index f5aaede210..0928cd6c0e 100644 --- a/app/Http/Controllers/Api/Application/Servers/ServerDetailsController.php +++ b/app/Http/Controllers/Api/Application/Servers/ServerDetailsController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Application\Servers; +use App\Data\Api\Application\ServerData; use App\Exceptions\DisplayException; use App\Exceptions\Model\DataValidationException; use App\Http\Controllers\Api\Application\ApplicationApiController; @@ -10,7 +11,6 @@ use App\Models\Server; use App\Services\Servers\BuildModificationService; use App\Services\Servers\DetailsModificationService; -use App\Transformers\Api\Application\ServerTransformer; use Dedoc\Scramble\Attributes\Group; #[Group('Server', weight: 2)] @@ -46,8 +46,8 @@ public function details(UpdateServerDetailsRequest $request, Server $server): ar $validated, ); - return $this->fractal->item($updated) - ->transformWith($this->getTransformer(ServerTransformer::class)) + return $this->response->item($updated) + ->transformWith(ServerData::class) ->toArray(); } @@ -65,8 +65,8 @@ public function build(UpdateServerBuildConfigurationRequest $request, Server $se { $server = $this->buildModificationService->handle($server, $request->validated()); - return $this->fractal->item($server) - ->transformWith($this->getTransformer(ServerTransformer::class)) + return $this->response->item($server) + ->transformWith(ServerData::class) ->toArray(); } } diff --git a/app/Http/Controllers/Api/Application/Servers/StartupController.php b/app/Http/Controllers/Api/Application/Servers/StartupController.php index 68d8bcf88d..7538d056e8 100644 --- a/app/Http/Controllers/Api/Application/Servers/StartupController.php +++ b/app/Http/Controllers/Api/Application/Servers/StartupController.php @@ -2,13 +2,13 @@ namespace App\Http\Controllers\Api\Application\Servers; +use App\Data\Api\Application\ServerData; use App\Exceptions\Model\DataValidationException; use App\Http\Controllers\Api\Application\ApplicationApiController; use App\Http\Requests\Api\Application\Servers\UpdateServerStartupRequest; use App\Models\Server; use App\Models\User; use App\Services\Servers\StartupModificationService; -use App\Transformers\Api\Application\ServerTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Http\Client\ConnectionException; use Illuminate\Validation\ValidationException; @@ -41,8 +41,8 @@ public function index(UpdateServerStartupRequest $request, Server $server): arra ->setUserLevel(User::USER_LEVEL_ADMIN) ->handle($server, $request->validated()); - return $this->fractal->item($server) - ->transformWith($this->getTransformer(ServerTransformer::class)) + return $this->response->item($server) + ->transformWith(ServerData::class) ->toArray(); } } diff --git a/app/Http/Controllers/Api/Application/Users/ExternalUserController.php b/app/Http/Controllers/Api/Application/Users/ExternalUserController.php index c376c5cb4e..de1915cb42 100644 --- a/app/Http/Controllers/Api/Application/Users/ExternalUserController.php +++ b/app/Http/Controllers/Api/Application/Users/ExternalUserController.php @@ -2,10 +2,10 @@ namespace App\Http\Controllers\Api\Application\Users; +use App\Data\Api\Application\UserData; use App\Http\Controllers\Api\Application\ApplicationApiController; use App\Http\Requests\Api\Application\Users\GetExternalUserRequest; use App\Models\User; -use App\Transformers\Api\Application\UserTransformer; use Dedoc\Scramble\Attributes\Group; #[Group('User', weight: 1)] @@ -22,8 +22,8 @@ public function index(GetExternalUserRequest $request, string $externalId): arra { $user = User::query()->where('external_id', $externalId)->firstOrFail(); - return $this->fractal->item($user) - ->transformWith($this->getTransformer(UserTransformer::class)) + return $this->response->item($user) + ->transformWith(UserData::class) ->toArray(); } } diff --git a/app/Http/Controllers/Api/Application/Users/UserController.php b/app/Http/Controllers/Api/Application/Users/UserController.php index 6a3b722180..3667064661 100644 --- a/app/Http/Controllers/Api/Application/Users/UserController.php +++ b/app/Http/Controllers/Api/Application/Users/UserController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Application\Users; +use App\Data\Api\Application\UserData; use App\Exceptions\Model\DataValidationException; use App\Http\Controllers\Api\Application\ApplicationApiController; use App\Http\Requests\Api\Application\Users\AssignUserRolesRequest; @@ -13,7 +14,6 @@ use App\Models\User; use App\Services\Users\UserCreationService; use App\Services\Users\UserUpdateService; -use App\Transformers\Api\Application\UserTransformer; use Dedoc\Scramble\Attributes\Group; use Exception; use Illuminate\Http\JsonResponse; @@ -48,8 +48,8 @@ public function index(GetUsersRequest $request): array ->allowedSorts(['id', 'uuid']) ->paginate($request->query('per_page') ?? 50); - return $this->fractal->collection($users) - ->transformWith($this->getTransformer(UserTransformer::class)) + return $this->response->collection($users) + ->transformWith(UserData::class) ->toArray(); } @@ -63,8 +63,8 @@ public function index(GetUsersRequest $request): array */ public function view(GetUsersRequest $request, User $user): array { - return $this->fractal->item($user) - ->transformWith($this->getTransformer(UserTransformer::class)) + return $this->response->item($user) + ->transformWith(UserData::class) ->toArray(); } @@ -87,8 +87,8 @@ public function update(UpdateUserRequest $request, User $user): array $this->updateService->setUserLevel(User::USER_LEVEL_ADMIN); $user = $this->updateService->handle($user, $request->validated()); - $response = $this->fractal->item($user) - ->transformWith($this->getTransformer(UserTransformer::class)); + $response = $this->response->item($user) + ->transformWith(UserData::class); return $response->toArray(); } @@ -113,8 +113,8 @@ public function assignRoles(AssignUserRolesRequest $request, User $user): array } } - $response = $this->fractal->item($user) - ->transformWith($this->getTransformer(UserTransformer::class)); + $response = $this->response->item($user) + ->transformWith(UserData::class); return $response->toArray(); } @@ -139,8 +139,8 @@ public function removeRoles(AssignUserRolesRequest $request, User $user): array } } - $response = $this->fractal->item($user) - ->transformWith($this->getTransformer(UserTransformer::class)); + $response = $this->response->item($user) + ->transformWith(UserData::class); return $response->toArray(); } @@ -158,8 +158,8 @@ public function store(StoreUserRequest $request): JsonResponse { $user = $this->creationService->handle($request->validated()); - return $this->fractal->item($user) - ->transformWith($this->getTransformer(UserTransformer::class)) + return $this->response->item($user) + ->transformWith(UserData::class) ->addMeta([ 'resource' => route('api.application.users.view', [ 'user' => $user->id, diff --git a/app/Http/Controllers/Api/Client/AccountController.php b/app/Http/Controllers/Api/Client/AccountController.php index 645a55fb0e..884923ff5b 100644 --- a/app/Http/Controllers/Api/Client/AccountController.php +++ b/app/Http/Controllers/Api/Client/AccountController.php @@ -2,12 +2,12 @@ namespace App\Http\Controllers\Api\Client; +use App\Data\Api\Client\UserData; use App\Facades\Activity; use App\Http\Requests\Api\Client\Account\UpdateEmailRequest; use App\Http\Requests\Api\Client\Account\UpdatePasswordRequest; use App\Http\Requests\Api\Client\Account\UpdateUsernameRequest; use App\Services\Users\UserUpdateService; -use App\Transformers\Api\Client\UserTransformer; use Illuminate\Auth\AuthManager; use Illuminate\Auth\SessionGuard; use Illuminate\Http\JsonResponse; @@ -41,8 +41,8 @@ public function __construct(private AuthManager $manager, private UserUpdateServ */ public function index(Request $request): array { - return $this->fractal->item($request->user()) - ->transformWith($this->getTransformer(UserTransformer::class)) + return $this->response->item($request->user()) + ->transformWith(UserData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Client/ActivityLogController.php b/app/Http/Controllers/Api/Client/ActivityLogController.php index fdbd626343..7bac83c0f8 100644 --- a/app/Http/Controllers/Api/Client/ActivityLogController.php +++ b/app/Http/Controllers/Api/Client/ActivityLogController.php @@ -2,9 +2,9 @@ namespace App\Http\Controllers\Api\Client; +use App\Data\Api\Client\ActivityLogData; use App\Http\Requests\Api\Client\ClientApiRequest; use App\Models\ActivityLog; -use App\Transformers\Api\Client\ActivityLogTransformer; use Spatie\QueryBuilder\AllowedFilter; use Spatie\QueryBuilder\QueryBuilder; @@ -27,8 +27,8 @@ public function __invoke(ClientApiRequest $request): array ->paginate(min($request->query('per_page', '25'), 100)) ->appends($request->query()); - return $this->fractal->collection($activity) - ->transformWith($this->getTransformer(ActivityLogTransformer::class)) + return $this->response->collection($activity) + ->transformWith(ActivityLogData::class) ->toArray(); } } diff --git a/app/Http/Controllers/Api/Client/ApiKeyController.php b/app/Http/Controllers/Api/Client/ApiKeyController.php index e6c738bb9c..6f183143cd 100644 --- a/app/Http/Controllers/Api/Client/ApiKeyController.php +++ b/app/Http/Controllers/Api/Client/ApiKeyController.php @@ -2,12 +2,12 @@ namespace App\Http\Controllers\Api\Client; +use App\Data\Api\Client\ApiKeyData; use App\Exceptions\DisplayException; use App\Facades\Activity; use App\Http\Requests\Api\Client\Account\StoreApiKeyRequest; use App\Http\Requests\Api\Client\ClientApiRequest; use App\Models\ApiKey; -use App\Transformers\Api\Client\ApiKeyTransformer; use Illuminate\Http\JsonResponse; class ApiKeyController extends ClientApiController @@ -21,8 +21,8 @@ class ApiKeyController extends ClientApiController */ public function index(ClientApiRequest $request): array { - return $this->fractal->collection($request->user()->apiKeys) - ->transformWith($this->getTransformer(ApiKeyTransformer::class)) + return $this->response->collection($request->user()->apiKeys) + ->transformWith(ApiKeyData::class) ->toArray(); } @@ -49,8 +49,8 @@ public function store(StoreApiKeyRequest $request): array ->property('identifier', $token->accessToken->identifier) ->log(); - return $this->fractal->item($token->accessToken) - ->transformWith($this->getTransformer(ApiKeyTransformer::class)) + return $this->response->item($token->accessToken) + ->transformWith(ApiKeyData::class) ->addMeta(['secret_token' => $token->plainTextToken]) ->toArray(); } diff --git a/app/Http/Controllers/Api/Client/ClientController.php b/app/Http/Controllers/Api/Client/ClientController.php index 42327ca182..498f8b2ba8 100644 --- a/app/Http/Controllers/Api/Client/ClientController.php +++ b/app/Http/Controllers/Api/Client/ClientController.php @@ -2,11 +2,11 @@ namespace App\Http\Controllers\Api\Client; +use App\Data\Api\Client\ServerData; use App\Http\Requests\Api\Client\GetServersRequest; use App\Models\Filters\MultiFieldServerFilter; use App\Models\Server; use App\Models\Subuser; -use App\Transformers\Api\Client\ServerTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; @@ -35,10 +35,12 @@ public function __construct() public function index(GetServersRequest $request): array { $user = $request->user(); - $transformer = $this->getTransformer(ServerTransformer::class); + + // Only eager load the relationships that map to includes the resource honors. + $includes = array_values(array_intersect($this->parseIncludes(), ServerData::$availableIncludes)); /** @var Builder $query */ - $query = Server::query()->with($this->getIncludesForTransformer($transformer, ['node'])); + $query = Server::query()->with(array_merge($includes, ['node'])); // Start the query builder and ensure we eager load any requested relationships from the request. $builder = QueryBuilder::for($query)->allowedFilters([ @@ -72,7 +74,7 @@ public function index(GetServersRequest $request): array $servers = $builder->paginate(min($request->query('per_page', '50'), 100))->appends($request->query()); - return $this->fractal->transformWith($transformer)->collection($servers)->toArray(); + return $this->response->transformWith(ServerData::class)->collection($servers)->toArray(); } /** diff --git a/app/Http/Controllers/Api/Client/SSHKeyController.php b/app/Http/Controllers/Api/Client/SSHKeyController.php index 445c2c7b84..93f40ab532 100644 --- a/app/Http/Controllers/Api/Client/SSHKeyController.php +++ b/app/Http/Controllers/Api/Client/SSHKeyController.php @@ -2,11 +2,11 @@ namespace App\Http\Controllers\Api\Client; +use App\Data\Api\Client\UserSSHKeyData; use App\Facades\Activity; use App\Http\Requests\Api\Client\Account\StoreSSHKeyRequest; use App\Http\Requests\Api\Client\ClientApiRequest; use App\Models\UserSSHKey; -use App\Transformers\Api\Client\UserSSHKeyTransformer; use Illuminate\Http\JsonResponse; class SSHKeyController extends ClientApiController @@ -20,8 +20,8 @@ class SSHKeyController extends ClientApiController */ public function index(ClientApiRequest $request): array { - return $this->fractal->collection($request->user()->sshKeys) - ->transformWith($this->getTransformer(UserSSHKeyTransformer::class)) + return $this->response->collection($request->user()->sshKeys) + ->transformWith(UserSSHKeyData::class) ->toArray(); } @@ -45,8 +45,8 @@ public function store(StoreSSHKeyRequest $request): array ->property('fingerprint', $request->getKeyFingerprint()) ->log(); - return $this->fractal->item($model) - ->transformWith($this->getTransformer(UserSSHKeyTransformer::class)) + return $this->response->item($model) + ->transformWith(UserSSHKeyData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Client/Servers/ActivityLogController.php b/app/Http/Controllers/Api/Client/Servers/ActivityLogController.php index 4fcdf1e73f..ea383cca04 100644 --- a/app/Http/Controllers/Api/Client/Servers/ActivityLogController.php +++ b/app/Http/Controllers/Api/Client/Servers/ActivityLogController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Client\Servers; +use App\Data\Api\Client\ActivityLogData; use App\Enums\SubuserPermission; use App\Http\Controllers\Api\Client\ClientApiController; use App\Http\Requests\Api\Client\ClientApiRequest; @@ -9,7 +10,6 @@ use App\Models\Role; use App\Models\Server; use App\Models\User; -use App\Transformers\Api\Client\ActivityLogTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Query\JoinClause; @@ -56,8 +56,8 @@ public function __invoke(ClientApiRequest $request, Server $server): array ->paginate(min($request->query('per_page', '25'), 100)) ->appends($request->query()); - return $this->fractal->collection($activity) - ->transformWith($this->getTransformer(ActivityLogTransformer::class)) + return $this->response->collection($activity) + ->transformWith(ActivityLogData::class) ->toArray(); } } diff --git a/app/Http/Controllers/Api/Client/Servers/BackupController.php b/app/Http/Controllers/Api/Client/Servers/BackupController.php index 9419414f06..bd8ba88fd7 100644 --- a/app/Http/Controllers/Api/Client/Servers/BackupController.php +++ b/app/Http/Controllers/Api/Client/Servers/BackupController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Client\Servers; +use App\Data\Api\Client\BackupData; use App\Enums\ServerState; use App\Enums\SubuserPermission; use App\Extensions\BackupAdapter\BackupAdapterService; @@ -16,7 +17,6 @@ use App\Services\Backups\DeleteBackupService; use App\Services\Backups\DownloadLinkService; use App\Services\Backups\InitiateBackupService; -use App\Transformers\Api\Client\BackupTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Http\JsonResponse; @@ -54,8 +54,8 @@ public function index(Request $request, Server $server): array $limit = min($request->query('per_page') ?? 20, 50); - return $this->fractal->collection($server->backups()->paginate($limit)) - ->transformWith($this->getTransformer(BackupTransformer::class)) + return $this->response->collection($server->backups()->paginate($limit)) + ->transformWith(BackupData::class) ->addMeta([ 'backup_count' => $server->backups()->nonFailed()->count(), ]) @@ -99,8 +99,8 @@ public function store(StoreBackupRequest $request, Server $server): array return $backup; }); - return $this->fractal->item($backup) - ->transformWith($this->getTransformer(BackupTransformer::class)) + return $this->response->item($backup) + ->transformWith(BackupData::class) ->toArray(); } @@ -124,8 +124,8 @@ public function toggleLock(Request $request, Server $server, Backup $backup): ar Activity::event($action)->subject($backup)->property('name', $backup->name)->log(); - return $this->fractal->item($backup) - ->transformWith($this->getTransformer(BackupTransformer::class)) + return $this->response->item($backup) + ->transformWith(BackupData::class) ->toArray(); } @@ -142,8 +142,8 @@ public function view(Request $request, Server $server, Backup $backup): array { throw_unless($request->user()->can(SubuserPermission::BackupRead, $server), new AuthorizationException()); - return $this->fractal->item($backup) - ->transformWith($this->getTransformer(BackupTransformer::class)) + return $this->response->item($backup) + ->transformWith(BackupData::class) ->toArray(); } @@ -222,8 +222,8 @@ public function rename(RenameBackupRequest $request, Server $server, Backup $bac ->log(); } - return $this->fractal->item($backup) - ->transformWith($this->getTransformer(BackupTransformer::class)) + return $this->response->item($backup) + ->transformWith(BackupData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Client/Servers/DatabaseController.php b/app/Http/Controllers/Api/Client/Servers/DatabaseController.php index c741544410..1ce66c6b35 100644 --- a/app/Http/Controllers/Api/Client/Servers/DatabaseController.php +++ b/app/Http/Controllers/Api/Client/Servers/DatabaseController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Client\Servers; +use App\Data\Api\Client\DatabaseData; use App\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException; use App\Exceptions\Service\Database\TooManyDatabasesException; use App\Facades\Activity; @@ -14,7 +15,6 @@ use App\Models\Server; use App\Services\Databases\DatabaseManagementService; use App\Services\Databases\DeployServerDatabaseService; -use App\Transformers\Api\Client\DatabaseTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Http\Response; use Throwable; @@ -41,8 +41,8 @@ public function __construct( */ public function index(GetDatabasesRequest $request, Server $server): array { - return $this->fractal->collection($server->databases) - ->transformWith($this->getTransformer(DatabaseTransformer::class)) + return $this->response->collection($server->databases) + ->transformWith(DatabaseData::class) ->toArray(); } @@ -69,9 +69,9 @@ public function store(StoreDatabaseRequest $request, Server $server): array return $database; }); - return $this->fractal->item($database) + return $this->response->item($database) ->parseIncludes(['password']) - ->transformWith($this->getTransformer(DatabaseTransformer::class)) + ->transformWith(DatabaseData::class) ->toArray(); } @@ -92,9 +92,9 @@ public function rotatePassword(RotatePasswordRequest $request, Server $server, D ->property('name', $database->database) ->transaction(fn () => $this->managementService->rotatePassword($database)); - return $this->fractal->item($database->refresh()) + return $this->response->item($database->refresh()) ->parseIncludes(['password']) - ->transformWith($this->getTransformer(DatabaseTransformer::class)) + ->transformWith(DatabaseData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Client/Servers/FileController.php b/app/Http/Controllers/Api/Client/Servers/FileController.php index ecc1610eb9..2799b69d3e 100644 --- a/app/Http/Controllers/Api/Client/Servers/FileController.php +++ b/app/Http/Controllers/Api/Client/Servers/FileController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Client\Servers; +use App\Data\Api\Client\FileObjectData; use App\Enums\NodeJwtScope; use App\Facades\Activity; use App\Http\Controllers\Api\Client\ClientApiController; @@ -19,7 +20,6 @@ use App\Models\Server; use App\Repositories\Daemon\DaemonFileRepository; use App\Services\Nodes\NodeJWTService; -use App\Transformers\Api\Client\FileObjectTransformer; use Carbon\CarbonImmutable; use Dedoc\Scramble\Attributes\Group; use Illuminate\Http\Client\ConnectionException; @@ -55,8 +55,8 @@ public function directory(ListFilesRequest $request, Server $server): array ->setServer($server) ->getDirectory($request->get('directory') ?? '/'); - return $this->fractal->collection($contents) - ->transformWith($this->getTransformer(FileObjectTransformer::class)) + return $this->response->collection($contents) + ->transformWith(FileObjectData::class) ->toArray(); } @@ -227,8 +227,8 @@ public function compress(CompressFilesRequest $request, Server $server): array ->property('files', $request->input('files')) ->log(); - return $this->fractal->item($file) - ->transformWith($this->getTransformer(FileObjectTransformer::class)) + return $this->response->item($file) + ->transformWith(FileObjectData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php b/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php index 8f43e0028a..1f47627486 100644 --- a/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php +++ b/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Client\Servers; +use App\Data\Api\Client\AllocationData; use App\Exceptions\DisplayException; use App\Exceptions\Model\DataValidationException; use App\Facades\Activity; @@ -14,7 +15,6 @@ use App\Models\Allocation; use App\Models\Server; use App\Services\Allocations\FindAssignableAllocationService; -use App\Transformers\Api\Client\AllocationTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Http\JsonResponse; @@ -40,8 +40,8 @@ public function __construct( */ public function index(GetNetworkRequest $request, Server $server): array { - return $this->fractal->collection($server->allocations) - ->transformWith($this->getTransformer(AllocationTransformer::class)) + return $this->response->collection($server->allocations) + ->transformWith(AllocationData::class) ->toArray(); } @@ -67,8 +67,8 @@ public function update(UpdateAllocationRequest $request, Server $server, Allocat ->log(); } - return $this->fractal->item($allocation) - ->transformWith($this->getTransformer(AllocationTransformer::class)) + return $this->response->item($allocation) + ->transformWith(AllocationData::class) ->toArray(); } @@ -91,8 +91,8 @@ public function setPrimary(SetPrimaryAllocationRequest $request, Server $server, ->property('allocation', $allocation->address) ->log(); - return $this->fractal->item($allocation) - ->transformWith($this->getTransformer(AllocationTransformer::class)) + return $this->response->item($allocation) + ->transformWith(AllocationData::class) ->toArray(); } @@ -119,8 +119,8 @@ public function store(NewAllocationRequest $request, Server $server): array return $allocation; }); - return $this->fractal->item($allocation) - ->transformWith($this->getTransformer(AllocationTransformer::class)) + return $this->response->item($allocation) + ->transformWith(AllocationData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Client/Servers/ResourceUtilizationController.php b/app/Http/Controllers/Api/Client/Servers/ResourceUtilizationController.php index f731c7967d..d0da7cec30 100644 --- a/app/Http/Controllers/Api/Client/Servers/ResourceUtilizationController.php +++ b/app/Http/Controllers/Api/Client/Servers/ResourceUtilizationController.php @@ -2,11 +2,11 @@ namespace App\Http\Controllers\Api\Client\Servers; +use App\Data\Api\Client\StatsData; use App\Http\Controllers\Api\Client\ClientApiController; use App\Http\Requests\Api\Client\Servers\GetServerRequest; use App\Models\Server; use App\Repositories\Daemon\DaemonServerRepository; -use App\Transformers\Api\Client\StatsTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Cache\Repository; use Illuminate\Http\Client\ConnectionException; @@ -41,8 +41,8 @@ public function __invoke(GetServerRequest $request, Server $server): array return $this->repository->setServer($server)->getDetails(); }); - return $this->fractal->item($stats) - ->transformWith($this->getTransformer(StatsTransformer::class)) + return $this->response->item($stats) + ->transformWith(StatsData::class) ->toArray(); } } diff --git a/app/Http/Controllers/Api/Client/Servers/ScheduleController.php b/app/Http/Controllers/Api/Client/Servers/ScheduleController.php index 2a270c60b3..d1b595aa51 100644 --- a/app/Http/Controllers/Api/Client/Servers/ScheduleController.php +++ b/app/Http/Controllers/Api/Client/Servers/ScheduleController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Client\Servers; +use App\Data\Api\Client\ScheduleData; use App\Exceptions\DisplayException; use App\Exceptions\Model\DataValidationException; use App\Facades\Activity; @@ -15,7 +16,6 @@ use App\Models\Schedule; use App\Models\Server; use App\Services\Schedules\ProcessScheduleService; -use App\Transformers\Api\Client\ScheduleTransformer; use Dedoc\Scramble\Attributes\Group; use Exception; use Illuminate\Http\JsonResponse; @@ -47,8 +47,8 @@ public function index(ViewScheduleRequest $request, Server $server): array { $schedules = $server->schedules->loadMissing('tasks'); - return $this->fractal->collection($schedules) - ->transformWith($this->getTransformer(ScheduleTransformer::class)) + return $this->response->collection($schedules) + ->transformWith(ScheduleData::class) ->toArray(); } @@ -83,8 +83,8 @@ public function store(StoreScheduleRequest $request, Server $server): array ->property('name', $model->name) ->log(); - return $this->fractal->item($model) - ->transformWith($this->getTransformer(ScheduleTransformer::class)) + return $this->response->item($model) + ->transformWith(ScheduleData::class) ->toArray(); } @@ -101,8 +101,8 @@ public function view(ViewScheduleRequest $request, Server $server, Schedule $sch $schedule->loadMissing('tasks'); - return $this->fractal->item($schedule) - ->transformWith($this->getTransformer(ScheduleTransformer::class)) + return $this->response->item($schedule) + ->transformWith(ScheduleData::class) ->toArray(); } @@ -145,8 +145,8 @@ public function update(UpdateScheduleRequest $request, Server $server, Schedule ->property(['name' => $schedule->name, 'active' => $active]) ->log(); - return $this->fractal->item($schedule->refresh()) - ->transformWith($this->getTransformer(ScheduleTransformer::class)) + return $this->response->item($schedule->refresh()) + ->transformWith(ScheduleData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Client/Servers/ScheduleTaskController.php b/app/Http/Controllers/Api/Client/Servers/ScheduleTaskController.php index 085588343b..5241cd622b 100644 --- a/app/Http/Controllers/Api/Client/Servers/ScheduleTaskController.php +++ b/app/Http/Controllers/Api/Client/Servers/ScheduleTaskController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Client\Servers; +use App\Data\Api\Client\TaskData; use App\Enums\SubuserPermission; use App\Exceptions\Http\HttpForbiddenException; use App\Exceptions\Model\DataValidationException; @@ -13,7 +14,6 @@ use App\Models\Schedule; use App\Models\Server; use App\Models\Task; -use App\Transformers\Api\Client\TaskTransformer; use Dedoc\Scramble\Attributes\Group; use Exception; use Illuminate\Database\ConnectionInterface; @@ -89,8 +89,8 @@ public function store(StoreTaskRequest $request, Server $server, Schedule $sched ->property(['name' => $schedule->name, 'action' => $task->action, 'payload' => $task->payload]) ->log(); - return $this->fractal->item($task) - ->transformWith($this->getTransformer(TaskTransformer::class)) + return $this->response->item($task) + ->transformWith(TaskData::class) ->toArray(); } @@ -143,8 +143,8 @@ public function update(StoreTaskRequest $request, Server $server, Schedule $sche ->property(['name' => $schedule->name, 'action' => $task->action, 'payload' => $task->payload]) ->log(); - return $this->fractal->item($task->refresh()) - ->transformWith($this->getTransformer(TaskTransformer::class)) + return $this->response->item($task->refresh()) + ->transformWith(TaskData::class) ->toArray(); } diff --git a/app/Http/Controllers/Api/Client/Servers/ServerController.php b/app/Http/Controllers/Api/Client/Servers/ServerController.php index b524c59bca..2a98bf40b3 100644 --- a/app/Http/Controllers/Api/Client/Servers/ServerController.php +++ b/app/Http/Controllers/Api/Client/Servers/ServerController.php @@ -2,11 +2,11 @@ namespace App\Http\Controllers\Api\Client\Servers; +use App\Data\Api\Client\ServerData; use App\Http\Controllers\Api\Client\ClientApiController; use App\Http\Requests\Api\Client\Servers\GetServerRequest; use App\Models\Server; use App\Services\Servers\GetUserPermissionsService; -use App\Transformers\Api\Client\ServerTransformer; use Dedoc\Scramble\Attributes\Group; #[Group('Server', weight: 0)] @@ -26,8 +26,8 @@ public function __construct(private GetUserPermissionsService $permissionsServic */ public function index(GetServerRequest $request, Server $server): array { - return $this->fractal->item($server) - ->transformWith($this->getTransformer(ServerTransformer::class)) + return $this->response->item($server) + ->transformWith(ServerData::class) ->addMeta([ 'is_server_owner' => $request->user()->id === $server->owner_id, 'user_permissions' => $this->permissionsService->handle($server, $request->user()), diff --git a/app/Http/Controllers/Api/Client/Servers/StartupController.php b/app/Http/Controllers/Api/Client/Servers/StartupController.php index 89e59d7139..75b44eca98 100644 --- a/app/Http/Controllers/Api/Client/Servers/StartupController.php +++ b/app/Http/Controllers/Api/Client/Servers/StartupController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Client\Servers; +use App\Data\Api\Client\EggVariableData; use App\Exceptions\Model\DataValidationException; use App\Facades\Activity; use App\Http\Controllers\Api\Client\ClientApiController; @@ -10,7 +11,6 @@ use App\Models\Server; use App\Models\ServerVariable; use App\Services\Servers\StartupCommandService; -use App\Transformers\Api\Client\EggVariableTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Validation\ValidationException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; @@ -38,10 +38,10 @@ public function index(GetStartupRequest $request, Server $server): array { $startup = $this->startupCommandService->handle($server); - return $this->fractal->collection( + return $this->response->collection( $server->variables()->where('user_viewable', true)->orderBy('sort')->get() ) - ->transformWith($this->getTransformer(EggVariableTransformer::class)) + ->transformWith(EggVariableData::class) ->addMeta([ 'startup_command' => $startup, 'docker_images' => $server->egg->docker_images, @@ -96,8 +96,8 @@ public function update(UpdateStartupVariableRequest $request, Server $server): a ->log(); } - return $this->fractal->item($variable) - ->transformWith($this->getTransformer(EggVariableTransformer::class)) + return $this->response->item($variable) + ->transformWith(EggVariableData::class) ->addMeta([ 'startup_command' => $startup, 'raw_startup_command' => $server->startup, diff --git a/app/Http/Controllers/Api/Client/Servers/SubuserController.php b/app/Http/Controllers/Api/Client/Servers/SubuserController.php index 2a19a35a98..14d92199e6 100644 --- a/app/Http/Controllers/Api/Client/Servers/SubuserController.php +++ b/app/Http/Controllers/Api/Client/Servers/SubuserController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Client\Servers; +use App\Data\Api\Client\SubuserData; use App\Enums\SubuserPermission; use App\Exceptions\Model\DataValidationException; use App\Exceptions\Service\Subuser\ServerSubuserExistsException; @@ -18,7 +19,6 @@ use App\Services\Subusers\SubuserCreationService; use App\Services\Subusers\SubuserDeletionService; use App\Services\Subusers\SubuserUpdateService; -use App\Transformers\Api\Client\SubuserTransformer; use Dedoc\Scramble\Attributes\Group; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -47,8 +47,8 @@ public function __construct( */ public function index(GetSubuserRequest $request, Server $server): array { - return $this->fractal->collection($server->subusers) - ->transformWith($this->getTransformer(SubuserTransformer::class)) + return $this->response->collection($server->subusers) + ->transformWith(SubuserData::class) ->toArray(); } @@ -63,8 +63,8 @@ public function view(GetSubuserRequest $request, Server $server, User $user): ar { $subuser = $request->attributes->get('subuser'); - return $this->fractal->item($subuser) - ->transformWith($this->getTransformer(SubuserTransformer::class)) + return $this->response->item($subuser) + ->transformWith(SubuserData::class) ->toArray(); } @@ -92,8 +92,8 @@ public function store(StoreSubuserRequest $request, Server $server): array ->property(['email' => $email, 'permissions' => $subuser->permissions]) ->log(); - return $this->fractal->item($subuser) - ->transformWith($this->getTransformer(SubuserTransformer::class)) + return $this->response->item($subuser) + ->transformWith(SubuserData::class) ->toArray(); } @@ -113,8 +113,8 @@ public function update(UpdateSubuserRequest $request, Server $server, User $user $this->updateService->handle($subuser, $server, $this->getCleanedPermissions($request)); - return $this->fractal->item($subuser->refresh()) - ->transformWith($this->getTransformer(SubuserTransformer::class)) + return $this->response->item($subuser->refresh()) + ->transformWith(SubuserData::class) ->toArray(); }