diff --git a/app/Http/Controllers/Api/ApplicationsController.php b/app/Http/Controllers/Api/ApplicationsController.php index 05576b55b..fb58018c6 100644 --- a/app/Http/Controllers/Api/ApplicationsController.php +++ b/app/Http/Controllers/Api/ApplicationsController.php @@ -17,6 +17,7 @@ use App\Models\Service; use Illuminate\Http\Request; use Illuminate\Validation\Rule; +use OpenApi\Attributes as OA; use Symfony\Component\Yaml\Yaml; use Visus\Cuid2\Cuid2; @@ -48,6 +49,37 @@ private function removeSensitiveData($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) { $teamId = getTeamIdFromToken(); @@ -95,9 +127,114 @@ public function create_dockercompose_application(Request $request) $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) { - $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(); if (is_null($teamId)) { return invalidTokenResponse(); @@ -167,7 +304,6 @@ private function create_application(Request $request, $type) 'build_pack' => ['required', Rule::enum(BuildPackTypes::class)], 'ports_exposes' => 'string|regex:/^(\d+)(,\d+)*$/|required', 'docker_compose_location' => 'string', - 'docker_compose' => 'string|nullable', 'docker_compose_raw' => 'string|nullable', 'docker_compose_domains' => 'array|nullable', 'docker_compose_custom_start_command' => 'string|nullable', @@ -243,7 +379,6 @@ private function create_application(Request $request, $type) 'github_app_uuid' => 'string|required', 'watch_paths' => 'string|nullable', 'docker_compose_location' => 'string', - 'docker_compose' => 'string|nullable', 'docker_compose_raw' => 'string|nullable', 'docker_compose_domains' => 'array|nullable', 'docker_compose_custom_start_command' => 'string|nullable', @@ -335,7 +470,6 @@ private function create_application(Request $request, $type) 'private_key_uuid' => 'string|required', 'watch_paths' => 'string|nullable', 'docker_compose_location' => 'string', - 'docker_compose' => 'string|nullable', 'docker_compose_raw' => 'string|nullable', 'docker_compose_domains' => 'array|nullable', 'docker_compose_custom_start_command' => 'string|nullable', @@ -626,6 +760,52 @@ private function create_application(Request $request, $type) } + #[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) { $teamId = getTeamIdFromToken(); @@ -695,7 +875,7 @@ public function update_by_uuid(Request $request) ], 404); } $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(), [ sharedDataApplications(), @@ -704,7 +884,6 @@ public function update_by_uuid(Request $request) 'static_image' => 'string', 'watch_paths' => 'string|nullable', 'docker_compose_location' => 'string', - 'docker_compose' => 'string|nullable', 'docker_compose_raw' => 'string|nullable', 'docker_compose_domains' => 'array|nullable', 'docker_compose_custom_start_command' => 'string|nullable', diff --git a/app/Http/Controllers/Api/DeployController.php b/app/Http/Controllers/Api/DeployController.php index 540723523..ec46a5296 100644 --- a/app/Http/Controllers/Api/DeployController.php +++ b/app/Http/Controllers/Api/DeployController.php @@ -9,6 +9,7 @@ use App\Models\Server; use App\Models\Tag; use Illuminate\Http\Request; +use OpenApi\Attributes as OA; use Visus\Cuid2\Cuid2; class DeployController extends Controller @@ -27,6 +28,38 @@ private function removeSensitiveData($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) { $teamId = getTeamIdFromToken(); @@ -34,25 +67,7 @@ public function deployments(Request $request) return invalidTokenResponse(); } $servers = Server::whereTeamId($teamId)->get(); - $deployments_per_server = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->whereIn('server_id', $servers->pluck('id'))->get([ - '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 = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->whereIn('server_id', $servers->pluck('id'))->get()->sortBy('id'); $deployments_per_server = $deployments_per_server->map(function ($deployment) { return $this->removeSensitiveData($deployment); }); @@ -60,6 +75,43 @@ public function deployments(Request $request) 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) { $teamId = getTeamIdFromToken(); @@ -70,26 +122,7 @@ public function deployment_by_uuid(Request $request) if (! $uuid) { return response()->json(['message' => 'UUID is required.'], 400); } - $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', - ]); + $deployment = ApplicationDeploymentQueue::where('deployment_uuid', $uuid)->first(); if (! $deployment) { return response()->json(['message' => 'Deployment not found.'], 404); } @@ -97,6 +130,57 @@ public function deployment_by_uuid(Request $request) 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) { $teamId = getTeamIdFromToken(); diff --git a/app/Http/Controllers/Api/OpenApi.php b/app/Http/Controllers/Api/OpenApi.php index e52c47ccb..59731ef40 100644 --- a/app/Http/Controllers/Api/OpenApi.php +++ b/app/Http/Controllers/Api/OpenApi.php @@ -13,15 +13,6 @@ description: 'Go to `Keys & Tokens` / `API tokens` and create a new token. Use the token as the bearer token.')] #[OA\Components( 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( response: 400, description: 'Invalid token.', @@ -31,13 +22,22 @@ 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( response: 404, description: 'Resource not found.', content: new OA\JsonContent( type: 'object', properties: [ - new OA\Property(property: 'message', type: 'string'), + new OA\Property(property: 'message', type: 'string', example: 'Resource not found.'), ] )), ], diff --git a/app/Http/Controllers/Api/OtherController.php b/app/Http/Controllers/Api/OtherController.php index 7ec7d8dd5..96dded3ce 100644 --- a/app/Http/Controllers/Api/OtherController.php +++ b/app/Http/Controllers/Api/OtherController.php @@ -159,9 +159,6 @@ public function feedback(Request $request) summary: 'Healthcheck', description: 'Healthcheck endpoint.', path: '/healthcheck', - security: [ - ['bearerAuth' => []], - ], responses: [ new OA\Response( response: 200, diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index e70da1ed0..b7c3d115d 100644 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -5,9 +5,41 @@ use App\Http\Controllers\Controller; use App\Models\Project; use Illuminate\Http\Request; +use OpenApi\Attributes as OA; 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) { $teamId = getTeamIdFromToken(); @@ -20,6 +52,36 @@ public function projects(Request $request) ); } + #[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) { $teamId = getTeamIdFromToken(); @@ -36,6 +98,37 @@ public function project_by_uuid(Request $request) ); } + #[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) { $teamId = getTeamIdFromToken(); diff --git a/app/Http/Controllers/Api/ResourcesController.php b/app/Http/Controllers/Api/ResourcesController.php index 866b7e548..ae076bb71 100644 --- a/app/Http/Controllers/Api/ResourcesController.php +++ b/app/Http/Controllers/Api/ResourcesController.php @@ -5,9 +5,37 @@ use App\Http\Controllers\Controller; use App\Models\Project; use Illuminate\Http\Request; +use OpenApi\Attributes as OA; 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) { $teamId = getTeamIdFromToken(); diff --git a/app/Http/Controllers/Api/SecurityController.php b/app/Http/Controllers/Api/SecurityController.php index fff280978..11e8e27ca 100644 --- a/app/Http/Controllers/Api/SecurityController.php +++ b/app/Http/Controllers/Api/SecurityController.php @@ -5,9 +5,54 @@ use App\Http\Controllers\Controller; use App\Models\PrivateKey; use Illuminate\Http\Request; +use OpenApi\Attributes as OA; 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) { $teamId = getTeamIdFromToken(); @@ -16,9 +61,47 @@ public function keys(Request $request) } $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) { $teamId = getTeamIdFromToken(); @@ -34,9 +117,60 @@ public function key_by_uuid(Request $request) ], 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) { $teamId = getTeamIdFromToken(); @@ -79,6 +213,57 @@ public function create_key(Request $request) ]))->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) { $allowedFields = ['name', 'description', 'private_key']; @@ -124,6 +309,46 @@ public function update_key(Request $request) ]))->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) { $teamId = getTeamIdFromToken(); diff --git a/app/Http/Controllers/Api/ServersController.php b/app/Http/Controllers/Api/ServersController.php index ab44664a7..247a2519f 100644 --- a/app/Http/Controllers/Api/ServersController.php +++ b/app/Http/Controllers/Api/ServersController.php @@ -8,6 +8,7 @@ use App\Models\Project; use App\Models\Server as ModelsServer; use Illuminate\Http\Request; +use OpenApi\Attributes as OA; use Stringable; class ServersController extends Controller @@ -38,6 +39,37 @@ private function removeSensitiveData($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) { $teamId = getTeamIdFromToken(); @@ -61,6 +93,43 @@ public function servers(Request $request) 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) { $with_resources = $request->query('resources'); @@ -101,6 +170,50 @@ public function server_by_uuid(Request $request) 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) { $teamId = getTeamIdFromToken(); @@ -134,6 +247,45 @@ public function resources_by_server(Request $request) 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) { $teamId = getTeamIdFromToken(); diff --git a/app/Http/Controllers/Api/TeamController.php b/app/Http/Controllers/Api/TeamController.php index e155ad1b7..2c32f01e7 100644 --- a/app/Http/Controllers/Api/TeamController.php +++ b/app/Http/Controllers/Api/TeamController.php @@ -125,6 +125,44 @@ public function team_by_id(Request $request) ); } + #[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) { $id = $request->id; @@ -147,6 +185,29 @@ public function members_by_id(Request $request) ); } + #[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) { $teamId = getTeamIdFromToken(); @@ -156,10 +217,41 @@ public function current_team(Request $request) $team = auth()->user()->currentTeam(); 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) { $teamId = getTeamIdFromToken(); @@ -167,6 +259,9 @@ public function current_team_members(Request $request) return invalidTokenResponse(); } $team = auth()->user()->currentTeam(); + $team->members->makeHidden([ + 'pivot', + ]); return response()->json( serializeApiResponse($team->members), diff --git a/app/Models/Application.php b/app/Models/Application.php index 8b9ff8ee7..dd04ee004 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -8,12 +8,96 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Collection; use Illuminate\Support\Str; +use OpenApi\Attributes as OA; use RuntimeException; use Spatie\Activitylog\Models\Activity; use Spatie\Url\Url; use Symfony\Component\Yaml\Yaml; 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 { use SoftDeletes; diff --git a/app/Models/ApplicationDeploymentQueue.php b/app/Models/ApplicationDeploymentQueue.php index b1c595046..90d7608cc 100644 --- a/app/Models/ApplicationDeploymentQueue.php +++ b/app/Models/ApplicationDeploymentQueue.php @@ -4,7 +4,37 @@ use Illuminate\Database\Eloquent\Model; 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 { protected $guarded = []; diff --git a/app/Models/Environment.php b/app/Models/Environment.php index fc19c134f..c892d7ba1 100644 --- a/app/Models/Environment.php +++ b/app/Models/Environment.php @@ -4,7 +4,20 @@ use Illuminate\Database\Eloquent\Casts\Attribute; 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 { protected $guarded = []; diff --git a/app/Models/PrivateKey.php b/app/Models/PrivateKey.php index 880496344..45bc6bc84 100644 --- a/app/Models/PrivateKey.php +++ b/app/Models/PrivateKey.php @@ -2,8 +2,24 @@ namespace App\Models; +use OpenApi\Attributes as OA; 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 { protected $fillable = [ diff --git a/app/Models/Project.php b/app/Models/Project.php index b7d34e876..d4310e349 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -2,6 +2,23 @@ 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 { protected $guarded = []; diff --git a/app/Models/Server.php b/app/Models/Server.php index ea487fee7..fc4fd9892 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -12,11 +12,95 @@ use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Stringable; +use OpenApi\Attributes as OA; use Spatie\SchemalessAttributes\Casts\SchemalessAttributes; use Spatie\SchemalessAttributes\SchemalessAttributesTrait; use Spatie\Url\Url; 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 { use SchemalessAttributesTrait; diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php index 9235848ee..c39982b91 100644 --- a/app/Models/ServerSetting.php +++ b/app/Models/ServerSetting.php @@ -3,7 +3,46 @@ namespace App\Models; 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 { protected $guarded = []; diff --git a/app/Models/Team.php b/app/Models/Team.php index 8b8c472ee..3f8e97bc5 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -59,6 +59,12 @@ '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_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 diff --git a/app/Models/User.php b/app/Models/User.php index 1e120e951..33b70be3d 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -17,7 +17,23 @@ use Laravel\Fortify\TwoFactorAuthenticatable; use Laravel\Sanctum\HasApiTokens; 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 { use HasApiTokens, HasFactory, Notifiable, TwoFactorAuthenticatable; diff --git a/openapi.yaml b/openapi.yaml index 19e342351..8ae08befa 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -6,6 +6,315 @@ servers: - url: 'https://app.coolify.io/api/v1' paths: + /applications: + get: + tags: + - Applications + summary: List + description: 'List all applications.' + operationId: 02978e79fc0b54d573b2359f2a1f7d86 + responses: + '200': + description: 'Get all applications.' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Application' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] + post: + tags: + - Applications + summary: Create + description: 'Create new application.' + operationId: b79c870f7f32360e4ed7fee8e053a055 + requestBody: + description: 'Application object that needs to be created.' + required: true + content: + application/json: + schema: + 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 + type: object + responses: + '200': + description: 'Get all applications.' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Application' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] + '/applications/{uuid}': + get: + tags: + - Applications + summary: Get + description: 'Get application by UUID.' + operationId: 3630b62c28e7358e7f0087c1d8fe1845 + parameters: + - + name: uuid + in: path + description: 'UUID of the application.' + required: true + schema: + type: string + format: uuid + responses: + '200': + description: 'Get all applications.' + content: + application/json: + schema: + $ref: '#/components/schemas/Application' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + '404': + $ref: '#/components/responses/404' + security: + - + bearerAuth: [] + /deployments: + get: + tags: + - Deployments + summary: List + description: 'List currently running deployments' + operationId: a2c05736269191ad0d99cadfd4708986 + responses: + '200': + description: 'Get all currently running deployments.' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ApplicationDeploymentQueue' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] + '/deployments/{uuid}': + get: + tags: + - Deployments + summary: Get + description: 'Get deployment by UUID.' + operationId: ccf9856174c115a1430d952ccbd36aea + parameters: + - + name: uuid + in: path + description: 'Deployment Uuid' + required: true + schema: + type: integer + responses: + '200': + description: 'Get deployment by UUID.' + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationDeploymentQueue' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + '404': + $ref: '#/components/responses/404' + security: + - + bearerAuth: [] + /deploy: + get: + tags: + - Deployments + summary: Deploy + description: 'Deploy by tag or uuid. `Post` request also accepted.' + operationId: 700eb6e51f4c9e86d722f600c65ed1d4 + parameters: + - + name: tag + in: query + description: 'Tag name(s). Comma separated list is also accepted.' + schema: + type: string + - + name: uuid + in: query + description: 'Resource UUID(s). Comma separated list is also accepted.' + schema: + type: string + - + name: force + in: query + description: 'Force rebuild (without cache)' + schema: + type: boolean + responses: + '200': + description: "Get deployment(s) Uuid's" + content: + application/json: + schema: + properties: + deployments: { type: array, items: { properties: { message: { type: string }, resource_uuid: { type: string }, deployment_uuid: { type: string } }, type: object } } + type: object + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] /version: get: summary: Version @@ -101,6 +410,399 @@ paths: $ref: '#/components/responses/401' '400': $ref: '#/components/responses/400' + /projects: + get: + tags: + - Projects + summary: List + description: 'list projects.' + operationId: 762788f00f2dabb981df9adbc948d3f6 + responses: + '200': + description: 'Get all projects.' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Project' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] + '/projects/{uuid}': + get: + tags: + - Projects + summary: Get + description: 'Get project by Uuid.' + operationId: 63bf8b6a68fbb757f09ab519331f6298 + parameters: + - + name: uuid + in: path + description: 'Project UUID' + required: true + schema: + type: integer + responses: + '200': + description: 'Project details' + content: + application/json: + schema: + $ref: '#/components/schemas/Project' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + '404': + description: 'Project not found.' + security: + - + bearerAuth: [] + '/projects/{uuid}/{environment_name}': + get: + tags: + - Projects + summary: Environment + description: 'Get environment by name.' + operationId: 7e44845dce5aa47ed7b0daf5595ad2e1 + parameters: + - + name: uuid + in: path + description: 'Project UUID' + required: true + schema: + type: integer + - + name: environment_name + in: path + description: 'Environment name' + required: true + schema: + type: string + responses: + '200': + description: 'Project details' + content: + application/json: + schema: + $ref: '#/components/schemas/Environment' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + '404': + $ref: '#/components/responses/404' + security: + - + bearerAuth: [] + /resources: + get: + tags: + - Resources + summary: List + description: 'Get all resources.' + operationId: c399903694eb1314596832e49f7c66d7 + responses: + '200': + description: 'Get all resources' + content: + application/json: + schema: + type: string + example: 'Content is very complex. Will be implemented later.' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] + /security/keys: + get: + tags: + - 'Private Keys' + summary: List + description: 'List all private keys.' + operationId: 8a5d8d3ccbbcef54ed0e913a27faea9d + responses: + '200': + description: 'Get all private keys.' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PrivateKey' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] + post: + tags: + - 'Private Keys' + summary: Create + description: 'Create a new private key.' + operationId: eb4780acaa990c594cdbe8ffa80b4fb0 + requestBody: + required: true + content: + application/json: + schema: + required: + - private_key + properties: + name: + type: string + description: + type: string + private_key: + type: string + type: object + additionalProperties: false + responses: + '201': + description: "The created private key's UUID." + content: + application/json: + schema: + properties: + uuid: { type: string } + type: object + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] + patch: + tags: + - 'Private Keys' + summary: Update + description: 'Update a private key.' + operationId: 371fd26b8949a070c26a264231fe233f + requestBody: + required: true + content: + application/json: + schema: + required: + - private_key + properties: + name: + type: string + description: + type: string + private_key: + type: string + type: object + additionalProperties: false + responses: + '201': + description: "The updated private key's UUID." + content: + application/json: + schema: + properties: + uuid: { type: string } + type: object + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] + '/security/keys/{uuid}': + get: + tags: + - 'Private Keys' + summary: Get + description: 'Get key by UUID.' + operationId: 2f743a85eb65d5ddb8cd5b362bb3d26a + parameters: + - + name: uuid + in: path + description: 'Private Key Uuid' + required: true + schema: + type: integer + responses: + '200': + description: 'Get all private keys.' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PrivateKey' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + '404': + description: 'Private Key not found.' + security: + - + bearerAuth: [] + delete: + tags: + - 'Private Keys' + summary: Delete + description: 'Delete a private key.' + operationId: 8faa0bb399142f0084dfc3e003c42cf6 + parameters: + - + name: uuid + in: path + description: 'Private Key Uuid' + required: true + schema: + type: integer + responses: + '200': + description: 'Private Key deleted.' + content: + application/json: + schema: + properties: + message: { type: string, example: 'Private Key deleted.' } + type: object + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + '404': + description: 'Private Key not found.' + security: + - + bearerAuth: [] + /servers: + get: + tags: + - Servers + summary: List + description: 'List all servers.' + operationId: 787448df856cefd2d9a313566be30d34 + responses: + '200': + description: 'Get all servers.' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Server' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] + '/servers/{uuid}': + get: + tags: + - Servers + summary: Get + description: 'Get server by UUID.' + operationId: 5baf04bddb8302c7e07f5b4c41aad10c + parameters: + - + name: uuid + in: path + description: "Server's Uuid" + required: true + schema: + type: integer + responses: + '200': + description: 'Get server by UUID' + content: + application/json: + schema: + $ref: '#/components/schemas/Server' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + '404': + $ref: '#/components/responses/404' + security: + - + bearerAuth: [] + '/servers/{uuid}/resources': + get: + tags: + - Servers + summary: Resources + description: 'Get resources by server.' + operationId: cef26c059941b44fbd8de3a7a58c10a5 + parameters: + - + name: uuid + in: path + description: "Server's Uuid" + required: true + schema: + type: integer + responses: + '200': + description: 'Get resources by server' + content: + application/json: + schema: + type: array + items: + properties: { id: { type: integer }, uuid: { type: string }, name: { type: string }, type: { type: string }, created_at: { type: string }, updated_at: { type: string }, status: { type: string } } + type: object + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] + '/servers/{uuid}/domains': + get: + tags: + - Servers + summary: Domains + description: 'Get domains by server.' + operationId: 1ee227755be848d572f412272f53dd93 + parameters: + - + name: uuid + in: path + description: "Server's Uuid" + required: true + schema: + type: integer + responses: + '200': + description: 'Get domains by server' + content: + application/json: + schema: + type: array + items: + properties: { ip: { type: string }, domains: { type: array, items: { type: string } } } + type: object + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' security: - bearerAuth: [] @@ -158,8 +860,633 @@ paths: security: - bearerAuth: [] + '/teams/{id}/members': + get: + tags: + - Teams + summary: Members + description: 'Get members by TeamId.' + operationId: 7858f5a45d9ea55184c182852a7f0f6c + parameters: + - + name: id + in: path + description: 'Team ID' + required: true + schema: + type: integer + responses: + '200': + description: 'List of members.' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + '404': + $ref: '#/components/responses/404' + security: + - + bearerAuth: [] + /teams/current: + get: + tags: + - Teams + summary: 'Authenticated Team' + description: 'Get currently authenticated team.' + operationId: 6a4ec9fed1aad7b0b38356c47d7ac509 + responses: + '200': + description: 'Current Team.' + content: + application/json: + schema: + $ref: '#/components/schemas/Team' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] + /teams/current/members: + get: + tags: + - Teams + summary: 'Authenticated Team Members' + description: 'Get currently authenticated team members.' + operationId: 97e636a5796dbe71afb0bbcf1eec6e41 + responses: + '200': + description: 'Currently authenticated team members.' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + '401': + $ref: '#/components/responses/401' + '400': + $ref: '#/components/responses/400' + security: + - + bearerAuth: [] components: schemas: + Application: + description: 'Application model' + 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 + type: object + ApplicationDeploymentQueue: + description: 'Project model' + 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 + type: object + Environment: + description: 'Environment model' + properties: + id: + type: integer + name: + type: string + project_id: + type: integer + created_at: + type: string + updated_at: + type: string + description: + type: string + type: object + PrivateKey: + description: 'Private Key model' + 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 + type: object + Project: + description: 'Project model' + properties: + id: + type: integer + uuid: + type: string + name: + type: string + environments: + description: 'The environments of the project.' + type: array + items: + $ref: '#/components/schemas/Environment' + type: object + Server: + description: 'Application model' + 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 + type: object + ServerSetting: + description: 'Server Settings model' + 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 + type: object Team: description: 'Team model' properties: @@ -301,18 +1628,35 @@ components: telegram_notifications_scheduled_tasks_thread_id: type: string description: 'The Telegram scheduled task message thread ID.' + members: + description: 'The members of the team.' + type: array + items: + $ref: '#/components/schemas/User' + type: object + User: + description: 'User model' + 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 type: object responses: - '401': - description: Unauthenticated. - content: - application/json: - schema: - properties: - message: - type: string - example: Unauthenticated. - type: object '400': description: 'Invalid token.' content: @@ -323,6 +1667,16 @@ components: type: string example: 'Invalid token.' type: object + '401': + description: Unauthenticated. + content: + application/json: + schema: + properties: + message: + type: string + example: Unauthenticated. + type: object '404': description: 'Resource not found.' content: @@ -331,6 +1685,7 @@ components: properties: message: type: string + example: 'Resource not found.' type: object securitySchemes: bearerAuth: @@ -338,6 +1693,24 @@ components: description: 'Go to `Keys & Tokens` / `API tokens` and create a new token. Use the token as the bearer token.' scheme: bearer tags: + - + name: Applications + description: Applications + - + name: Deployments + description: Deployments + - + name: Projects + description: Projects + - + name: Resources + description: Resources + - + name: 'Private Keys' + description: 'Private Keys' + - + name: Servers + description: Servers - name: Teams description: Teams diff --git a/routes/api.php b/routes/api.php index 5daf6cd01..ecf797017 100644 --- a/routes/api.php +++ b/routes/api.php @@ -49,7 +49,6 @@ Route::delete('/security/keys/{uuid}', [SecurityController::class, 'delete_key'])->middleware([IgnoreReadOnlyApiToken::class]); Route::match(['get', 'post'], '/deploy', [DeployController::class, 'deploy'])->middleware([IgnoreReadOnlyApiToken::class]); - Route::get('/deployments', [DeployController::class, 'deployments']); Route::get('/deployments/{uuid}', [DeployController::class, 'deployment_by_uuid']);