mirror of
https://github.com/tiennm99/coolify.git
synced 2026-04-17 17:21:04 +00:00
fix(api): application endpoint issues part 2 (#7948)
This commit is contained in:
@@ -153,11 +153,14 @@ class ApplicationsController extends Controller
|
|||||||
'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
|
'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
|
||||||
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
||||||
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
||||||
'domains' => ['type' => 'string', 'description' => 'The application domains.'],
|
'domains' => ['type' => 'string', 'description' => 'The application URLs in a comma-separated list.'],
|
||||||
'git_commit_sha' => ['type' => 'string', 'description' => 'The git commit SHA.'],
|
'git_commit_sha' => ['type' => 'string', 'description' => 'The git commit SHA.'],
|
||||||
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
|
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
|
||||||
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
|
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
|
||||||
'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
|
'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
|
||||||
|
'is_spa' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true.'],
|
||||||
|
'is_auto_deploy_enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if auto-deploy is enabled on git push. Defaults to true.'],
|
||||||
|
'is_force_https_enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if HTTPS is forced. Defaults to true.'],
|
||||||
'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
|
'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
|
||||||
'install_command' => ['type' => 'string', 'description' => 'The install command.'],
|
'install_command' => ['type' => 'string', 'description' => 'The install command.'],
|
||||||
'build_command' => ['type' => 'string', 'description' => 'The build command.'],
|
'build_command' => ['type' => 'string', 'description' => 'The build command.'],
|
||||||
@@ -198,6 +201,7 @@ class ApplicationsController extends Controller
|
|||||||
// 'github_app_uuid' => ['type' => 'string', 'description' => 'The Github App UUID.'],
|
// 'github_app_uuid' => ['type' => 'string', 'description' => 'The Github App UUID.'],
|
||||||
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
||||||
'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
|
'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
|
||||||
|
'dockerfile_location' => ['type' => 'string', 'description' => 'The Dockerfile location in the repository.'],
|
||||||
'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
|
'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
|
||||||
'docker_compose_custom_start_command' => ['type' => 'string', 'description' => 'The Docker Compose custom start command.'],
|
'docker_compose_custom_start_command' => ['type' => 'string', 'description' => 'The Docker Compose custom start command.'],
|
||||||
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
|
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
|
||||||
@@ -315,11 +319,14 @@ class ApplicationsController extends Controller
|
|||||||
'build_pack' => ['type' => 'string', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose'], 'description' => 'The build pack type.'],
|
'build_pack' => ['type' => 'string', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose'], 'description' => 'The build pack type.'],
|
||||||
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
||||||
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
||||||
'domains' => ['type' => 'string', 'description' => 'The application domains.'],
|
'domains' => ['type' => 'string', 'description' => 'The application URLs in a comma-separated list.'],
|
||||||
'git_commit_sha' => ['type' => 'string', 'description' => 'The git commit SHA.'],
|
'git_commit_sha' => ['type' => 'string', 'description' => 'The git commit SHA.'],
|
||||||
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
|
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
|
||||||
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
|
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
|
||||||
'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
|
'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
|
||||||
|
'is_spa' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true.'],
|
||||||
|
'is_auto_deploy_enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if auto-deploy is enabled on git push. Defaults to true.'],
|
||||||
|
'is_force_https_enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if HTTPS is forced. Defaults to true.'],
|
||||||
'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
|
'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
|
||||||
'install_command' => ['type' => 'string', 'description' => 'The install command.'],
|
'install_command' => ['type' => 'string', 'description' => 'The install command.'],
|
||||||
'build_command' => ['type' => 'string', 'description' => 'The build command.'],
|
'build_command' => ['type' => 'string', 'description' => 'The build command.'],
|
||||||
@@ -359,6 +366,7 @@ class ApplicationsController extends Controller
|
|||||||
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
||||||
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
||||||
'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
|
'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
|
||||||
|
'dockerfile_location' => ['type' => 'string', 'description' => 'The Dockerfile location in the repository'],
|
||||||
'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
|
'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
|
||||||
'docker_compose_custom_start_command' => ['type' => 'string', 'description' => 'The Docker Compose custom start command.'],
|
'docker_compose_custom_start_command' => ['type' => 'string', 'description' => 'The Docker Compose custom start command.'],
|
||||||
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
|
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
|
||||||
@@ -476,11 +484,14 @@ class ApplicationsController extends Controller
|
|||||||
'build_pack' => ['type' => 'string', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose'], 'description' => 'The build pack type.'],
|
'build_pack' => ['type' => 'string', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose'], 'description' => 'The build pack type.'],
|
||||||
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
||||||
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
||||||
'domains' => ['type' => 'string', 'description' => 'The application domains.'],
|
'domains' => ['type' => 'string', 'description' => 'The application URLs in a comma-separated list.'],
|
||||||
'git_commit_sha' => ['type' => 'string', 'description' => 'The git commit SHA.'],
|
'git_commit_sha' => ['type' => 'string', 'description' => 'The git commit SHA.'],
|
||||||
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
|
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
|
||||||
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
|
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
|
||||||
'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
|
'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
|
||||||
|
'is_spa' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true.'],
|
||||||
|
'is_auto_deploy_enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if auto-deploy is enabled on git push. Defaults to true.'],
|
||||||
|
'is_force_https_enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if HTTPS is forced. Defaults to true.'],
|
||||||
'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
|
'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
|
||||||
'install_command' => ['type' => 'string', 'description' => 'The install command.'],
|
'install_command' => ['type' => 'string', 'description' => 'The install command.'],
|
||||||
'build_command' => ['type' => 'string', 'description' => 'The build command.'],
|
'build_command' => ['type' => 'string', 'description' => 'The build command.'],
|
||||||
@@ -520,6 +531,7 @@ class ApplicationsController extends Controller
|
|||||||
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
||||||
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
||||||
'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
|
'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
|
||||||
|
'dockerfile_location' => ['type' => 'string', 'description' => 'The Dockerfile location in the repository.'],
|
||||||
'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
|
'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
|
||||||
'docker_compose_custom_start_command' => ['type' => 'string', 'description' => 'The Docker Compose custom start command.'],
|
'docker_compose_custom_start_command' => ['type' => 'string', 'description' => 'The Docker Compose custom start command.'],
|
||||||
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
|
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
|
||||||
@@ -635,7 +647,7 @@ class ApplicationsController extends Controller
|
|||||||
'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
|
'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
|
||||||
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
||||||
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
||||||
'domains' => ['type' => 'string', 'description' => 'The application domains.'],
|
'domains' => ['type' => 'string', 'description' => 'The application URLs in a comma-separated list.'],
|
||||||
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
|
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
|
||||||
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
|
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
|
||||||
'ports_mappings' => ['type' => 'string', 'description' => 'The ports mappings.'],
|
'ports_mappings' => ['type' => 'string', 'description' => 'The ports mappings.'],
|
||||||
@@ -671,6 +683,7 @@ class ApplicationsController extends Controller
|
|||||||
'manual_webhook_secret_gitea' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitea.'],
|
'manual_webhook_secret_gitea' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitea.'],
|
||||||
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
||||||
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
||||||
|
'is_force_https_enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if HTTPS is forced. Defaults to true.'],
|
||||||
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
|
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
|
||||||
'is_http_basic_auth_enabled' => ['type' => 'boolean', 'description' => 'HTTP Basic Authentication enabled.'],
|
'is_http_basic_auth_enabled' => ['type' => 'boolean', 'description' => 'HTTP Basic Authentication enabled.'],
|
||||||
'http_basic_auth_username' => ['type' => 'string', 'nullable' => true, 'description' => 'Username for HTTP Basic Authentication'],
|
'http_basic_auth_username' => ['type' => 'string', 'nullable' => true, 'description' => 'Username for HTTP Basic Authentication'],
|
||||||
@@ -771,7 +784,7 @@ class ApplicationsController extends Controller
|
|||||||
'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
|
'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
|
||||||
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
||||||
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
||||||
'domains' => ['type' => 'string', 'description' => 'The application domains.'],
|
'domains' => ['type' => 'string', 'description' => 'The application URLs in a comma-separated list.'],
|
||||||
'ports_mappings' => ['type' => 'string', 'description' => 'The ports mappings.'],
|
'ports_mappings' => ['type' => 'string', 'description' => 'The ports mappings.'],
|
||||||
'health_check_enabled' => ['type' => 'boolean', 'description' => 'Health check enabled.'],
|
'health_check_enabled' => ['type' => 'boolean', 'description' => 'Health check enabled.'],
|
||||||
'health_check_path' => ['type' => 'string', 'description' => 'Health check path.'],
|
'health_check_path' => ['type' => 'string', 'description' => 'Health check path.'],
|
||||||
@@ -804,6 +817,7 @@ class ApplicationsController extends Controller
|
|||||||
'manual_webhook_secret_gitea' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitea.'],
|
'manual_webhook_secret_gitea' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitea.'],
|
||||||
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
||||||
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
||||||
|
'is_force_https_enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if HTTPS is forced. Defaults to true.'],
|
||||||
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
|
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
|
||||||
'is_http_basic_auth_enabled' => ['type' => 'boolean', 'description' => 'HTTP Basic Authentication enabled.'],
|
'is_http_basic_auth_enabled' => ['type' => 'boolean', 'description' => 'HTTP Basic Authentication enabled.'],
|
||||||
'http_basic_auth_username' => ['type' => 'string', 'nullable' => true, 'description' => 'Username for HTTP Basic Authentication'],
|
'http_basic_auth_username' => ['type' => 'string', 'nullable' => true, 'description' => 'Username for HTTP Basic Authentication'],
|
||||||
@@ -987,7 +1001,7 @@ class ApplicationsController extends Controller
|
|||||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
$allowedFields = ['project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'private_key_uuid', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'custom_network_aliases', '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', 'use_build_server', 'static_image', 'custom_nginx_configuration', 'is_http_basic_auth_enabled', 'http_basic_auth_username', 'http_basic_auth_password', 'connect_to_docker_network', 'force_domain_override', 'autogenerate_domain', 'is_container_label_escape_enabled'];
|
$allowedFields = ['project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'is_spa', 'is_auto_deploy_enabled', 'is_force_https_enabled', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'private_key_uuid', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'custom_network_aliases', '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', 'dockerfile_location', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'watch_paths', 'use_build_server', 'static_image', 'custom_nginx_configuration', 'is_http_basic_auth_enabled', 'http_basic_auth_username', 'http_basic_auth_password', 'connect_to_docker_network', 'force_domain_override', 'autogenerate_domain', 'is_container_label_escape_enabled'];
|
||||||
|
|
||||||
$validator = customApiValidator($request->all(), [
|
$validator = customApiValidator($request->all(), [
|
||||||
'name' => 'string|max:255',
|
'name' => 'string|max:255',
|
||||||
@@ -1030,6 +1044,9 @@ class ApplicationsController extends Controller
|
|||||||
$githubAppUuid = $request->github_app_uuid;
|
$githubAppUuid = $request->github_app_uuid;
|
||||||
$useBuildServer = $request->use_build_server;
|
$useBuildServer = $request->use_build_server;
|
||||||
$isStatic = $request->is_static;
|
$isStatic = $request->is_static;
|
||||||
|
$isSpa = $request->is_spa;
|
||||||
|
$isAutoDeployEnabled = $request->is_auto_deploy_enabled;
|
||||||
|
$isForceHttpsEnabled = $request->is_force_https_enabled;
|
||||||
$connectToDockerNetwork = $request->connect_to_docker_network;
|
$connectToDockerNetwork = $request->connect_to_docker_network;
|
||||||
$customNginxConfiguration = $request->custom_nginx_configuration;
|
$customNginxConfiguration = $request->custom_nginx_configuration;
|
||||||
$isContainerLabelEscapeEnabled = $request->boolean('is_container_label_escape_enabled', true);
|
$isContainerLabelEscapeEnabled = $request->boolean('is_container_label_escape_enabled', true);
|
||||||
@@ -1130,39 +1147,63 @@ class ApplicationsController extends Controller
|
|||||||
$dockerComposeDomainsJson = collect();
|
$dockerComposeDomainsJson = collect();
|
||||||
if ($request->has('docker_compose_domains')) {
|
if ($request->has('docker_compose_domains')) {
|
||||||
$dockerComposeDomains = collect($request->docker_compose_domains);
|
$dockerComposeDomains = collect($request->docker_compose_domains);
|
||||||
$domainErrors = [];
|
|
||||||
|
|
||||||
foreach ($dockerComposeDomains as $index => $item) {
|
// Collect all URLs from all docker_compose_domains items
|
||||||
|
$urls = $dockerComposeDomains->flatMap(function ($item) {
|
||||||
$domainValue = data_get($item, 'domain');
|
$domainValue = data_get($item, 'domain');
|
||||||
if (filled($domainValue)) {
|
if (blank($domainValue)) {
|
||||||
$urls = str($domainValue)->replaceStart(',', '')->replaceEnd(',', '')->trim();
|
return [];
|
||||||
str($urls)->explode(',')->each(function ($url) use (&$domainErrors) {
|
|
||||||
$url = trim($url);
|
|
||||||
if (empty($url)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (! filter_var($url, FILTER_VALIDATE_URL)) {
|
|
||||||
$domainErrors[] = "Invalid URL: {$url}";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$scheme = parse_url($url, PHP_URL_SCHEME) ?? '';
|
|
||||||
if (! in_array(strtolower($scheme), ['http', 'https'])) {
|
|
||||||
$domainErrors[] = "Invalid URL scheme: {$scheme} for URL: {$url}. Only http and https are supported.";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return str($domainValue)->replaceStart(',', '')->replaceEnd(',', '')->trim()->explode(',')->map(fn ($url) => trim($url))->filter();
|
||||||
|
});
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
$urls = $urls->map(function ($url) use (&$errors) {
|
||||||
|
if (! filter_var($url, FILTER_VALIDATE_URL)) {
|
||||||
|
$errors[] = "Invalid URL: {$url}";
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
$scheme = parse_url($url, PHP_URL_SCHEME) ?? '';
|
||||||
|
if (! in_array(strtolower($scheme), ['http', 'https'])) {
|
||||||
|
$errors[] = "Invalid URL scheme: {$scheme} for URL: {$url}. Only http and https are supported.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
});
|
||||||
|
|
||||||
|
$duplicates = $urls->duplicates()->unique()->values();
|
||||||
|
if ($duplicates->isNotEmpty() && ! $request->boolean('force_domain_override')) {
|
||||||
|
$errors[] = 'The current request contains conflicting URLs: '.implode(', ', $duplicates->toArray()).' Use force_domain_override=true to proceed.';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($domainErrors)) {
|
if (count($errors) > 0) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Validation failed.',
|
'message' => 'Validation failed.',
|
||||||
'errors' => [
|
'errors' => ['docker_compose_domains' => $errors],
|
||||||
'docker_compose_domains' => $domainErrors,
|
|
||||||
],
|
|
||||||
], 422);
|
], 422);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for domain conflicts
|
||||||
|
if ($urls->isNotEmpty()) {
|
||||||
|
$result = checkIfDomainIsAlreadyUsedViaAPI($urls, $teamId);
|
||||||
|
if (isset($result['error'])) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Validation failed.',
|
||||||
|
'errors' => ['docker_compose_domains' => $result['error']],
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result['hasConflicts'] && ! $request->boolean('force_domain_override')) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Domain conflicts detected. Use force_domain_override=true to proceed.',
|
||||||
|
'conflicts' => $result['conflicts'],
|
||||||
|
'warning' => 'Using the same domain for multiple resources can cause routing conflicts and unpredictable behavior.',
|
||||||
|
], 409);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$dockerComposeDomains->each(function ($domain) use ($dockerComposeDomainsJson) {
|
$dockerComposeDomains->each(function ($domain) use ($dockerComposeDomainsJson) {
|
||||||
$dockerComposeDomainsJson->put(data_get($domain, 'name'), ['domain' => data_get($domain, 'domain')]);
|
$dockerComposeDomainsJson->put(data_get($domain, 'name'), ['domain' => data_get($domain, 'domain')]);
|
||||||
});
|
});
|
||||||
@@ -1187,6 +1228,18 @@ class ApplicationsController extends Controller
|
|||||||
$application->settings->is_static = $isStatic;
|
$application->settings->is_static = $isStatic;
|
||||||
$application->settings->save();
|
$application->settings->save();
|
||||||
}
|
}
|
||||||
|
if (isset($isSpa)) {
|
||||||
|
$application->settings->is_spa = $isSpa;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($isAutoDeployEnabled)) {
|
||||||
|
$application->settings->is_auto_deploy_enabled = $isAutoDeployEnabled;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($isForceHttpsEnabled)) {
|
||||||
|
$application->settings->is_force_https_enabled = $isForceHttpsEnabled;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
if (isset($connectToDockerNetwork)) {
|
if (isset($connectToDockerNetwork)) {
|
||||||
$application->settings->connect_to_docker_network = $connectToDockerNetwork;
|
$application->settings->connect_to_docker_network = $connectToDockerNetwork;
|
||||||
$application->settings->save();
|
$application->settings->save();
|
||||||
@@ -1319,39 +1372,63 @@ class ApplicationsController extends Controller
|
|||||||
$dockerComposeDomainsJson = collect();
|
$dockerComposeDomainsJson = collect();
|
||||||
if ($request->has('docker_compose_domains')) {
|
if ($request->has('docker_compose_domains')) {
|
||||||
$dockerComposeDomains = collect($request->docker_compose_domains);
|
$dockerComposeDomains = collect($request->docker_compose_domains);
|
||||||
$domainErrors = [];
|
|
||||||
|
|
||||||
foreach ($dockerComposeDomains as $index => $item) {
|
// Collect all URLs from all docker_compose_domains items
|
||||||
|
$urls = $dockerComposeDomains->flatMap(function ($item) {
|
||||||
$domainValue = data_get($item, 'domain');
|
$domainValue = data_get($item, 'domain');
|
||||||
if (filled($domainValue)) {
|
if (blank($domainValue)) {
|
||||||
$urls = str($domainValue)->replaceStart(',', '')->replaceEnd(',', '')->trim();
|
return [];
|
||||||
str($urls)->explode(',')->each(function ($url) use (&$domainErrors) {
|
|
||||||
$url = trim($url);
|
|
||||||
if (empty($url)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (! filter_var($url, FILTER_VALIDATE_URL)) {
|
|
||||||
$domainErrors[] = "Invalid URL: {$url}";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$scheme = parse_url($url, PHP_URL_SCHEME) ?? '';
|
|
||||||
if (! in_array(strtolower($scheme), ['http', 'https'])) {
|
|
||||||
$domainErrors[] = "Invalid URL scheme: {$scheme} for URL: {$url}. Only http and https are supported.";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return str($domainValue)->replaceStart(',', '')->replaceEnd(',', '')->trim()->explode(',')->map(fn ($url) => trim($url))->filter();
|
||||||
|
});
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
$urls = $urls->map(function ($url) use (&$errors) {
|
||||||
|
if (! filter_var($url, FILTER_VALIDATE_URL)) {
|
||||||
|
$errors[] = "Invalid URL: {$url}";
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
$scheme = parse_url($url, PHP_URL_SCHEME) ?? '';
|
||||||
|
if (! in_array(strtolower($scheme), ['http', 'https'])) {
|
||||||
|
$errors[] = "Invalid URL scheme: {$scheme} for URL: {$url}. Only http and https are supported.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
});
|
||||||
|
|
||||||
|
$duplicates = $urls->duplicates()->unique()->values();
|
||||||
|
if ($duplicates->isNotEmpty() && ! $request->boolean('force_domain_override')) {
|
||||||
|
$errors[] = 'The current request contains conflicting URLs: '.implode(', ', $duplicates->toArray()).' Use force_domain_override=true to proceed. ';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($domainErrors)) {
|
if (count($errors) > 0) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Validation failed.',
|
'message' => 'Validation failed.',
|
||||||
'errors' => [
|
'errors' => ['docker_compose_domains' => $errors],
|
||||||
'docker_compose_domains' => $domainErrors,
|
|
||||||
],
|
|
||||||
], 422);
|
], 422);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for domain conflicts
|
||||||
|
if ($urls->isNotEmpty()) {
|
||||||
|
$result = checkIfDomainIsAlreadyUsedViaAPI($urls, $teamId);
|
||||||
|
if (isset($result['error'])) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Validation failed.',
|
||||||
|
'errors' => ['docker_compose_domains' => $result['error']],
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result['hasConflicts'] && ! $request->boolean('force_domain_override')) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Domain conflicts detected. Use force_domain_override=true to proceed.',
|
||||||
|
'conflicts' => $result['conflicts'],
|
||||||
|
'warning' => 'Using the same domain for multiple resources can cause routing conflicts and unpredictable behavior.',
|
||||||
|
], 409);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$dockerComposeDomains->each(function ($domain) use ($dockerComposeDomainsJson) {
|
$dockerComposeDomains->each(function ($domain) use ($dockerComposeDomainsJson) {
|
||||||
$dockerComposeDomainsJson->put(data_get($domain, 'name'), ['domain' => data_get($domain, 'domain')]);
|
$dockerComposeDomainsJson->put(data_get($domain, 'name'), ['domain' => data_get($domain, 'domain')]);
|
||||||
});
|
});
|
||||||
@@ -1376,6 +1453,26 @@ class ApplicationsController extends Controller
|
|||||||
$application->fqdn = generateUrl(server: $server, random: $application->uuid);
|
$application->fqdn = generateUrl(server: $server, random: $application->uuid);
|
||||||
$application->save();
|
$application->save();
|
||||||
}
|
}
|
||||||
|
if (isset($isStatic)) {
|
||||||
|
$application->settings->is_static = $isStatic;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($isSpa)) {
|
||||||
|
$application->settings->is_spa = $isSpa;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($isAutoDeployEnabled)) {
|
||||||
|
$application->settings->is_auto_deploy_enabled = $isAutoDeployEnabled;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($isForceHttpsEnabled)) {
|
||||||
|
$application->settings->is_force_https_enabled = $isForceHttpsEnabled;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($connectToDockerNetwork)) {
|
||||||
|
$application->settings->connect_to_docker_network = $connectToDockerNetwork;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
if (isset($useBuildServer)) {
|
if (isset($useBuildServer)) {
|
||||||
$application->settings->is_build_server_enabled = $useBuildServer;
|
$application->settings->is_build_server_enabled = $useBuildServer;
|
||||||
$application->settings->save();
|
$application->settings->save();
|
||||||
@@ -1476,39 +1573,63 @@ class ApplicationsController extends Controller
|
|||||||
$dockerComposeDomainsJson = collect();
|
$dockerComposeDomainsJson = collect();
|
||||||
if ($request->has('docker_compose_domains')) {
|
if ($request->has('docker_compose_domains')) {
|
||||||
$dockerComposeDomains = collect($request->docker_compose_domains);
|
$dockerComposeDomains = collect($request->docker_compose_domains);
|
||||||
$domainErrors = [];
|
|
||||||
|
|
||||||
foreach ($dockerComposeDomains as $index => $item) {
|
// Collect all URLs from all docker_compose_domains items
|
||||||
|
$urls = $dockerComposeDomains->flatMap(function ($item) {
|
||||||
$domainValue = data_get($item, 'domain');
|
$domainValue = data_get($item, 'domain');
|
||||||
if (filled($domainValue)) {
|
if (blank($domainValue)) {
|
||||||
$urls = str($domainValue)->replaceStart(',', '')->replaceEnd(',', '')->trim();
|
return [];
|
||||||
str($urls)->explode(',')->each(function ($url) use (&$domainErrors) {
|
|
||||||
$url = trim($url);
|
|
||||||
if (empty($url)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (! filter_var($url, FILTER_VALIDATE_URL)) {
|
|
||||||
$domainErrors[] = "Invalid URL: {$url}";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$scheme = parse_url($url, PHP_URL_SCHEME) ?? '';
|
|
||||||
if (! in_array(strtolower($scheme), ['http', 'https'])) {
|
|
||||||
$domainErrors[] = "Invalid URL scheme: {$scheme} for URL: {$url}. Only http and https are supported.";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return str($domainValue)->replaceStart(',', '')->replaceEnd(',', '')->trim()->explode(',')->map(fn ($url) => trim($url))->filter();
|
||||||
|
});
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
$urls = $urls->map(function ($url) use (&$errors) {
|
||||||
|
if (! filter_var($url, FILTER_VALIDATE_URL)) {
|
||||||
|
$errors[] = "Invalid URL: {$url}";
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
$scheme = parse_url($url, PHP_URL_SCHEME) ?? '';
|
||||||
|
if (! in_array(strtolower($scheme), ['http', 'https'])) {
|
||||||
|
$errors[] = "Invalid URL scheme: {$scheme} for URL: {$url}. Only http and https are supported.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
});
|
||||||
|
|
||||||
|
$duplicates = $urls->duplicates()->unique()->values();
|
||||||
|
if ($duplicates->isNotEmpty() && ! $request->boolean('force_domain_override')) {
|
||||||
|
$errors[] = 'The current request contains conflicting URLs: '.implode(', ', $duplicates->toArray()).' Use force_domain_override=true to proceed.';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($domainErrors)) {
|
if (count($errors) > 0) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Validation failed.',
|
'message' => 'Validation failed.',
|
||||||
'errors' => [
|
'errors' => ['docker_compose_domains' => $errors],
|
||||||
'docker_compose_domains' => $domainErrors,
|
|
||||||
],
|
|
||||||
], 422);
|
], 422);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for domain conflicts
|
||||||
|
if ($urls->isNotEmpty()) {
|
||||||
|
$result = checkIfDomainIsAlreadyUsedViaAPI($urls, $teamId);
|
||||||
|
if (isset($result['error'])) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Validation failed.',
|
||||||
|
'errors' => ['docker_compose_domains' => $result['error']],
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result['hasConflicts'] && ! $request->boolean('force_domain_override')) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Domain conflicts detected. Use force_domain_override=true to proceed.',
|
||||||
|
'conflicts' => $result['conflicts'],
|
||||||
|
'warning' => 'Using the same domain for multiple resources can cause routing conflicts and unpredictable behavior.',
|
||||||
|
], 409);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$dockerComposeDomains->each(function ($domain) use ($dockerComposeDomainsJson) {
|
$dockerComposeDomains->each(function ($domain) use ($dockerComposeDomainsJson) {
|
||||||
$dockerComposeDomainsJson->put(data_get($domain, 'name'), ['domain' => data_get($domain, 'domain')]);
|
$dockerComposeDomainsJson->put(data_get($domain, 'name'), ['domain' => data_get($domain, 'domain')]);
|
||||||
});
|
});
|
||||||
@@ -1529,6 +1650,26 @@ class ApplicationsController extends Controller
|
|||||||
$application->fqdn = generateUrl(server: $server, random: $application->uuid);
|
$application->fqdn = generateUrl(server: $server, random: $application->uuid);
|
||||||
$application->save();
|
$application->save();
|
||||||
}
|
}
|
||||||
|
if (isset($isStatic)) {
|
||||||
|
$application->settings->is_static = $isStatic;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($isSpa)) {
|
||||||
|
$application->settings->is_spa = $isSpa;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($isAutoDeployEnabled)) {
|
||||||
|
$application->settings->is_auto_deploy_enabled = $isAutoDeployEnabled;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($isForceHttpsEnabled)) {
|
||||||
|
$application->settings->is_force_https_enabled = $isForceHttpsEnabled;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($connectToDockerNetwork)) {
|
||||||
|
$application->settings->connect_to_docker_network = $connectToDockerNetwork;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
if (isset($useBuildServer)) {
|
if (isset($useBuildServer)) {
|
||||||
$application->settings->is_build_server_enabled = $useBuildServer;
|
$application->settings->is_build_server_enabled = $useBuildServer;
|
||||||
$application->settings->save();
|
$application->settings->save();
|
||||||
@@ -1632,6 +1773,14 @@ class ApplicationsController extends Controller
|
|||||||
$application->fqdn = generateUrl(server: $server, random: $application->uuid);
|
$application->fqdn = generateUrl(server: $server, random: $application->uuid);
|
||||||
$application->save();
|
$application->save();
|
||||||
}
|
}
|
||||||
|
if (isset($isForceHttpsEnabled)) {
|
||||||
|
$application->settings->is_force_https_enabled = $isForceHttpsEnabled;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($connectToDockerNetwork)) {
|
||||||
|
$application->settings->connect_to_docker_network = $connectToDockerNetwork;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
if (isset($useBuildServer)) {
|
if (isset($useBuildServer)) {
|
||||||
$application->settings->is_build_server_enabled = $useBuildServer;
|
$application->settings->is_build_server_enabled = $useBuildServer;
|
||||||
$application->settings->save();
|
$application->settings->save();
|
||||||
@@ -1734,6 +1883,14 @@ class ApplicationsController extends Controller
|
|||||||
$application->fqdn = generateUrl(server: $server, random: $application->uuid);
|
$application->fqdn = generateUrl(server: $server, random: $application->uuid);
|
||||||
$application->save();
|
$application->save();
|
||||||
}
|
}
|
||||||
|
if (isset($isForceHttpsEnabled)) {
|
||||||
|
$application->settings->is_force_https_enabled = $isForceHttpsEnabled;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
if (isset($connectToDockerNetwork)) {
|
||||||
|
$application->settings->connect_to_docker_network = $connectToDockerNetwork;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
if (isset($useBuildServer)) {
|
if (isset($useBuildServer)) {
|
||||||
$application->settings->is_build_server_enabled = $useBuildServer;
|
$application->settings->is_build_server_enabled = $useBuildServer;
|
||||||
$application->settings->save();
|
$application->settings->save();
|
||||||
@@ -2150,11 +2307,14 @@ class ApplicationsController extends Controller
|
|||||||
'build_pack' => ['type' => 'string', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose'], 'description' => 'The build pack type.'],
|
'build_pack' => ['type' => 'string', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose'], 'description' => 'The build pack type.'],
|
||||||
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
'name' => ['type' => 'string', 'description' => 'The application name.'],
|
||||||
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
'description' => ['type' => 'string', 'description' => 'The application description.'],
|
||||||
'domains' => ['type' => 'string', 'description' => 'The application domains.'],
|
'domains' => ['type' => 'string', 'description' => 'The application URLs in a comma-separated list.'],
|
||||||
'git_commit_sha' => ['type' => 'string', 'description' => 'The git commit SHA.'],
|
'git_commit_sha' => ['type' => 'string', 'description' => 'The git commit SHA.'],
|
||||||
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
|
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
|
||||||
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
|
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
|
||||||
'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
|
'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
|
||||||
|
'is_spa' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true.'],
|
||||||
|
'is_auto_deploy_enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if auto-deploy is enabled on git push. Defaults to true.'],
|
||||||
|
'is_force_https_enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if HTTPS is forced. Defaults to true.'],
|
||||||
'install_command' => ['type' => 'string', 'description' => 'The install command.'],
|
'install_command' => ['type' => 'string', 'description' => 'The install command.'],
|
||||||
'build_command' => ['type' => 'string', 'description' => 'The build command.'],
|
'build_command' => ['type' => 'string', 'description' => 'The build command.'],
|
||||||
'start_command' => ['type' => 'string', 'description' => 'The start command.'],
|
'start_command' => ['type' => 'string', 'description' => 'The start command.'],
|
||||||
@@ -2193,6 +2353,7 @@ class ApplicationsController extends Controller
|
|||||||
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
||||||
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
||||||
'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
|
'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
|
||||||
|
'dockerfile_location' => ['type' => 'string', 'description' => 'The Dockerfile location in the repository.'],
|
||||||
'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
|
'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
|
||||||
'docker_compose_custom_start_command' => ['type' => 'string', 'description' => 'The Docker Compose custom start command.'],
|
'docker_compose_custom_start_command' => ['type' => 'string', 'description' => 'The Docker Compose custom start command.'],
|
||||||
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
|
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
|
||||||
@@ -2297,7 +2458,7 @@ class ApplicationsController extends Controller
|
|||||||
$this->authorize('update', $application);
|
$this->authorize('update', $application);
|
||||||
|
|
||||||
$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','custom_network_aliases', '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_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect', 'instant_deploy', 'use_build_server', 'custom_nginx_configuration', 'is_http_basic_auth_enabled', 'http_basic_auth_username', 'http_basic_auth_password', 'connect_to_docker_network', 'force_domain_override', 'is_container_label_escape_enabled'];
|
$allowedFields = ['name', 'description', 'is_static', 'is_spa', 'is_auto_deploy_enabled', 'is_force_https_enabled', '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', 'custom_network_aliases', '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', 'dockerfile_location', 'docker_compose_location', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect', 'instant_deploy', 'use_build_server', 'custom_nginx_configuration', 'is_http_basic_auth_enabled', 'http_basic_auth_username', 'http_basic_auth_password', 'connect_to_docker_network', 'force_domain_override', 'is_container_label_escape_enabled'];
|
||||||
|
|
||||||
$validationRules = [
|
$validationRules = [
|
||||||
'name' => 'string|max:255',
|
'name' => 'string|max:255',
|
||||||
@@ -2411,18 +2572,30 @@ class ApplicationsController extends Controller
|
|||||||
$requestHasDomains = $request->has('domains');
|
$requestHasDomains = $request->has('domains');
|
||||||
if ($requestHasDomains && $server->isProxyShouldRun()) {
|
if ($requestHasDomains && $server->isProxyShouldRun()) {
|
||||||
$uuid = $request->uuid;
|
$uuid = $request->uuid;
|
||||||
$fqdn = $request->domains;
|
$urls = $request->domains;
|
||||||
$fqdn = str($fqdn)->replaceEnd(',', '')->trim();
|
$urls = str($urls)->replaceStart(',', '')->replaceEnd(',', '')->trim();
|
||||||
$fqdn = str($fqdn)->replaceStart(',', '')->trim();
|
|
||||||
$errors = [];
|
$errors = [];
|
||||||
$fqdn = str($fqdn)->trim()->explode(',')->map(function ($domain) use (&$errors) {
|
$urls = str($urls)->trim()->explode(',')->map(function ($url) use (&$errors) {
|
||||||
$domain = trim($domain);
|
$url = trim($url);
|
||||||
if (filter_var($domain, FILTER_VALIDATE_URL) === false || ! preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,}/', $domain)) {
|
|
||||||
$errors[] = 'Invalid domain: '.$domain;
|
// If "domains" is empty clear all URLs from the fqdn column
|
||||||
|
if (blank($url)) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $domain;
|
if (! filter_var($url, FILTER_VALIDATE_URL)) {
|
||||||
|
$errors[] = 'Invalid URL: '.$url;
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
$scheme = parse_url($url, PHP_URL_SCHEME) ?? '';
|
||||||
|
if (! in_array(strtolower($scheme), ['http', 'https'])) {
|
||||||
|
$errors[] = "Invalid URL scheme: {$scheme} for URL: {$url}. Only http and https are supported.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return str($url)->lower();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (count($errors) > 0) {
|
if (count($errors) > 0) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Validation failed.',
|
'message' => 'Validation failed.',
|
||||||
@@ -2430,7 +2603,7 @@ class ApplicationsController extends Controller
|
|||||||
], 422);
|
], 422);
|
||||||
}
|
}
|
||||||
// Check for domain conflicts
|
// Check for domain conflicts
|
||||||
$result = checkIfDomainIsAlreadyUsedViaAPI($fqdn, $teamId, $uuid);
|
$result = checkIfDomainIsAlreadyUsedViaAPI($urls, $teamId, $uuid);
|
||||||
if (isset($result['error'])) {
|
if (isset($result['error'])) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Validation failed.',
|
'message' => 'Validation failed.',
|
||||||
@@ -2460,39 +2633,63 @@ class ApplicationsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$dockerComposeDomains = collect($request->docker_compose_domains);
|
$dockerComposeDomains = collect($request->docker_compose_domains);
|
||||||
$domainErrors = [];
|
|
||||||
|
|
||||||
foreach ($dockerComposeDomains as $item) {
|
// Collect all URLs from all docker_compose_domains items
|
||||||
|
$urls = $dockerComposeDomains->flatMap(function ($item) {
|
||||||
$domainValue = data_get($item, 'domain');
|
$domainValue = data_get($item, 'domain');
|
||||||
if (filled($domainValue)) {
|
if (blank($domainValue)) {
|
||||||
$urls = str($domainValue)->replaceStart(',', '')->replaceEnd(',', '')->trim();
|
return [];
|
||||||
str($urls)->explode(',')->each(function ($url) use (&$domainErrors) {
|
|
||||||
$url = trim($url);
|
|
||||||
if (empty($url)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (! filter_var($url, FILTER_VALIDATE_URL)) {
|
|
||||||
$domainErrors[] = "Invalid URL: {$url}";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$scheme = parse_url($url, PHP_URL_SCHEME) ?? '';
|
|
||||||
if (! in_array(strtolower($scheme), ['http', 'https'])) {
|
|
||||||
$domainErrors[] = "Invalid URL scheme: {$scheme} for URL: {$url}. Only http and https are supported.";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return str($domainValue)->replaceStart(',', '')->replaceEnd(',', '')->trim()->explode(',')->map(fn ($url) => trim($url))->filter();
|
||||||
|
});
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
$urls = $urls->map(function ($url) use (&$errors) {
|
||||||
|
if (! filter_var($url, FILTER_VALIDATE_URL)) {
|
||||||
|
$errors[] = "Invalid URL: {$url}";
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
$scheme = parse_url($url, PHP_URL_SCHEME) ?? '';
|
||||||
|
if (! in_array(strtolower($scheme), ['http', 'https'])) {
|
||||||
|
$errors[] = "Invalid URL scheme: {$scheme} for URL: {$url}. Only http and https are supported.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
});
|
||||||
|
|
||||||
|
$duplicates = $urls->duplicates()->unique()->values();
|
||||||
|
if ($duplicates->isNotEmpty() && ! $request->boolean('force_domain_override')) {
|
||||||
|
$errors[] = 'The current request contains conflicting URLs: '.implode(', ', $duplicates->toArray()).' Use force_domain_override=true to proceed.';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($domainErrors)) {
|
if (count($errors) > 0) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Validation failed.',
|
'message' => 'Validation failed.',
|
||||||
'errors' => [
|
'errors' => ['docker_compose_domains' => $errors],
|
||||||
'docker_compose_domains' => $domainErrors,
|
|
||||||
],
|
|
||||||
], 422);
|
], 422);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for domain conflicts
|
||||||
|
if ($urls->isNotEmpty()) {
|
||||||
|
$result = checkIfDomainIsAlreadyUsedViaAPI($urls, $teamId, $request->uuid);
|
||||||
|
if (isset($result['error'])) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Validation failed.',
|
||||||
|
'errors' => ['docker_compose_domains' => $result['error']],
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result['hasConflicts'] && ! $request->boolean('force_domain_override')) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Domain conflicts detected. Use force_domain_override=true to proceed.',
|
||||||
|
'conflicts' => $result['conflicts'],
|
||||||
|
'warning' => 'Using the same domain for multiple resources can cause routing conflicts and unpredictable behavior.',
|
||||||
|
], 409);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$yaml = Yaml::parse($application->docker_compose_raw);
|
$yaml = Yaml::parse($application->docker_compose_raw);
|
||||||
$services = data_get($yaml, 'services', []);
|
$services = data_get($yaml, 'services', []);
|
||||||
$dockerComposeDomains->each(function ($domain) use ($services, $dockerComposeDomainsJson) {
|
$dockerComposeDomains->each(function ($domain) use ($services, $dockerComposeDomainsJson) {
|
||||||
@@ -2505,6 +2702,9 @@ class ApplicationsController extends Controller
|
|||||||
}
|
}
|
||||||
$instantDeploy = $request->instant_deploy;
|
$instantDeploy = $request->instant_deploy;
|
||||||
$isStatic = $request->is_static;
|
$isStatic = $request->is_static;
|
||||||
|
$isSpa = $request->is_spa;
|
||||||
|
$isAutoDeployEnabled = $request->is_auto_deploy_enabled;
|
||||||
|
$isForceHttpsEnabled = $request->is_force_https_enabled;
|
||||||
$connectToDockerNetwork = $request->connect_to_docker_network;
|
$connectToDockerNetwork = $request->connect_to_docker_network;
|
||||||
$useBuildServer = $request->use_build_server;
|
$useBuildServer = $request->use_build_server;
|
||||||
$isContainerLabelEscapeEnabled = $request->boolean('is_container_label_escape_enabled');
|
$isContainerLabelEscapeEnabled = $request->boolean('is_container_label_escape_enabled');
|
||||||
@@ -2519,6 +2719,21 @@ class ApplicationsController extends Controller
|
|||||||
$application->settings->save();
|
$application->settings->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($isSpa)) {
|
||||||
|
$application->settings->is_spa = $isSpa;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($isAutoDeployEnabled)) {
|
||||||
|
$application->settings->is_auto_deploy_enabled = $isAutoDeployEnabled;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($isForceHttpsEnabled)) {
|
||||||
|
$application->settings->is_force_https_enabled = $isForceHttpsEnabled;
|
||||||
|
$application->settings->save();
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($connectToDockerNetwork)) {
|
if (isset($connectToDockerNetwork)) {
|
||||||
$application->settings->connect_to_docker_network = $connectToDockerNetwork;
|
$application->settings->connect_to_docker_network = $connectToDockerNetwork;
|
||||||
$application->settings->save();
|
$application->settings->save();
|
||||||
@@ -3626,17 +3841,29 @@ class ApplicationsController extends Controller
|
|||||||
}
|
}
|
||||||
if ($request->has('domains') && $server->isProxyShouldRun()) {
|
if ($request->has('domains') && $server->isProxyShouldRun()) {
|
||||||
$uuid = $request->uuid;
|
$uuid = $request->uuid;
|
||||||
$fqdn = $request->domains;
|
$urls = $request->domains;
|
||||||
$fqdn = str($fqdn)->replaceEnd(',', '')->trim();
|
$urls = str($urls)->replaceEnd(',', '')->trim();
|
||||||
$fqdn = str($fqdn)->replaceStart(',', '')->trim();
|
$urls = str($urls)->replaceStart(',', '')->trim();
|
||||||
$errors = [];
|
$errors = [];
|
||||||
$fqdn = str($fqdn)->trim()->explode(',')->map(function ($domain) use (&$errors) {
|
$urls = str($urls)->trim()->explode(',')->map(function ($url) use (&$errors) {
|
||||||
$domain = trim($domain);
|
$url = trim($url);
|
||||||
if (filter_var($domain, FILTER_VALIDATE_URL) === false) {
|
|
||||||
$errors[] = 'Invalid domain: '.$domain;
|
// If "domains" is empty clear all URLs from the fqdn column
|
||||||
|
if (blank($url)) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return str($domain)->lower();
|
if (! filter_var($url, FILTER_VALIDATE_URL)) {
|
||||||
|
$errors[] = 'Invalid URL: '.$url;
|
||||||
|
|
||||||
|
return str($url)->lower();
|
||||||
|
}
|
||||||
|
$scheme = parse_url($url, PHP_URL_SCHEME) ?? '';
|
||||||
|
if (! in_array(strtolower($scheme), ['http', 'https'])) {
|
||||||
|
$errors[] = "Invalid URL scheme: {$scheme} for URL: {$url}. Only http and https are supported.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return str($url)->lower();
|
||||||
});
|
});
|
||||||
if (count($errors) > 0) {
|
if (count($errors) > 0) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@@ -3645,7 +3872,7 @@ class ApplicationsController extends Controller
|
|||||||
], 422);
|
], 422);
|
||||||
}
|
}
|
||||||
// Check for domain conflicts
|
// Check for domain conflicts
|
||||||
$result = checkIfDomainIsAlreadyUsedViaAPI($fqdn, $teamId, $uuid);
|
$result = checkIfDomainIsAlreadyUsedViaAPI($urls, $teamId, $uuid);
|
||||||
if (isset($result['error'])) {
|
if (isset($result['error'])) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'Validation failed.',
|
'message' => 'Validation failed.',
|
||||||
|
|||||||
@@ -86,8 +86,11 @@ function sharedDataApplications()
|
|||||||
'git_branch' => 'string',
|
'git_branch' => 'string',
|
||||||
'build_pack' => Rule::enum(BuildPackTypes::class),
|
'build_pack' => Rule::enum(BuildPackTypes::class),
|
||||||
'is_static' => 'boolean',
|
'is_static' => 'boolean',
|
||||||
|
'is_spa' => 'boolean',
|
||||||
|
'is_auto_deploy_enabled' => 'boolean',
|
||||||
|
'is_force_https_enabled' => 'boolean',
|
||||||
'static_image' => Rule::enum(StaticImageTypes::class),
|
'static_image' => Rule::enum(StaticImageTypes::class),
|
||||||
'domains' => 'string',
|
'domains' => 'string|nullable',
|
||||||
'redirect' => Rule::enum(RedirectTypes::class),
|
'redirect' => Rule::enum(RedirectTypes::class),
|
||||||
'git_commit_sha' => 'string',
|
'git_commit_sha' => 'string',
|
||||||
'docker_registry_image_name' => 'string|nullable',
|
'docker_registry_image_name' => 'string|nullable',
|
||||||
@@ -129,6 +132,7 @@ function sharedDataApplications()
|
|||||||
'manual_webhook_secret_gitlab' => 'string|nullable',
|
'manual_webhook_secret_gitlab' => 'string|nullable',
|
||||||
'manual_webhook_secret_bitbucket' => 'string|nullable',
|
'manual_webhook_secret_bitbucket' => 'string|nullable',
|
||||||
'manual_webhook_secret_gitea' => 'string|nullable',
|
'manual_webhook_secret_gitea' => 'string|nullable',
|
||||||
|
'dockerfile_location' => 'string|nullable',
|
||||||
'docker_compose_location' => 'string',
|
'docker_compose_location' => 'string',
|
||||||
'docker_compose' => 'string|nullable',
|
'docker_compose' => 'string|nullable',
|
||||||
'docker_compose_domains' => 'array|nullable',
|
'docker_compose_domains' => 'array|nullable',
|
||||||
@@ -177,6 +181,10 @@ function removeUnnecessaryFieldsFromRequest(Request $request)
|
|||||||
$request->offsetUnset('private_key_uuid');
|
$request->offsetUnset('private_key_uuid');
|
||||||
$request->offsetUnset('use_build_server');
|
$request->offsetUnset('use_build_server');
|
||||||
$request->offsetUnset('is_static');
|
$request->offsetUnset('is_static');
|
||||||
|
$request->offsetUnset('is_spa');
|
||||||
|
$request->offsetUnset('is_auto_deploy_enabled');
|
||||||
|
$request->offsetUnset('is_force_https_enabled');
|
||||||
|
$request->offsetUnset('connect_to_docker_network');
|
||||||
$request->offsetUnset('force_domain_override');
|
$request->offsetUnset('force_domain_override');
|
||||||
$request->offsetUnset('autogenerate_domain');
|
$request->offsetUnset('autogenerate_domain');
|
||||||
$request->offsetUnset('is_container_label_escape_enabled');
|
$request->offsetUnset('is_container_label_escape_enabled');
|
||||||
|
|||||||
@@ -158,8 +158,7 @@ function checkIfDomainIsAlreadyUsedViaAPI(Collection|array $domains, ?string $te
|
|||||||
return str($domain);
|
return str($domain);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check applications within the same team
|
$applications = Application::ownedByCurrentTeamAPI($teamId)->get(['fqdn', 'uuid', 'name', 'id', 'docker_compose_domains', 'build_pack']);
|
||||||
$applications = Application::ownedByCurrentTeamAPI($teamId)->get(['fqdn', 'uuid', 'name', 'id']);
|
|
||||||
$serviceApplications = ServiceApplication::ownedByCurrentTeamAPI($teamId)->with('service:id,name')->get(['fqdn', 'uuid', 'id', 'service_id']);
|
$serviceApplications = ServiceApplication::ownedByCurrentTeamAPI($teamId)->with('service:id,name')->get(['fqdn', 'uuid', 'id', 'service_id']);
|
||||||
|
|
||||||
if ($uuid) {
|
if ($uuid) {
|
||||||
@@ -168,23 +167,51 @@ function checkIfDomainIsAlreadyUsedViaAPI(Collection|array $domains, ?string $te
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($applications as $app) {
|
foreach ($applications as $app) {
|
||||||
if (is_null($app->fqdn)) {
|
if (! is_null($app->fqdn)) {
|
||||||
continue;
|
$list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== '');
|
||||||
}
|
foreach ($list_of_domains as $domain) {
|
||||||
$list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== '');
|
if (str($domain)->endsWith('/')) {
|
||||||
foreach ($list_of_domains as $domain) {
|
$domain = str($domain)->beforeLast('/');
|
||||||
if (str($domain)->endsWith('/')) {
|
}
|
||||||
$domain = str($domain)->beforeLast('/');
|
$naked_domain = str($domain)->value();
|
||||||
|
if ($domains->contains($naked_domain)) {
|
||||||
|
$conflicts[] = [
|
||||||
|
'domain' => $naked_domain,
|
||||||
|
'resource_name' => $app->name,
|
||||||
|
'resource_uuid' => $app->uuid,
|
||||||
|
'resource_type' => 'application',
|
||||||
|
'message' => "Domain $naked_domain is already in use by application '{$app->name}'",
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$naked_domain = str($domain)->value();
|
}
|
||||||
if ($domains->contains($naked_domain)) {
|
|
||||||
$conflicts[] = [
|
if ($app->build_pack === 'dockercompose' && ! empty($app->docker_compose_domains)) {
|
||||||
'domain' => $naked_domain,
|
$dockerComposeDomains = json_decode($app->docker_compose_domains, true);
|
||||||
'resource_name' => $app->name,
|
if (is_array($dockerComposeDomains)) {
|
||||||
'resource_uuid' => $app->uuid,
|
foreach ($dockerComposeDomains as $serviceName => $domainConfig) {
|
||||||
'resource_type' => 'application',
|
$domainValue = data_get($domainConfig, 'domain');
|
||||||
'message' => "Domain $naked_domain is already in use by application '{$app->name}'",
|
if (empty($domainValue)) {
|
||||||
];
|
continue;
|
||||||
|
}
|
||||||
|
$list_of_domains = collect(explode(',', $domainValue))->filter(fn ($fqdn) => $fqdn !== '');
|
||||||
|
foreach ($list_of_domains as $domain) {
|
||||||
|
if (str($domain)->endsWith('/')) {
|
||||||
|
$domain = str($domain)->beforeLast('/');
|
||||||
|
}
|
||||||
|
$naked_domain = str($domain)->value();
|
||||||
|
if ($domains->contains($naked_domain)) {
|
||||||
|
$conflicts[] = [
|
||||||
|
'domain' => $naked_domain,
|
||||||
|
'resource_name' => $app->name,
|
||||||
|
'resource_uuid' => $app->uuid,
|
||||||
|
'resource_type' => 'application',
|
||||||
|
'service_name' => $serviceName,
|
||||||
|
'message' => "Domain $naked_domain is already in use by application '{$app->name}' (service: {$serviceName})",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
84
openapi.json
84
openapi.json
@@ -135,7 +135,7 @@
|
|||||||
},
|
},
|
||||||
"domains": {
|
"domains": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The application domains."
|
"description": "The application URLs in a comma-separated list."
|
||||||
},
|
},
|
||||||
"git_commit_sha": {
|
"git_commit_sha": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -153,6 +153,18 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "The flag to indicate if the application is static."
|
"description": "The flag to indicate if the application is static."
|
||||||
},
|
},
|
||||||
|
"is_spa": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true."
|
||||||
|
},
|
||||||
|
"is_auto_deploy_enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if auto-deploy is enabled on git push. Defaults to true."
|
||||||
|
},
|
||||||
|
"is_force_https_enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if HTTPS is forced. Defaults to true."
|
||||||
|
},
|
||||||
"static_image": {
|
"static_image": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
@@ -322,6 +334,10 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The Dockerfile content."
|
"description": "The Dockerfile content."
|
||||||
},
|
},
|
||||||
|
"dockerfile_location": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The Dockerfile location in the repository."
|
||||||
|
},
|
||||||
"docker_compose_location": {
|
"docker_compose_location": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The Docker Compose location."
|
"description": "The Docker Compose location."
|
||||||
@@ -564,7 +580,7 @@
|
|||||||
},
|
},
|
||||||
"domains": {
|
"domains": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The application domains."
|
"description": "The application URLs in a comma-separated list."
|
||||||
},
|
},
|
||||||
"git_commit_sha": {
|
"git_commit_sha": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -582,6 +598,18 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "The flag to indicate if the application is static."
|
"description": "The flag to indicate if the application is static."
|
||||||
},
|
},
|
||||||
|
"is_spa": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true."
|
||||||
|
},
|
||||||
|
"is_auto_deploy_enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if auto-deploy is enabled on git push. Defaults to true."
|
||||||
|
},
|
||||||
|
"is_force_https_enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if HTTPS is forced. Defaults to true."
|
||||||
|
},
|
||||||
"static_image": {
|
"static_image": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
@@ -751,6 +779,10 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The Dockerfile content."
|
"description": "The Dockerfile content."
|
||||||
},
|
},
|
||||||
|
"dockerfile_location": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The Dockerfile location in the repository"
|
||||||
|
},
|
||||||
"docker_compose_location": {
|
"docker_compose_location": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The Docker Compose location."
|
"description": "The Docker Compose location."
|
||||||
@@ -993,7 +1025,7 @@
|
|||||||
},
|
},
|
||||||
"domains": {
|
"domains": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The application domains."
|
"description": "The application URLs in a comma-separated list."
|
||||||
},
|
},
|
||||||
"git_commit_sha": {
|
"git_commit_sha": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -1011,6 +1043,18 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "The flag to indicate if the application is static."
|
"description": "The flag to indicate if the application is static."
|
||||||
},
|
},
|
||||||
|
"is_spa": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true."
|
||||||
|
},
|
||||||
|
"is_auto_deploy_enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if auto-deploy is enabled on git push. Defaults to true."
|
||||||
|
},
|
||||||
|
"is_force_https_enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if HTTPS is forced. Defaults to true."
|
||||||
|
},
|
||||||
"static_image": {
|
"static_image": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
@@ -1180,6 +1224,10 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The Dockerfile content."
|
"description": "The Dockerfile content."
|
||||||
},
|
},
|
||||||
|
"dockerfile_location": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The Dockerfile location in the repository."
|
||||||
|
},
|
||||||
"docker_compose_location": {
|
"docker_compose_location": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The Docker Compose location."
|
"description": "The Docker Compose location."
|
||||||
@@ -1410,7 +1458,7 @@
|
|||||||
},
|
},
|
||||||
"domains": {
|
"domains": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The application domains."
|
"description": "The application URLs in a comma-separated list."
|
||||||
},
|
},
|
||||||
"docker_registry_image_name": {
|
"docker_registry_image_name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -1562,6 +1610,10 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "The flag to indicate if the application should be deployed instantly."
|
"description": "The flag to indicate if the application should be deployed instantly."
|
||||||
},
|
},
|
||||||
|
"is_force_https_enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if HTTPS is forced. Defaults to true."
|
||||||
|
},
|
||||||
"use_build_server": {
|
"use_build_server": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
@@ -1754,7 +1806,7 @@
|
|||||||
},
|
},
|
||||||
"domains": {
|
"domains": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The application domains."
|
"description": "The application URLs in a comma-separated list."
|
||||||
},
|
},
|
||||||
"ports_mappings": {
|
"ports_mappings": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -1894,6 +1946,10 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "The flag to indicate if the application should be deployed instantly."
|
"description": "The flag to indicate if the application should be deployed instantly."
|
||||||
},
|
},
|
||||||
|
"is_force_https_enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if HTTPS is forced. Defaults to true."
|
||||||
|
},
|
||||||
"use_build_server": {
|
"use_build_server": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
@@ -2402,7 +2458,7 @@
|
|||||||
},
|
},
|
||||||
"domains": {
|
"domains": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The application domains."
|
"description": "The application URLs in a comma-separated list."
|
||||||
},
|
},
|
||||||
"git_commit_sha": {
|
"git_commit_sha": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -2420,6 +2476,18 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "The flag to indicate if the application is static."
|
"description": "The flag to indicate if the application is static."
|
||||||
},
|
},
|
||||||
|
"is_spa": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true."
|
||||||
|
},
|
||||||
|
"is_auto_deploy_enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if auto-deploy is enabled on git push. Defaults to true."
|
||||||
|
},
|
||||||
|
"is_force_https_enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "The flag to indicate if HTTPS is forced. Defaults to true."
|
||||||
|
},
|
||||||
"install_command": {
|
"install_command": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The install command."
|
"description": "The install command."
|
||||||
@@ -2582,6 +2650,10 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The Dockerfile content."
|
"description": "The Dockerfile content."
|
||||||
},
|
},
|
||||||
|
"dockerfile_location": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The Dockerfile location in the repository."
|
||||||
|
},
|
||||||
"docker_compose_location": {
|
"docker_compose_location": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The Docker Compose location."
|
"description": "The Docker Compose location."
|
||||||
|
|||||||
66
openapi.yaml
66
openapi.yaml
@@ -97,7 +97,7 @@ paths:
|
|||||||
description: 'The application description.'
|
description: 'The application description.'
|
||||||
domains:
|
domains:
|
||||||
type: string
|
type: string
|
||||||
description: 'The application domains.'
|
description: 'The application URLs in a comma-separated list.'
|
||||||
git_commit_sha:
|
git_commit_sha:
|
||||||
type: string
|
type: string
|
||||||
description: 'The git commit SHA.'
|
description: 'The git commit SHA.'
|
||||||
@@ -110,6 +110,15 @@ paths:
|
|||||||
is_static:
|
is_static:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 'The flag to indicate if the application is static.'
|
description: 'The flag to indicate if the application is static.'
|
||||||
|
is_spa:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true.'
|
||||||
|
is_auto_deploy_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if auto-deploy is enabled on git push. Defaults to true.'
|
||||||
|
is_force_https_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if HTTPS is forced. Defaults to true.'
|
||||||
static_image:
|
static_image:
|
||||||
type: string
|
type: string
|
||||||
enum: ['nginx:alpine']
|
enum: ['nginx:alpine']
|
||||||
@@ -234,6 +243,9 @@ paths:
|
|||||||
dockerfile:
|
dockerfile:
|
||||||
type: string
|
type: string
|
||||||
description: 'The Dockerfile content.'
|
description: 'The Dockerfile content.'
|
||||||
|
dockerfile_location:
|
||||||
|
type: string
|
||||||
|
description: 'The Dockerfile location in the repository.'
|
||||||
docker_compose_location:
|
docker_compose_location:
|
||||||
type: string
|
type: string
|
||||||
description: 'The Docker Compose location.'
|
description: 'The Docker Compose location.'
|
||||||
@@ -369,7 +381,7 @@ paths:
|
|||||||
description: 'The application description.'
|
description: 'The application description.'
|
||||||
domains:
|
domains:
|
||||||
type: string
|
type: string
|
||||||
description: 'The application domains.'
|
description: 'The application URLs in a comma-separated list.'
|
||||||
git_commit_sha:
|
git_commit_sha:
|
||||||
type: string
|
type: string
|
||||||
description: 'The git commit SHA.'
|
description: 'The git commit SHA.'
|
||||||
@@ -382,6 +394,15 @@ paths:
|
|||||||
is_static:
|
is_static:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 'The flag to indicate if the application is static.'
|
description: 'The flag to indicate if the application is static.'
|
||||||
|
is_spa:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true.'
|
||||||
|
is_auto_deploy_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if auto-deploy is enabled on git push. Defaults to true.'
|
||||||
|
is_force_https_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if HTTPS is forced. Defaults to true.'
|
||||||
static_image:
|
static_image:
|
||||||
type: string
|
type: string
|
||||||
enum: ['nginx:alpine']
|
enum: ['nginx:alpine']
|
||||||
@@ -506,6 +527,9 @@ paths:
|
|||||||
dockerfile:
|
dockerfile:
|
||||||
type: string
|
type: string
|
||||||
description: 'The Dockerfile content.'
|
description: 'The Dockerfile content.'
|
||||||
|
dockerfile_location:
|
||||||
|
type: string
|
||||||
|
description: 'The Dockerfile location in the repository'
|
||||||
docker_compose_location:
|
docker_compose_location:
|
||||||
type: string
|
type: string
|
||||||
description: 'The Docker Compose location.'
|
description: 'The Docker Compose location.'
|
||||||
@@ -641,7 +665,7 @@ paths:
|
|||||||
description: 'The application description.'
|
description: 'The application description.'
|
||||||
domains:
|
domains:
|
||||||
type: string
|
type: string
|
||||||
description: 'The application domains.'
|
description: 'The application URLs in a comma-separated list.'
|
||||||
git_commit_sha:
|
git_commit_sha:
|
||||||
type: string
|
type: string
|
||||||
description: 'The git commit SHA.'
|
description: 'The git commit SHA.'
|
||||||
@@ -654,6 +678,15 @@ paths:
|
|||||||
is_static:
|
is_static:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 'The flag to indicate if the application is static.'
|
description: 'The flag to indicate if the application is static.'
|
||||||
|
is_spa:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true.'
|
||||||
|
is_auto_deploy_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if auto-deploy is enabled on git push. Defaults to true.'
|
||||||
|
is_force_https_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if HTTPS is forced. Defaults to true.'
|
||||||
static_image:
|
static_image:
|
||||||
type: string
|
type: string
|
||||||
enum: ['nginx:alpine']
|
enum: ['nginx:alpine']
|
||||||
@@ -778,6 +811,9 @@ paths:
|
|||||||
dockerfile:
|
dockerfile:
|
||||||
type: string
|
type: string
|
||||||
description: 'The Dockerfile content.'
|
description: 'The Dockerfile content.'
|
||||||
|
dockerfile_location:
|
||||||
|
type: string
|
||||||
|
description: 'The Dockerfile location in the repository.'
|
||||||
docker_compose_location:
|
docker_compose_location:
|
||||||
type: string
|
type: string
|
||||||
description: 'The Docker Compose location.'
|
description: 'The Docker Compose location.'
|
||||||
@@ -903,7 +939,7 @@ paths:
|
|||||||
description: 'The application description.'
|
description: 'The application description.'
|
||||||
domains:
|
domains:
|
||||||
type: string
|
type: string
|
||||||
description: 'The application domains.'
|
description: 'The application URLs in a comma-separated list.'
|
||||||
docker_registry_image_name:
|
docker_registry_image_name:
|
||||||
type: string
|
type: string
|
||||||
description: 'The docker registry image name.'
|
description: 'The docker registry image name.'
|
||||||
@@ -1015,6 +1051,9 @@ paths:
|
|||||||
instant_deploy:
|
instant_deploy:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 'The flag to indicate if the application should be deployed instantly.'
|
description: 'The flag to indicate if the application should be deployed instantly.'
|
||||||
|
is_force_https_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if HTTPS is forced. Defaults to true.'
|
||||||
use_build_server:
|
use_build_server:
|
||||||
type: boolean
|
type: boolean
|
||||||
nullable: true
|
nullable: true
|
||||||
@@ -1124,7 +1163,7 @@ paths:
|
|||||||
description: 'The application description.'
|
description: 'The application description.'
|
||||||
domains:
|
domains:
|
||||||
type: string
|
type: string
|
||||||
description: 'The application domains.'
|
description: 'The application URLs in a comma-separated list.'
|
||||||
ports_mappings:
|
ports_mappings:
|
||||||
type: string
|
type: string
|
||||||
description: 'The ports mappings.'
|
description: 'The ports mappings.'
|
||||||
@@ -1227,6 +1266,9 @@ paths:
|
|||||||
instant_deploy:
|
instant_deploy:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 'The flag to indicate if the application should be deployed instantly.'
|
description: 'The flag to indicate if the application should be deployed instantly.'
|
||||||
|
is_force_https_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if HTTPS is forced. Defaults to true.'
|
||||||
use_build_server:
|
use_build_server:
|
||||||
type: boolean
|
type: boolean
|
||||||
nullable: true
|
nullable: true
|
||||||
@@ -1524,7 +1566,7 @@ paths:
|
|||||||
description: 'The application description.'
|
description: 'The application description.'
|
||||||
domains:
|
domains:
|
||||||
type: string
|
type: string
|
||||||
description: 'The application domains.'
|
description: 'The application URLs in a comma-separated list.'
|
||||||
git_commit_sha:
|
git_commit_sha:
|
||||||
type: string
|
type: string
|
||||||
description: 'The git commit SHA.'
|
description: 'The git commit SHA.'
|
||||||
@@ -1537,6 +1579,15 @@ paths:
|
|||||||
is_static:
|
is_static:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 'The flag to indicate if the application is static.'
|
description: 'The flag to indicate if the application is static.'
|
||||||
|
is_spa:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if the application is a single-page application (SPA). Only relevant when is_static is true.'
|
||||||
|
is_auto_deploy_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if auto-deploy is enabled on git push. Defaults to true.'
|
||||||
|
is_force_https_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to indicate if HTTPS is forced. Defaults to true.'
|
||||||
install_command:
|
install_command:
|
||||||
type: string
|
type: string
|
||||||
description: 'The install command.'
|
description: 'The install command.'
|
||||||
@@ -1657,6 +1708,9 @@ paths:
|
|||||||
dockerfile:
|
dockerfile:
|
||||||
type: string
|
type: string
|
||||||
description: 'The Dockerfile content.'
|
description: 'The Dockerfile content.'
|
||||||
|
dockerfile_location:
|
||||||
|
type: string
|
||||||
|
description: 'The Dockerfile location in the repository.'
|
||||||
docker_compose_location:
|
docker_compose_location:
|
||||||
type: string
|
type: string
|
||||||
description: 'The Docker Compose location.'
|
description: 'The Docker Compose location.'
|
||||||
|
|||||||
Reference in New Issue
Block a user