openapi work work

This commit is contained in:
Andras Bacsai 2024-07-09 10:45:10 +02:00
parent 9c821e2480
commit 2d3a6a4528
20 changed files with 2602 additions and 72 deletions

View File

@ -17,6 +17,7 @@ use App\Models\Server;
use App\Models\Service; use App\Models\Service;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use OpenApi\Attributes as OA;
use Symfony\Component\Yaml\Yaml; use Symfony\Component\Yaml\Yaml;
use Visus\Cuid2\Cuid2; use Visus\Cuid2\Cuid2;
@ -48,6 +49,37 @@ class ApplicationsController extends Controller
return serializeApiResponse($application); return serializeApiResponse($application);
} }
#[OA\Get(
summary: 'List',
description: 'List all applications.',
path: '/applications',
security: [
['bearerAuth' => []],
],
tags: ['Applications'],
responses: [
new OA\Response(
response: 200,
description: 'Get all applications.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'array',
items: new OA\Items(ref: '#/components/schemas/Application')
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function applications(Request $request) public function applications(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -95,9 +127,114 @@ class ApplicationsController extends Controller
$this->create_application($request, 'dockercompose'); $this->create_application($request, 'dockercompose');
} }
#[OA\Post(
summary: 'Create',
description: 'Create new application.',
path: '/applications',
security: [
['bearerAuth' => []],
],
tags: ['Applications'],
requestBody: new OA\RequestBody(
description: 'Application object that needs to be created.',
required: true,
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'object',
required: ['type', 'project_uuid', 'server_uuid', 'environment_name'],
properties: [
'type' => ['type' => 'string', 'enum' => ['public', 'private-gh-app', 'private-deploy-key', 'dockerfile', 'docker-image', 'dockercompose']],
'project_uuid' => ['type' => 'string'],
'server_uuid' => ['type' => 'string'],
'environment_name' => ['type' => 'string'],
'destination_uuid' => ['type' => 'string'],
'name' => ['type' => 'string'],
'description' => ['type' => 'string'],
'is_static' => ['type' => 'boolean'],
'domains' => ['type' => 'string'],
'git_repository' => ['type' => 'string'],
'git_branch' => ['type' => 'string'],
'git_commit_sha' => ['type' => 'string'],
'docker_registry_image_name' => ['type' => 'string'],
'docker_registry_image_tag' => ['type' => 'string'],
'build_pack' => ['type' => 'string'],
'install_command' => ['type' => 'string'],
'build_command' => ['type' => 'string'],
'start_command' => ['type' => 'string'],
'ports_exposes' => ['type' => 'string'],
'ports_mappings' => ['type' => 'string'],
'base_directory' => ['type' => 'string'],
'publish_directory' => ['type' => 'string'],
'health_check_enabled' => ['type' => 'boolean'],
'health_check_path' => ['type' => 'string'],
'health_check_port' => ['type' => 'integer'],
'health_check_host' => ['type' => 'string'],
'health_check_method' => ['type' => 'string'],
'health_check_return_code' => ['type' => 'integer'],
'health_check_scheme' => ['type' => 'string'],
'health_check_response_text' => ['type' => 'string'],
'health_check_interval' => ['type' => 'integer'],
'health_check_timeout' => ['type' => 'integer'],
'health_check_retries' => ['type' => 'integer'],
'health_check_start_period' => ['type' => 'integer'],
'limits_memory' => ['type' => 'string'],
'limits_memory_swap' => ['type' => 'string'],
'limits_memory_swappiness' => ['type' => 'integer'],
'limits_memory_reservation' => ['type' => 'string'],
'limits_cpus' => ['type' => 'string'],
'limits_cpuset' => ['type' => 'string'],
'limits_cpu_shares' => ['type' => 'string'],
'custom_labels' => ['type' => 'string'],
'custom_docker_run_options' => ['type' => 'string'],
'post_deployment_command' => ['type' => 'string'],
'post_deployment_command_container' => ['type' => 'string'],
'pre_deployment_command' => ['type' => 'string'],
'pre_deployment_command_container' => ['type' => 'string'],
'manual_webhook_secret_github' => ['type' => 'string'],
'manual_webhook_secret_gitlab' => ['type' => 'string'],
'manual_webhook_secret_bitbucket' => ['type' => 'string'],
'manual_webhook_secret_gitea' => ['type' => 'string'],
'redirect' => ['type' => 'string'],
'github_app_uuid' => ['type' => 'string'],
'instant_deploy' => ['type' => 'boolean'],
'dockerfile' => ['type' => 'string'],
'docker_compose_location' => ['type' => 'string'],
'docker_compose_raw' => ['type' => 'string'],
'docker_compose_custom_start_command' => ['type' => 'string'],
'docker_compose_custom_build_command' => ['type' => 'string'],
'docker_compose_domains' => ['type' => 'array'],
'watch_paths' => ['type' => 'string'],
],
)),
]),
responses: [
new OA\Response(
response: 200,
description: 'Get all applications.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'array',
items: new OA\Items(ref: '#/components/schemas/Application')
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
private function create_application(Request $request, $type) private function create_application(Request $request, $type)
{ {
$allowedFields = ['project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'redirect', 'github_app_uuid', 'instant_deploy', 'dockerfile', 'docker_compose_location', 'docker_compose', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'watch_paths']; $allowedFields = ['project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'redirect', 'github_app_uuid', 'instant_deploy', 'dockerfile', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'watch_paths'];
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
if (is_null($teamId)) { if (is_null($teamId)) {
return invalidTokenResponse(); return invalidTokenResponse();
@ -167,7 +304,6 @@ class ApplicationsController extends Controller
'build_pack' => ['required', Rule::enum(BuildPackTypes::class)], 'build_pack' => ['required', Rule::enum(BuildPackTypes::class)],
'ports_exposes' => 'string|regex:/^(\d+)(,\d+)*$/|required', 'ports_exposes' => 'string|regex:/^(\d+)(,\d+)*$/|required',
'docker_compose_location' => 'string', 'docker_compose_location' => 'string',
'docker_compose' => 'string|nullable',
'docker_compose_raw' => 'string|nullable', 'docker_compose_raw' => 'string|nullable',
'docker_compose_domains' => 'array|nullable', 'docker_compose_domains' => 'array|nullable',
'docker_compose_custom_start_command' => 'string|nullable', 'docker_compose_custom_start_command' => 'string|nullable',
@ -243,7 +379,6 @@ class ApplicationsController extends Controller
'github_app_uuid' => 'string|required', 'github_app_uuid' => 'string|required',
'watch_paths' => 'string|nullable', 'watch_paths' => 'string|nullable',
'docker_compose_location' => 'string', 'docker_compose_location' => 'string',
'docker_compose' => 'string|nullable',
'docker_compose_raw' => 'string|nullable', 'docker_compose_raw' => 'string|nullable',
'docker_compose_domains' => 'array|nullable', 'docker_compose_domains' => 'array|nullable',
'docker_compose_custom_start_command' => 'string|nullable', 'docker_compose_custom_start_command' => 'string|nullable',
@ -335,7 +470,6 @@ class ApplicationsController extends Controller
'private_key_uuid' => 'string|required', 'private_key_uuid' => 'string|required',
'watch_paths' => 'string|nullable', 'watch_paths' => 'string|nullable',
'docker_compose_location' => 'string', 'docker_compose_location' => 'string',
'docker_compose' => 'string|nullable',
'docker_compose_raw' => 'string|nullable', 'docker_compose_raw' => 'string|nullable',
'docker_compose_domains' => 'array|nullable', 'docker_compose_domains' => 'array|nullable',
'docker_compose_custom_start_command' => 'string|nullable', 'docker_compose_custom_start_command' => 'string|nullable',
@ -626,6 +760,52 @@ class ApplicationsController extends Controller
} }
#[OA\Get(
summary: 'Get',
description: 'Get application by UUID.',
path: '/applications/{uuid}',
security: [
['bearerAuth' => []],
],
tags: ['Applications'],
parameters: [
new OA\Parameter(
name: 'uuid',
in: 'path',
description: 'UUID of the application.',
required: true,
schema: new OA\Schema(
type: 'string',
format: 'uuid',
)
),
],
responses: [
new OA\Response(
response: 200,
description: 'Get all applications.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
ref: '#/components/schemas/Application'
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
new OA\Response(
response: 404,
ref: '#/components/responses/404',
),
]
)]
public function application_by_uuid(Request $request) public function application_by_uuid(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -695,7 +875,7 @@ class ApplicationsController extends Controller
], 404); ], 404);
} }
$server = $application->destination->server; $server = $application->destination->server;
$allowedFields = ['name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'static_image', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'watch_paths', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'docker_compose_location', 'docker_compose', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect']; $allowedFields = ['name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'static_image', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'watch_paths', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect'];
$validator = customApiValidator($request->all(), [ $validator = customApiValidator($request->all(), [
sharedDataApplications(), sharedDataApplications(),
@ -704,7 +884,6 @@ class ApplicationsController extends Controller
'static_image' => 'string', 'static_image' => 'string',
'watch_paths' => 'string|nullable', 'watch_paths' => 'string|nullable',
'docker_compose_location' => 'string', 'docker_compose_location' => 'string',
'docker_compose' => 'string|nullable',
'docker_compose_raw' => 'string|nullable', 'docker_compose_raw' => 'string|nullable',
'docker_compose_domains' => 'array|nullable', 'docker_compose_domains' => 'array|nullable',
'docker_compose_custom_start_command' => 'string|nullable', 'docker_compose_custom_start_command' => 'string|nullable',

View File

@ -9,6 +9,7 @@ use App\Models\ApplicationDeploymentQueue;
use App\Models\Server; use App\Models\Server;
use App\Models\Tag; use App\Models\Tag;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use OpenApi\Attributes as OA;
use Visus\Cuid2\Cuid2; use Visus\Cuid2\Cuid2;
class DeployController extends Controller class DeployController extends Controller
@ -27,6 +28,38 @@ class DeployController extends Controller
return serializeApiResponse($deployment); return serializeApiResponse($deployment);
} }
#[OA\Get(
summary: 'List',
description: 'List currently running deployments',
path: '/deployments',
security: [
['bearerAuth' => []],
],
tags: ['Deployments'],
responses: [
new OA\Response(
response: 200,
description: 'Get all currently running deployments.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'array',
items: new OA\Items(ref: '#/components/schemas/ApplicationDeploymentQueue'),
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function deployments(Request $request) public function deployments(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -34,25 +67,7 @@ class DeployController extends Controller
return invalidTokenResponse(); return invalidTokenResponse();
} }
$servers = Server::whereTeamId($teamId)->get(); $servers = Server::whereTeamId($teamId)->get();
$deployments_per_server = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->whereIn('server_id', $servers->pluck('id'))->get([ $deployments_per_server = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->whereIn('server_id', $servers->pluck('id'))->get()->sortBy('id');
'deployment_uuid',
'commit',
'commit_message',
'application_id',
'application_name',
'deployment_url',
'pull_request_id',
'server_name',
'server_id',
'status',
'is_api',
'is_webhook',
'restart_only',
'force_rebuild',
'rollback',
'created_at',
'updated_at',
])->sortBy('id');
$deployments_per_server = $deployments_per_server->map(function ($deployment) { $deployments_per_server = $deployments_per_server->map(function ($deployment) {
return $this->removeSensitiveData($deployment); return $this->removeSensitiveData($deployment);
}); });
@ -60,6 +75,43 @@ class DeployController extends Controller
return response()->json($deployments_per_server); return response()->json($deployments_per_server);
} }
#[OA\Get(
summary: 'Get',
description: 'Get deployment by UUID.',
path: '/deployments/{uuid}',
security: [
['bearerAuth' => []],
],
tags: ['Deployments'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Deployment Uuid', schema: new OA\Schema(type: 'integer')),
],
responses: [
new OA\Response(
response: 200,
description: 'Get deployment by UUID.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
ref: '#/components/schemas/ApplicationDeploymentQueue',
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
new OA\Response(
response: 404,
ref: '#/components/responses/404',
),
]
)]
public function deployment_by_uuid(Request $request) public function deployment_by_uuid(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -70,26 +122,7 @@ class DeployController extends Controller
if (! $uuid) { if (! $uuid) {
return response()->json(['message' => 'UUID is required.'], 400); return response()->json(['message' => 'UUID is required.'], 400);
} }
$deployment = ApplicationDeploymentQueue::where('deployment_uuid', $uuid)->first([ $deployment = ApplicationDeploymentQueue::where('deployment_uuid', $uuid)->first();
'deployment_uuid',
'commit',
'commit_message',
'application_id',
'application_name',
'deployment_url',
'pull_request_id',
'server_name',
'server_id',
'logs',
'status',
'is_api',
'is_webhook',
'restart_only',
'force_rebuild',
'rollback',
'created_at',
'updated_at',
]);
if (! $deployment) { if (! $deployment) {
return response()->json(['message' => 'Deployment not found.'], 404); return response()->json(['message' => 'Deployment not found.'], 404);
} }
@ -97,6 +130,57 @@ class DeployController extends Controller
return response()->json($this->removeSensitiveData($deployment)); return response()->json($this->removeSensitiveData($deployment));
} }
#[OA\Get(
summary: 'Deploy',
description: 'Deploy by tag or uuid. `Post` request also accepted.',
path: '/deploy',
security: [
['bearerAuth' => []],
],
tags: ['Deployments'],
parameters: [
new OA\Parameter(name: 'tag', in: 'query', description: 'Tag name(s). Comma separated list is also accepted.', schema: new OA\Schema(type: 'string')),
new OA\Parameter(name: 'uuid', in: 'query', description: 'Resource UUID(s). Comma separated list is also accepted.', schema: new OA\Schema(type: 'string')),
new OA\Parameter(name: 'force', in: 'query', description: 'Force rebuild (without cache)', schema: new OA\Schema(type: 'boolean')),
],
responses: [
new OA\Response(
response: 200,
description: 'Get deployment(s) Uuid\'s',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'object',
properties: [
'deployments' => new OA\Property(
property: 'deployments',
type: 'array',
items: new OA\Items(
type: 'object',
properties: [
'message' => ['type' => 'string'],
'resource_uuid' => ['type' => 'string'],
'deployment_uuid' => ['type' => 'string'],
]
),
),
],
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function deploy(Request $request) public function deploy(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();

View File

@ -13,15 +13,6 @@ use OpenApi\Attributes as OA;
description: 'Go to `Keys & Tokens` / `API tokens` and create a new token. Use the token as the bearer token.')] description: 'Go to `Keys & Tokens` / `API tokens` and create a new token. Use the token as the bearer token.')]
#[OA\Components( #[OA\Components(
responses: [ responses: [
new OA\Response(
response: 401,
description: 'Unauthenticated.',
content: new OA\JsonContent(
type: 'object',
properties: [
new OA\Property(property: 'message', type: 'string', example: 'Unauthenticated.'),
]
)),
new OA\Response( new OA\Response(
response: 400, response: 400,
description: 'Invalid token.', description: 'Invalid token.',
@ -31,13 +22,22 @@ use OpenApi\Attributes as OA;
new OA\Property(property: 'message', type: 'string', example: 'Invalid token.'), new OA\Property(property: 'message', type: 'string', example: 'Invalid token.'),
] ]
)), )),
new OA\Response(
response: 401,
description: 'Unauthenticated.',
content: new OA\JsonContent(
type: 'object',
properties: [
new OA\Property(property: 'message', type: 'string', example: 'Unauthenticated.'),
]
)),
new OA\Response( new OA\Response(
response: 404, response: 404,
description: 'Resource not found.', description: 'Resource not found.',
content: new OA\JsonContent( content: new OA\JsonContent(
type: 'object', type: 'object',
properties: [ properties: [
new OA\Property(property: 'message', type: 'string'), new OA\Property(property: 'message', type: 'string', example: 'Resource not found.'),
] ]
)), )),
], ],

