vito/app/Http/Controllers/API/ServerController.php
2025-03-12 13:31:10 +01:00

132 lines
5.7 KiB
PHP

<?php
namespace App\Http\Controllers\API;
use App\Actions\Server\CreateServer;
use App\Actions\Server\RebootServer;
use App\Actions\Server\Update;
use App\Enums\Database;
use App\Enums\PHP;
use App\Enums\ServerProvider;
use App\Enums\Webserver;
use App\Http\Controllers\Controller;
use App\Http\Resources\ServerResource;
use App\Models\Project;
use App\Models\Server;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Knuckles\Scribe\Attributes\BodyParam;
use Knuckles\Scribe\Attributes\Endpoint;
use Knuckles\Scribe\Attributes\Group;
use Knuckles\Scribe\Attributes\Response;
use Knuckles\Scribe\Attributes\ResponseFromApiResource;
use Spatie\RouteAttributes\Attributes\Delete;
use Spatie\RouteAttributes\Attributes\Get;
use Spatie\RouteAttributes\Attributes\Middleware;
use Spatie\RouteAttributes\Attributes\Post;
use Spatie\RouteAttributes\Attributes\Prefix;
#[Prefix('api/projects/{project}/servers')]
#[Middleware(['auth:sanctum', 'can-see-project'])]
#[Group(name: 'servers')]
class ServerController extends Controller
{
#[Get('/', name: 'api.projects.servers', middleware: 'ability:read')]
#[Endpoint(title: 'list', description: 'Get all servers in a project.')]
#[ResponseFromApiResource(ServerResource::class, Server::class, collection: true, paginate: 25)]
public function index(Project $project): ResourceCollection
{
$this->authorize('viewAny', [Server::class, $project]);
return ServerResource::collection($project->servers()->simplePaginate(25));
}
#[Post('/', name: 'api.projects.servers.create', middleware: 'ability:write')]
#[Endpoint(title: 'create', description: 'Create a new server.')]
#[BodyParam(name: 'provider', description: 'The server provider type', required: true)]
#[BodyParam(name: 'server_provider', description: 'If the provider is not custom, the ID of the server provider profile', enum: [ServerProvider::CUSTOM, ServerProvider::HETZNER, ServerProvider::DIGITALOCEAN, ServerProvider::LINODE, ServerProvider::VULTR])]
#[BodyParam(name: 'region', description: 'Provider region if the provider is not custom')]
#[BodyParam(name: 'plan', description: 'Provider plan if the provider is not custom')]
#[BodyParam(name: 'ip', description: 'SSH IP address if the provider is custom')]
#[BodyParam(name: 'port', description: 'SSH Port if the provider is custom')]
#[BodyParam(name: 'name', description: 'The name of the server.', required: true)]
#[BodyParam(name: 'os', description: 'The os of the server', required: true)]
#[BodyParam(name: 'webserver', description: 'Web server', required: true, enum: [Webserver::NONE, Webserver::NGINX])]
#[BodyParam(name: 'database', description: 'Database', required: true, enum: [Database::NONE, Database::MYSQL57, Database::MYSQL80, Database::MARIADB103, Database::MARIADB104, Database::MARIADB103, Database::POSTGRESQL12, Database::POSTGRESQL13, Database::POSTGRESQL14, Database::POSTGRESQL15, Database::POSTGRESQL16], )]
#[BodyParam(name: 'php', description: 'PHP version', required: true, enum: [PHP::V70, PHP::V71, PHP::V72, PHP::V73, PHP::V74, PHP::V80, PHP::V81, PHP::V82, PHP::V83])]
#[ResponseFromApiResource(ServerResource::class, Server::class)]
public function create(Request $request, Project $project): ServerResource
{
$this->authorize('create', [Server::class, $project]);
$this->validate($request, CreateServer::rules($project, $request->input()));
/** @var \App\Models\User $user */
$user = auth()->user();
$server = app(CreateServer::class)->create($user, $project, $request->all());
return new ServerResource($server);
}
#[Get('{server}', name: 'api.projects.servers.show', middleware: 'ability:read')]
#[Endpoint(title: 'show', description: 'Get a server by ID.')]
#[ResponseFromApiResource(ServerResource::class, Server::class)]
public function show(Project $project, Server $server): ServerResource
{
$this->authorize('view', [$server, $project]);
$this->validateRoute($project, $server);
return new ServerResource($server);
}
#[Post('{server}/reboot', name: 'api.projects.servers.reboot', middleware: 'ability:write')]
#[Endpoint(title: 'reboot', description: 'Reboot a server.')]
#[Response(status: 204)]
public function reboot(Project $project, Server $server): \Illuminate\Http\Response
{
$this->authorize('update', [$server, $project]);
$this->validateRoute($project, $server);
app(RebootServer::class)->reboot($server);
return response()->noContent();
}
#[Post('{server}/upgrade', name: 'api.projects.servers.upgrade', middleware: 'ability:write')]
#[Endpoint(title: 'upgrade', description: 'Upgrade server.')]
#[Response(status: 204)]
public function upgrade(Project $project, Server $server): \Illuminate\Http\Response
{
$this->authorize('update', [$server, $project]);
$this->validateRoute($project, $server);
app(Update::class)->update($server);
return response()->noContent();
}
#[Delete('{server}', name: 'api.projects.servers.delete', middleware: 'ability:write')]
#[Endpoint(title: 'delete', description: 'Delete server.')]
#[Response(status: 204)]
public function delete(Project $project, Server $server): \Illuminate\Http\Response
{
$this->authorize('delete', [$server, $project]);
$this->validateRoute($project, $server);
$server->delete();
return response()->noContent();
}
private function validateRoute(Project $project, Server $server): void
{
if ($project->id !== $server->project_id) {
abort(404, 'Server not found in project');
}
}
}