View File

@ -159,9 +159,6 @@ class OtherController extends Controller
summary: 'Healthcheck', summary: 'Healthcheck',
description: 'Healthcheck endpoint.', description: 'Healthcheck endpoint.',
path: '/healthcheck', path: '/healthcheck',
security: [
['bearerAuth' => []],
],
responses: [ responses: [
new OA\Response( new OA\Response(
response: 200, response: 200,

View File

@ -5,9 +5,41 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Project; use App\Models\Project;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use OpenApi\Attributes as OA;
class ProjectController extends Controller class ProjectController extends Controller
{ {
#[OA\Get(
summary: 'List',
description: 'list projects.',
path: '/projects',
security: [
['bearerAuth' => []],
],
tags: ['Projects'],
responses: [
new OA\Response(
response: 200,
description: 'Get all projects.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'array',
items: new OA\Items(ref: '#/components/schemas/Project')
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function projects(Request $request) public function projects(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -20,6 +52,36 @@ class ProjectController extends Controller
); );
} }
#[OA\Get(
summary: 'Get',
description: 'Get project by Uuid.',
path: '/projects/{uuid}',
security: [
['bearerAuth' => []],
],
tags: ['Projects'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Project UUID', schema: new OA\Schema(type: 'integer')),
],
responses: [
new OA\Response(
response: 200,
description: 'Project details',
content: new OA\JsonContent(ref: '#/components/schemas/Project')),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
new OA\Response(
response: 404,
description: 'Project not found.',
),
]
)]
public function project_by_uuid(Request $request) public function project_by_uuid(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -36,6 +98,37 @@ class ProjectController extends Controller
); );
} }
#[OA\Get(
summary: 'Environment',
description: 'Get environment by name.',
path: '/projects/{uuid}/{environment_name}',
security: [
['bearerAuth' => []],
],
tags: ['Projects'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Project UUID', schema: new OA\Schema(type: 'integer')),
new OA\Parameter(name: 'environment_name', in: 'path', required: true, description: 'Environment name', schema: new OA\Schema(type: 'string')),
],
responses: [
new OA\Response(
response: 200,
description: 'Project details',
content: new OA\JsonContent(ref: '#/components/schemas/Environment')),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
new OA\Response(
response: 404,
ref: '#/components/responses/404',
),
]
)]
public function environment_details(Request $request) public function environment_details(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();

View File

@ -5,9 +5,37 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Project; use App\Models\Project;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use OpenApi\Attributes as OA;
class ResourcesController extends Controller class ResourcesController extends Controller
{ {
#[OA\Get(
summary: 'List',
description: 'Get all resources.',
path: '/resources',
security: [
['bearerAuth' => []],
],
tags: ['Resources'],
responses: [
new OA\Response(
response: 200,
description: 'Get all resources',
content: new OA\JsonContent(
type: 'string',
example: 'Content is very complex. Will be implemented later.',
),
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function resources(Request $request) public function resources(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();

View File

@ -5,9 +5,54 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\PrivateKey; use App\Models\PrivateKey;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use OpenApi\Attributes as OA;
class SecurityController extends Controller class SecurityController extends Controller
{ {
private function removeSensitiveData($team)
{
$token = auth()->user()->currentAccessToken();
if ($token->can('view:sensitive')) {
return serializeApiResponse($team);
}
$team->makeHidden([
'private_key',
]);
return serializeApiResponse($team);
}
#[OA\Get(
summary: 'List',
description: 'List all private keys.',
path: '/security/keys',
security: [
['bearerAuth' => []],
],
tags: ['Private Keys'],
responses: [
new OA\Response(
response: 200,
description: 'Get all private keys.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'array',
items: new OA\Items(ref: '#/components/schemas/PrivateKey')
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function keys(Request $request) public function keys(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -16,9 +61,47 @@ class SecurityController extends Controller
} }
$keys = PrivateKey::where('team_id', $teamId)->get(); $keys = PrivateKey::where('team_id', $teamId)->get();
return response()->json(serializeApiResponse($keys)); return response()->json($this->removeSensitiveData($keys));
} }
#[OA\Get(
summary: 'Get',
description: 'Get key by UUID.',
path: '/security/keys/{uuid}',
security: [
['bearerAuth' => []],
],
tags: ['Private Keys'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Private Key Uuid', schema: new OA\Schema(type: 'integer')),
],
responses: [
new OA\Response(
response: 200,
description: 'Get all private keys.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'array',
items: new OA\Items(ref: '#/components/schemas/PrivateKey')
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
new OA\Response(
response: 404,
description: 'Private Key not found.',
),
]
)]
public function key_by_uuid(Request $request) public function key_by_uuid(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -34,9 +117,60 @@ class SecurityController extends Controller
], 404); ], 404);
} }
return response()->json(serializeApiResponse($key)); return response()->json($this->removeSensitiveData($key));
} }
#[OA\Post(
summary: 'Create',
description: 'Create a new private key.',
path: '/security/keys',
security: [
['bearerAuth' => []],
],
tags: ['Private Keys'],
requestBody: new OA\RequestBody(
required: true,
content: [
'application/json' => new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'object',
required: ['private_key'],
properties: [
'name' => ['type' => 'string'],
'description' => ['type' => 'string'],
'private_key' => ['type' => 'string'],
],
additionalProperties: false,
)
),
]
),
responses: [
new OA\Response(
response: 201,
description: 'The created private key\'s UUID.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'object',
properties: [
'uuid' => ['type' => 'string'],
]
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function create_key(Request $request) public function create_key(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -79,6 +213,57 @@ class SecurityController extends Controller
]))->setStatusCode(201); ]))->setStatusCode(201);
} }
#[OA\Patch(
summary: 'Update',
description: 'Update a private key.',
path: '/security/keys',
security: [
['bearerAuth' => []],
],
tags: ['Private Keys'],
requestBody: new OA\RequestBody(
required: true,
content: [
'application/json' => new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'object',
required: ['private_key'],
properties: [
'name' => ['type' => 'string'],
'description' => ['type' => 'string'],
'private_key' => ['type' => 'string'],
],
additionalProperties: false,
)
),
]
),
responses: [
new OA\Response(
response: 201,
description: 'The updated private key\'s UUID.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'object',
properties: [
'uuid' => ['type' => 'string'],
]
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function update_key(Request $request) public function update_key(Request $request)
{ {
$allowedFields = ['name', 'description', 'private_key']; $allowedFields = ['name', 'description', 'private_key'];
@ -124,6 +309,46 @@ class SecurityController extends Controller
]))->setStatusCode(201); ]))->setStatusCode(201);
} }
#[OA\Delete(
summary: 'Delete',
description: 'Delete a private key.',
path: '/security/keys/{uuid}',
security: [
['bearerAuth' => []],
],
tags: ['Private Keys'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Private Key Uuid', schema: new OA\Schema(type: 'integer')),
],
responses: [
new OA\Response(
response: 200,
description: 'Private Key deleted.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'object',
properties: [
'message' => ['type' => 'string', 'example' => 'Private Key deleted.'],
]
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
new OA\Response(
response: 404,
description: 'Private Key not found.',
),
]
)]
public function delete_key(Request $request) public function delete_key(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();

View File

@ -8,6 +8,7 @@ use App\Models\InstanceSettings;
use App\Models\Project; use App\Models\Project;
use App\Models\Server as ModelsServer; use App\Models\Server as ModelsServer;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use OpenApi\Attributes as OA;
use Stringable; use Stringable;
class ServersController extends Controller class ServersController extends Controller
@ -38,6 +39,37 @@ class ServersController extends Controller
return serializeApiResponse($server); return serializeApiResponse($server);
} }
#[OA\Get(
summary: 'List',
description: 'List all servers.',
path: '/servers',
security: [
['bearerAuth' => []],
],
tags: ['Servers'],
responses: [
new OA\Response(
response: 200,
description: 'Get all servers.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'array',
items: new OA\Items(ref: '#/components/schemas/Server')
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function servers(Request $request) public function servers(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -61,6 +93,43 @@ class ServersController extends Controller
return response()->json($servers); return response()->json($servers);
} }
#[OA\Get(
summary: 'Get',
description: 'Get server by UUID.',
path: '/servers/{uuid}',
security: [
['bearerAuth' => []],
],
tags: ['Servers'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'integer')),
],
responses: [
new OA\Response(
response: 200,
description: 'Get server by UUID',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
ref: '#/components/schemas/Server'
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
new OA\Response(
response: 404,
ref: '#/components/responses/404',
),
]
)]
public function server_by_uuid(Request $request) public function server_by_uuid(Request $request)
{ {
$with_resources = $request->query('resources'); $with_resources = $request->query('resources');
@ -101,6 +170,50 @@ class ServersController extends Controller
return response()->json(serializeApiResponse($server)); return response()->json(serializeApiResponse($server));
} }
#[OA\Get(
summary: 'Resources',
description: 'Get resources by server.',
path: '/servers/{uuid}/resources',
security: [
['bearerAuth' => []],
],
tags: ['Servers'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'integer')),
],
responses: [
new OA\Response(
response: 200,
description: 'Get resources by server',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'array',
items: new OA\Items(
type: 'object',
properties: [
'id' => ['type' => 'integer'],
'uuid' => ['type' => 'string'],
'name' => ['type' => 'string'],
'type' => ['type' => 'string'],
'created_at' => ['type' => 'string'],
'updated_at' => ['type' => 'string'],
'status' => ['type' => 'string'],
]
)
)),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function resources_by_server(Request $request) public function resources_by_server(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -134,6 +247,45 @@ class ServersController extends Controller
return response()->json(serializeApiResponse(data_get($server, 'resources'))); return response()->json(serializeApiResponse(data_get($server, 'resources')));
} }
#[OA\Get(
summary: 'Domains',
description: 'Get domains by server.',
path: '/servers/{uuid}/domains',
security: [
['bearerAuth' => []],
],
tags: ['Servers'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'integer')),
],
responses: [
new OA\Response(
response: 200,
description: 'Get domains by server',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'array',
items: new OA\Items(
type: 'object',
properties: [
'ip' => ['type' => 'string'],
'domains' => ['type' => 'array', 'items' => ['type' => 'string']],
]
)
)),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function domains_by_server(Request $request) public function domains_by_server(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();

View File

@ -125,6 +125,44 @@ class TeamController extends Controller
); );
} }
#[OA\Get(
summary: 'Members',
description: 'Get members by TeamId.',
path: '/teams/{id}/members',
security: [
['bearerAuth' => []],
],
tags: ['Teams'],
parameters: [
new OA\Parameter(name: 'id', in: 'path', required: true, description: 'Team ID', schema: new OA\Schema(type: 'integer')),
],
responses: [
new OA\Response(
response: 200,
description: 'List of members.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'array',
items: new OA\Items(ref: '#/components/schemas/User')
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
new OA\Response(
response: 404,
ref: '#/components/responses/404',
),
]
)]
public function members_by_id(Request $request) public function members_by_id(Request $request)
{ {
$id = $request->id; $id = $request->id;
@ -147,6 +185,29 @@ class TeamController extends Controller
); );
} }
#[OA\Get(
summary: 'Authenticated Team',
description: 'Get currently authenticated team.',
path: '/teams/current',
security: [
['bearerAuth' => []],
],
tags: ['Teams'],
responses: [
new OA\Response(
response: 200,
description: 'Current Team.',
content: new OA\JsonContent(ref: '#/components/schemas/Team')),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function current_team(Request $request) public function current_team(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -156,10 +217,41 @@ class TeamController extends Controller
$team = auth()->user()->currentTeam(); $team = auth()->user()->currentTeam();
return response()->json( return response()->json(
serializeApiResponse($team), $this->removeSensitiveData($team),
); );
} }
#[OA\Get(
summary: 'Authenticated Team Members',
description: 'Get currently authenticated team members.',
path: '/teams/current/members',
security: [
['bearerAuth' => []],
],
tags: ['Teams'],
responses: [
new OA\Response(
response: 200,
description: 'Currently authenticated team members.',
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'array',
items: new OA\Items(ref: '#/components/schemas/User')
)
),
]),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
]
)]
public function current_team_members(Request $request) public function current_team_members(Request $request)
{ {
$teamId = getTeamIdFromToken(); $teamId = getTeamIdFromToken();
@ -167,6 +259,9 @@ class TeamController extends Controller
return invalidTokenResponse(); return invalidTokenResponse();
} }
$team = auth()->user()->currentTeam(); $team = auth()->user()->currentTeam();
$team->members->makeHidden([
'pivot',
]);
return response()->json( return response()->json(
serializeApiResponse($team->members), serializeApiResponse($team->members),

View File

@ -8,12 +8,96 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use OpenApi\Attributes as OA;
use RuntimeException; use RuntimeException;
use Spatie\Activitylog\Models\Activity; use Spatie\Activitylog\Models\Activity;
use Spatie\Url\Url; use Spatie\Url\Url;
use Symfony\Component\Yaml\Yaml; use Symfony\Component\Yaml\Yaml;
use Visus\Cuid2\Cuid2; use Visus\Cuid2\Cuid2;
#[OA\Schema(
description: 'Application model',
type: 'object',
properties: [
'id' => ['type' => 'integer'],
'repository_project_id' => ['type' => 'integer', 'nullable' => true],
'uuid' => ['type' => 'string'],
'name' => ['type' => 'string'],
'fqdn' => ['type' => 'string'],
'config_hash' => ['type' => 'string'],
'git_repository' => ['type' => 'string'],
'git_branch' => ['type' => 'string'],
'git_commit_sha' => ['type' => 'string'],
'git_full_url' => ['type' => 'string', 'nullable' => true],
'docker_registry_image_name' => ['type' => 'string', 'nullable' => true],
'docker_registry_image_tag' => ['type' => 'string', 'nullable' => true],
'build_pack' => ['type' => 'string'],
'static_image' => ['type' => 'string'],
'install_command' => ['type' => 'string'],
'build_command' => ['type' => 'string'],
'start_command' => ['type' => 'string'],
'ports_exposes' => ['type' => 'string'],
'ports_mappings' => ['type' => 'string', 'nullable' => true],
'base_directory' => ['type' => 'string'],
'publish_directory' => ['type' => 'string'],
'health_check_path' => ['type' => 'string'],
'health_check_port' => ['type' => 'string', 'nullable' => true],
'health_check_host' => ['type' => 'string'],
'health_check_method' => ['type' => 'string'],
'health_check_return_code' => ['type' => 'integer'],
'health_check_scheme' => ['type' => 'string'],
'health_check_response_text' => ['type' => 'string', 'nullable' => true],
'health_check_interval' => ['type' => 'integer'],
'health_check_timeout' => ['type' => 'integer'],
'health_check_retries' => ['type' => 'integer'],
'health_check_start_period' => ['type' => 'integer'],
'limits_memory' => ['type' => 'string'],
'limits_memory_swap' => ['type' => 'string'],
'limits_memory_swappiness' => ['type' => 'integer'],
'limits_memory_reservation' => ['type' => 'string'],
'limits_cpus' => ['type' => 'string'],
'limits_cpuset' => ['type' => 'string', 'nullable' => true],
'limits_cpu_shares' => ['type' => 'integer'],
'status' => ['type' => 'string'],
'preview_url_template' => ['type' => 'string'],
'destination_type' => ['type' => 'string'],
'destination_id' => ['type' => 'integer'],
'source_type' => ['type' => 'string'],
'source_id' => ['type' => 'integer'],
'private_key_id' => ['type' => 'integer', 'nullable' => true],
'environment_id' => ['type' => 'integer'],
'created_at' => ['type' => 'string', 'format' => 'date-time'],
'updated_at' => ['type' => 'string', 'format' => 'date-time'],
'description' => ['type' => 'string', 'nullable' => true],
'dockerfile' => ['type' => 'string', 'nullable' => true],
'health_check_enabled' => ['type' => 'boolean'],
'dockerfile_location' => ['type' => 'string'],
'custom_labels' => ['type' => 'string'],
'dockerfile_target_build' => ['type' => 'string', 'nullable' => true],
'manual_webhook_secret_github' => ['type' => 'string', 'nullable' => true],
'manual_webhook_secret_gitlab' => ['type' => 'string', 'nullable' => true],
'docker_compose_location' => ['type' => 'string'],
'docker_compose' => ['type' => 'string', 'nullable' => true],
'docker_compose_raw' => ['type' => 'string', 'nullable' => true],
'docker_compose_domains' => ['type' => 'string', 'nullable' => true],
'deleted_at' => ['type' => 'string', 'format' => 'date-time', 'nullable' => true],
'docker_compose_custom_start_command' => ['type' => 'string', 'nullable' => true],
'docker_compose_custom_build_command' => ['type' => 'string', 'nullable' => true],
'swarm_replicas' => ['type' => 'integer'],
'swarm_placement_constraints' => ['type' => 'string', 'nullable' => true],
'manual_webhook_secret_bitbucket' => ['type' => 'string', 'nullable' => true],
'custom_docker_run_options' => ['type' => 'string', 'nullable' => true],
'post_deployment_command' => ['type' => 'string', 'nullable' => true],
'post_deployment_command_container' => ['type' => 'string', 'nullable' => true],
'pre_deployment_command' => ['type' => 'string', 'nullable' => true],
'pre_deployment_command_container' => ['type' => 'string', 'nullable' => true],
'watch_paths' => ['type' => 'string', 'nullable' => true],
'custom_healthcheck_found' => ['type' => 'boolean'],
'manual_webhook_secret_gitea' => ['type' => 'string', 'nullable' => true],
'redirect' => ['type' => 'string'],
]
)]
class Application extends BaseModel class Application extends BaseModel
{ {
use SoftDeletes; use SoftDeletes;

View File

@ -4,7 +4,37 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use OpenApi\Attributes as OA;
#[OA\Schema(
description: 'Project model',
type: 'object',
properties: [
'id' => ['type' => 'integer'],
'application_id' => ['type' => 'string'],
'deployment_uuid' => ['type' => 'string'],
'pull_request_id' => ['type' => 'integer'],
'force_rebuild' => ['type' => 'boolean'],
'commit' => ['type' => 'string'],
'status' => ['type' => 'string'],
'is_webhook' => ['type' => 'boolean'],
'is_api' => ['type' => 'boolean'],
'created_at' => ['type' => 'string'],
'updated_at' => ['type' => 'string'],
'logs' => ['type' => 'string'],
'current_process_id' => ['type' => 'string'],
'restart_only' => ['type' => 'boolean'],
'git_type' => ['type' => 'string'],
'server_id' => ['type' => 'integer'],
'application_name' => ['type' => 'string'],
'server_name' => ['type' => 'string'],
'deployment_url' => ['type' => 'string'],
'destination_id' => ['type' => 'string'],
'only_this_server' => ['type' => 'boolean'],
'rollback' => ['type' => 'boolean'],
'commit_message' => ['type' => 'string'],
],
)]
class ApplicationDeploymentQueue extends Model class ApplicationDeploymentQueue extends Model
{ {
protected $guarded = []; protected $guarded = [];

View File

@ -4,7 +4,20 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use OpenApi\Attributes as OA;
#[OA\Schema(
description: 'Environment model',
type: 'object',
properties: [
'id' => ['type' => 'integer'],
'name' => ['type' => 'string'],
'project_id' => ['type' => 'integer'],
'created_at' => ['type' => 'string'],
'updated_at' => ['type' => 'string'],
'description' => ['type' => 'string'],
]
)]
class Environment extends Model class Environment extends Model
{ {
protected $guarded = []; protected $guarded = [];

View File

@ -2,8 +2,24 @@
namespace App\Models; namespace App\Models;
use OpenApi\Attributes as OA;
use phpseclib3\Crypt\PublicKeyLoader; use phpseclib3\Crypt\PublicKeyLoader;
#[OA\Schema(
description: 'Private Key model',
type: 'object',
properties: [
'id' => ['type' => 'integer'],
'uuid' => ['type' => 'string'],
'name' => ['type' => 'string'],
'description' => ['type' => 'string'],
'private_key' => ['type' => 'string', 'format' => 'private-key'],
'is_git_related' => ['type' => 'boolean'],
'team_id' => ['type' => 'integer'],
'created_at' => ['type' => 'string'],
'updated_at' => ['type' => 'string'],
],
)]
class PrivateKey extends BaseModel class PrivateKey extends BaseModel
{ {
protected $fillable = [ protected $fillable = [

View File

@ -2,6 +2,23 @@
namespace App\Models; namespace App\Models;
use OpenApi\Attributes as OA;
#[OA\Schema(
description: 'Project model',
type: 'object',
properties: [
'id' => ['type' => 'integer'],
'uuid' => ['type' => 'string'],
'name' => ['type' => 'string'],
'environments' => new OA\Property(
property: 'environments',
type: 'array',
items: new OA\Items(ref: '#/components/schemas/Environment'),
description: 'The environments of the project.'
),
]
)]
class Project extends BaseModel class Project extends BaseModel
{ {
protected $guarded = []; protected $guarded = [];

View File

@ -12,11 +12,95 @@ use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Process;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Stringable; use Illuminate\Support\Stringable;
use OpenApi\Attributes as OA;
use Spatie\SchemalessAttributes\Casts\SchemalessAttributes; use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
use Spatie\SchemalessAttributes\SchemalessAttributesTrait; use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
use Spatie\Url\Url; use Spatie\Url\Url;
use Symfony\Component\Yaml\Yaml; use Symfony\Component\Yaml\Yaml;
#[OA\Schema(
description: 'Application model',
type: 'object',
properties: [
'id' => ['type' => 'integer'],
'repository_project_id' => ['type' => 'integer', 'nullable' => true],
'uuid' => ['type' => 'string'],
'name' => ['type' => 'string'],
'fqdn' => ['type' => 'string'],
'config_hash' => ['type' => 'string'],
'git_repository' => ['type' => 'string'],
'git_branch' => ['type' => 'string'],
'git_commit_sha' => ['type' => 'string'],
'git_full_url' => ['type' => 'string', 'nullable' => true],
'docker_registry_image_name' => ['type' => 'string', 'nullable' => true],
'docker_registry_image_tag' => ['type' => 'string', 'nullable' => true],
'build_pack' => ['type' => 'string'],
'static_image' => ['type' => 'string'],
'install_command' => ['type' => 'string'],
'build_command' => ['type' => 'string'],
'start_command' => ['type' => 'string'],
'ports_exposes' => ['type' => 'string'],
'ports_mappings' => ['type' => 'string', 'nullable' => true],
'base_directory' => ['type' => 'string'],
'publish_directory' => ['type' => 'string'],
'health_check_path' => ['type' => 'string'],
'health_check_port' => ['type' => 'string', 'nullable' => true],
'health_check_host' => ['type' => 'string'],
'health_check_method' => ['type' => 'string'],
'health_check_return_code' => ['type' => 'integer'],
'health_check_scheme' => ['type' => 'string'],
'health_check_response_text' => ['type' => 'string', 'nullable' => true],
'health_check_interval' => ['type' => 'integer'],
'health_check_timeout' => ['type' => 'integer'],
'health_check_retries' => ['type' => 'integer'],
'health_check_start_period' => ['type' => 'integer'],
'limits_memory' => ['type' => 'string'],
'limits_memory_swap' => ['type' => 'string'],
'limits_memory_swappiness' => ['type' => 'integer'],
'limits_memory_reservation' => ['type' => 'string'],
'limits_cpus' => ['type' => 'string'],
'limits_cpuset' => ['type' => 'string', 'nullable' => true],
'limits_cpu_shares' => ['type' => 'integer'],
'status' => ['type' => 'string'],
'preview_url_template' => ['type' => 'string'],
'destination_type' => ['type' => 'string'],
'destination_id' => ['type' => 'integer'],
'source_type' => ['type' => 'string'],
'source_id' => ['type' => 'integer'],
'private_key_id' => ['type' => 'integer', 'nullable' => true],
'environment_id' => ['type' => 'integer'],
'created_at' => ['type' => 'string', 'format' => 'date-time'],
'updated_at' => ['type' => 'string', 'format' => 'date-time'],
'description' => ['type' => 'string', 'nullable' => true],
'dockerfile' => ['type' => 'string', 'nullable' => true],
'health_check_enabled' => ['type' => 'boolean'],
'dockerfile_location' => ['type' => 'string'],
'custom_labels' => ['type' => 'string'],
'dockerfile_target_build' => ['type' => 'string', 'nullable' => true],
'manual_webhook_secret_github' => ['type' => 'string', 'nullable' => true],
'manual_webhook_secret_gitlab' => ['type' => 'string', 'nullable' => true],
'docker_compose_location' => ['type' => 'string'],
'docker_compose' => ['type' => 'string', 'nullable' => true],
'docker_compose_raw' => ['type' => 'string', 'nullable' => true],
'docker_compose_domains' => ['type' => 'string', 'nullable' => true],
'deleted_at' => ['type' => 'string', 'format' => 'date-time', 'nullable' => true],
'docker_compose_custom_start_command' => ['type' => 'string', 'nullable' => true],
'docker_compose_custom_build_command' => ['type' => 'string', 'nullable' => true],
'swarm_replicas' => ['type' => 'integer'],
'swarm_placement_constraints' => ['type' => 'string', 'nullable' => true],
'manual_webhook_secret_bitbucket' => ['type' => 'string', 'nullable' => true],
'custom_docker_run_options' => ['type' => 'string', 'nullable' => true],
'post_deployment_command' => ['type' => 'string', 'nullable' => true],
'post_deployment_command_container' => ['type' => 'string', 'nullable' => true],
'pre_deployment_command' => ['type' => 'string', 'nullable' => true],
'pre_deployment_command_container' => ['type' => 'string', 'nullable' => true],
'watch_paths' => ['type' => 'string', 'nullable' => true],
'custom_healthcheck_found' => ['type' => 'boolean'],
'manual_webhook_secret_gitea' => ['type' => 'string', 'nullable' => true],
'redirect' => ['type' => 'string'],
]
)]
class Server extends BaseModel class Server extends BaseModel
{ {
use SchemalessAttributesTrait; use SchemalessAttributesTrait;

View File

@ -3,7 +3,46 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use OpenApi\Attributes as OA;
#[OA\Schema(
description: 'Server Settings model',
type: 'object',
properties: [
'id' => ['type' => 'integer'],
'cleanup_after_percentage' => ['type' => 'integer'],
'concurrent_builds' => ['type' => 'integer'],
'dynamic_timeout' => ['type' => 'integer'],
'force_disabled' => ['type' => 'boolean'],
'is_build_server' => ['type' => 'boolean'],
'is_cloudflare_tunnel' => ['type' => 'boolean'],
'is_jump_server' => ['type' => 'boolean'],
'is_logdrain_axiom_enabled' => ['type' => 'boolean'],
'is_logdrain_custom_enabled' => ['type' => 'boolean'],
'is_logdrain_highlight_enabled' => ['type' => 'boolean'],
'is_logdrain_newrelic_enabled' => ['type' => 'boolean'],
'is_metrics_enabled' => ['type' => 'boolean'],
'is_reachable' => ['type' => 'boolean'],
'is_server_api_enabled' => ['type' => 'boolean'],
'is_swarm_manager' => ['type' => 'boolean'],
'is_swarm_worker' => ['type' => 'boolean'],
'is_usable' => ['type' => 'boolean'],
'logdrain_axiom_api_key' => ['type' => 'string'],
'logdrain_axiom_dataset_name' => ['type' => 'string'],
'logdrain_custom_config' => ['type' => 'string'],
'logdrain_custom_config_parser' => ['type' => 'string'],
'logdrain_highlight_project_id' => ['type' => 'string'],
'logdrain_newrelic_base_uri' => ['type' => 'string'],
'logdrain_newrelic_license_key' => ['type' => 'string'],
'metrics_history_days' => ['type' => 'integer'],
'metrics_refresh_rate_seconds' => ['type' => 'integer'],
'metrics_token' => ['type' => 'string'],
'server_id' => ['type' => 'integer'],
'wildcard_domain' => ['type' => 'string'],
'created_at' => ['type' => 'string'],
'updated_at' => ['type' => 'string'],
]
)]
class ServerSetting extends Model class ServerSetting extends Model
{ {
protected $guarded = []; protected $guarded = [];

View File

@ -59,6 +59,12 @@ use OpenApi\Attributes as OA;
'custom_server_limit' => ['type' => 'string', 'description' => 'The custom server limit.'], 'custom_server_limit' => ['type' => 'string', 'description' => 'The custom server limit.'],
'telegram_notifications_scheduled_tasks' => ['type' => 'boolean', 'description' => 'Whether to send scheduled task notifications via Telegram.'], 'telegram_notifications_scheduled_tasks' => ['type' => 'boolean', 'description' => 'Whether to send scheduled task notifications via Telegram.'],
'telegram_notifications_scheduled_tasks_thread_id' => ['type' => 'string', 'description' => 'The Telegram scheduled task message thread ID.'], 'telegram_notifications_scheduled_tasks_thread_id' => ['type' => 'string', 'description' => 'The Telegram scheduled task message thread ID.'],
'members' => new OA\Property(
property: 'members',
type: 'array',
items: new OA\Items(ref: '#/components/schemas/User'),
description: 'The members of the team.'
),
] ]
)] )]
class Team extends Model implements SendsDiscord, SendsEmail class Team extends Model implements SendsDiscord, SendsEmail

View File

@ -17,7 +17,23 @@ use Illuminate\Support\Str;
use Laravel\Fortify\TwoFactorAuthenticatable; use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Sanctum\HasApiTokens; use Laravel\Sanctum\HasApiTokens;
use Laravel\Sanctum\NewAccessToken; use Laravel\Sanctum\NewAccessToken;
use OpenApi\Attributes as OA;
#[OA\Schema(
description: 'User model',
type: 'object',
properties: [
'id' => ['type' => 'integer'],
'name' => ['type' => 'string'],
'email' => ['type' => 'string'],
'email_verified_at' => ['type' => 'string'],
'created_at' => ['type' => 'string'],
'updated_at' => ['type' => 'string'],
'two_factor_confirmed_at' => ['type' => 'string'],
'force_password_reset' => ['type' => 'boolean'],
'marketing_emails' => ['type' => 'boolean'],
],
)]
class User extends Authenticatable implements SendsEmail class User extends Authenticatable implements SendsEmail
{ {
use HasApiTokens, HasFactory, Notifiable, TwoFactorAuthenticatable; use HasApiTokens, HasFactory, Notifiable, TwoFactorAuthenticatable;

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,6 @@ Route::group([
Route::delete('/security/keys/{uuid}', [SecurityController::class, 'delete_key'])->middleware([IgnoreReadOnlyApiToken::class]); Route::delete('/security/keys/{uuid}', [SecurityController::class, 'delete_key'])->middleware([IgnoreReadOnlyApiToken::class]);
Route::match(['get', 'post'], '/deploy', [DeployController::class, 'deploy'])->middleware([IgnoreReadOnlyApiToken::class]); Route::match(['get', 'post'], '/deploy', [DeployController::class, 'deploy'])->middleware([IgnoreReadOnlyApiToken::class]);
Route::get('/deployments', [DeployController::class, 'deployments']); Route::get('/deployments', [DeployController::class, 'deployments']);
Route::get('/deployments/{uuid}', [DeployController::class, 'deployment_by_uuid']); Route::get('/deployments/{uuid}', [DeployController::class, 'deployment_by_uuid']);