From 82923bffdfb377de558c9030cf3e3787f736d236 Mon Sep 17 00:00:00 2001
From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com>
Date: Sun, 16 Mar 2025 23:08:49 +0100
Subject: [PATCH] feat(core): create empty skeleton
---
.coolify-logo | 8 -
.dockerignore | 38 -
.env.development.example | 34 -
.env.dusk.ci | 15 -
.env.example | 65 +
.env.production | 16 -
.env.windows-docker-desktop.example | 13 -
.gitattributes | 2 +-
.github/FUNDING.yaml | 2 -
.github/ISSUE_TEMPLATE/01_BUG_REPORT.yml | 65 -
.../ISSUE_TEMPLATE/02_ENHANCEMENT_BOUNTY.yml | 31 -
.github/ISSUE_TEMPLATE/config.yml | 18 -
.github/pull_request_template.md | 13 -
.github/workflows/browser-tests.yml | 65 -
...lock-closed-issues-discussions-and-prs.yml | 17 -
.../chore-manage-stale-issues-and-prs.yml | 28 -
...e-remove-labels-and-assignees-on-close.yml | 82 -
.github/workflows/coolify-helper-next.yml | 142 -
.github/workflows/coolify-helper.yml | 142 -
.../workflows/coolify-production-build.yml | 140 -
.github/workflows/coolify-realtime-next.yml | 147 -
.github/workflows/coolify-realtime.yml | 147 -
.github/workflows/coolify-staging-build.yml | 126 -
.github/workflows/coolify-testing-host.yml | 126 -
.github/workflows/generate-changelog.yml | 36 -
.gitignore | 27 +-
CHANGELOG.md | 6844 ---
CODE_OF_CONDUCT.md | 94 -
CONTRIBUTING.md | 245 -
LICENSE | 201 -
README.md | 170 +-
RELEASE.md | 133 -
SECURITY.md | 25 -
TECH_STACK.md | 29 -
app/Actions/Application/GenerateConfig.php | 16 -
.../Application/IsHorizonQueueEmpty.php | 37 -
app/Actions/Application/LoadComposeFile.php | 16 -
app/Actions/Application/StopApplication.php | 43 -
.../Application/StopApplicationOneServer.php | 38 -
.../CoolifyTask/PrepareCoolifyTask.php | 54 -
app/Actions/CoolifyTask/RunRemoteProcess.php | 198 -
app/Actions/Database/RestartDatabase.php | 29 -
app/Actions/Database/StartClickhouse.php | 165 -
app/Actions/Database/StartDatabase.php | 59 -
app/Actions/Database/StartDatabaseProxy.php | 117 -
app/Actions/Database/StartDragonfly.php | 156 -
app/Actions/Database/StartKeydb.php | 180 -
app/Actions/Database/StartMariadb.php | 185 -
app/Actions/Database/StartMongodb.php | 210 -
app/Actions/Database/StartMysql.php | 185 -
app/Actions/Database/StartPostgresql.php | 236 -
app/Actions/Database/StartRedis.php | 219 -
app/Actions/Database/StopDatabase.php | 75 -
app/Actions/Database/StopDatabaseProxy.php | 38 -
app/Actions/Docker/GetContainersStatus.php | 345 -
app/Actions/Fortify/CreateNewUser.php | 70 -
app/Actions/Fortify/ResetUserPassword.php | 28 -
app/Actions/Fortify/UpdateUserPassword.php | 31 -
.../Fortify/UpdateUserProfileInformation.php | 60 -
app/Actions/Proxy/CheckConfiguration.php | 33 -
app/Actions/Proxy/CheckProxy.php | 111 -
app/Actions/Proxy/SaveConfiguration.php | 28 -
app/Actions/Proxy/StartProxy.php | 78 -
app/Actions/Server/CleanupDocker.php | 49 -
app/Actions/Server/ConfigureCloudflared.php | 55 -
app/Actions/Server/DeleteServer.php | 17 -
app/Actions/Server/InstallDocker.php | 109 -
app/Actions/Server/ResourcesCheck.php | 41 -
app/Actions/Server/RestartContainer.php | 16 -
app/Actions/Server/RunCommand.php | 17 -
app/Actions/Server/ServerCheck.php | 267 -
app/Actions/Server/StartLogDrain.php | 223 -
app/Actions/Server/StartSentinel.php | 65 -
app/Actions/Server/StopLogDrain.php | 20 -
app/Actions/Server/StopSentinel.php | 17 -
app/Actions/Server/UpdateCoolify.php | 62 -
app/Actions/Server/ValidateServer.php | 69 -
app/Actions/Service/DeleteService.php | 78 -
app/Actions/Service/RestartService.php | 20 -
app/Actions/Service/StartService.php | 46 -
app/Actions/Service/StopService.php | 36 -
app/Actions/Shared/ComplexStatusCheck.php | 60 -
app/Console/Commands/AdminRemoveUser.php | 56 -
.../CheckApplicationDeploymentQueue.php | 50 -
.../CleanupApplicationDeploymentQueue.php | 26 -
app/Console/Commands/CleanupDatabase.php | 76 -
app/Console/Commands/CleanupRedis.php | 29 -
.../Commands/CleanupStuckedResources.php | 414 -
.../Commands/CleanupUnreachableServers.php | 27 -
.../Commands/CloudCheckSubscription.php | 49 -
.../Commands/CloudCleanupSubscriptions.php | 101 -
app/Console/Commands/Dev.php | 80 -
app/Console/Commands/Emails.php | 277 -
app/Console/Commands/Horizon.php | 23 -
app/Console/Commands/HorizonManage.php | 178 -
app/Console/Commands/Init.php | 273 -
app/Console/Commands/Migration.php | 24 -
app/Console/Commands/NotifyDemo.php | 78 -
app/Console/Commands/OpenApi.php | 33 -
app/Console/Commands/RootChangeEmail.php | 42 -
app/Console/Commands/RootResetPassword.php | 50 -
app/Console/Commands/Scheduler.php | 23 -
app/Console/Commands/Seeder.php | 24 -
app/Console/Commands/ServicesDelete.php | 155 -
app/Console/Commands/ServicesGenerate.php | 89 -
app/Console/Commands/SyncBunny.php | 159 -
app/Console/Kernel.php | 312 -
.../CustomJobRepositoryInterface.php | 19 -
app/Data/CoolifyTaskArgs.php | 30 -
app/Data/ServerMetadata.php | 15 -
app/Enums/ActivityTypes.php | 9 -
app/Enums/ApplicationDeploymentStatus.php | 12 -
app/Enums/BuildPackTypes.php | 11 -
app/Enums/ContainerStatusTypes.php | 14 -
app/Enums/NewDatabaseTypes.php | 15 -
app/Enums/NewResourceTypes.php | 22 -
app/Enums/ProcessStatus.php | 14 -
app/Enums/ProxyTypes.php | 17 -
app/Enums/RedirectTypes.php | 10 -
app/Enums/Role.php | 37 -
app/Enums/StaticImageTypes.php | 8 -
app/Events/ApplicationStatusChanged.php | 34 -
app/Events/BackupCreated.php | 34 -
app/Events/CloudflareTunnelConfigured.php | 34 -
app/Events/DatabaseProxyStopped.php | 35 -
app/Events/DatabaseStatusChanged.php | 40 -
app/Events/DockerCleanupDone.php | 24 -
app/Events/FileStorageChanged.php | 31 -
app/Events/ProxyStarted.php | 14 -
app/Events/ProxyStatusChanged.php | 34 -
app/Events/RestoreJobFinished.php | 34 -
app/Events/ScheduledTaskDone.php | 34 -
app/Events/ServerReachabilityChanged.php | 17 -
app/Events/ServiceStatusChanged.php | 39 -
app/Events/TestEvent.php | 28 -
app/Exceptions/Handler.php | 90 -
app/Exceptions/ProcessException.php | 7 -
app/Helpers/SshMultiplexingHelper.php | 185 -
.../Api/ApplicationsController.php | 3056 -
.../Controllers/Api/DatabasesController.php | 1852 -
app/Http/Controllers/Api/DeployController.php | 317 -
app/Http/Controllers/Api/OpenApi.php | 51 -
app/Http/Controllers/Api/OtherController.php | 187 -
.../Controllers/Api/ProjectController.php | 438 -
.../Controllers/Api/ResourcesController.php | 64 -
.../Controllers/Api/SecurityController.php | 393 -
.../Controllers/Api/ServersController.php | 814 -
.../Controllers/Api/ServicesController.php | 1261 -
app/Http/Controllers/Api/TeamController.php | 273 -
app/Http/Controllers/Controller.php | 161 -
app/Http/Controllers/MagicController.php | 84 -
app/Http/Controllers/OauthController.php | 43 -
app/Http/Controllers/UploadController.php | 81 -
app/Http/Controllers/Webhook/Bitbucket.php | 194 -
app/Http/Controllers/Webhook/Gitea.php | 227 -
app/Http/Controllers/Webhook/Github.php | 518 -
app/Http/Controllers/Webhook/Gitlab.php | 259 -
app/Http/Controllers/Webhook/Stripe.php | 59 -
app/Http/Kernel.php | 75 -
app/Http/Middleware/ApiAbility.php | 27 -
app/Http/Middleware/ApiAllowed.php | 32 -
app/Http/Middleware/ApiSensitiveData.php | 21 -
app/Http/Middleware/Authenticate.php | 17 -
.../Middleware/CheckForcePasswordReset.php | 38 -
.../Middleware/DecideWhatToDoWithUser.php | 61 -
app/Http/Middleware/EncryptCookies.php | 17 -
.../PreventRequestsDuringMaintenance.php | 18 -
.../Middleware/RedirectIfAuthenticated.php | 30 -
app/Http/Middleware/TrimStrings.php | 19 -
app/Http/Middleware/TrustHosts.php | 20 -
app/Http/Middleware/TrustProxies.php | 28 -
app/Http/Middleware/ValidateSignature.php | 22 -
app/Http/Middleware/VerifyCsrfToken.php | 17 -
app/Jobs/ApplicationDeploymentJob.php | 2460 -
app/Jobs/ApplicationPullRequestUpdateJob.php | 89 -
app/Jobs/CheckAndStartSentinelJob.php | 52 -
app/Jobs/CheckForUpdatesJob.php | 44 -
app/Jobs/CheckHelperImageJob.php | 39 -
app/Jobs/CleanupHelperContainersJob.php | 34 -
app/Jobs/CleanupInstanceStuffsJob.php | 43 -
.../CleanupStaleMultiplexedConnections.php | 82 -
app/Jobs/ContainerStatusJob.php | 31 -
app/Jobs/CoolifyTask.php | 45 -
app/Jobs/DatabaseBackupJob.php | 520 -
app/Jobs/DeleteResourceJob.php | 101 -
app/Jobs/DockerCleanupJob.php | 131 -
app/Jobs/GithubAppPermissionJob.php | 57 -
app/Jobs/PullHelperImageJob.php | 30 -
app/Jobs/PullTemplatesFromCDN.php | 42 -
app/Jobs/PushServerUpdateJob.php | 372 -
app/Jobs/ScheduledTaskJob.php | 142 -
app/Jobs/SendMessageToDiscordJob.php | 46 -
app/Jobs/SendMessageToPushoverJob.php | 50 -
app/Jobs/SendMessageToSlackJob.php | 60 -
app/Jobs/SendMessageToTelegramJob.php | 78 -
app/Jobs/ServerCheckJob.php | 103 -
app/Jobs/ServerCheckNewJob.php | 34 -
app/Jobs/ServerCleanupMux.php | 40 -
app/Jobs/ServerFilesFromServerJob.php | 28 -
app/Jobs/ServerLimitCheckJob.php | 55 -
app/Jobs/ServerStorageCheckJob.php | 65 -
app/Jobs/ServerStorageSaveJob.php | 26 -
app/Jobs/StripeProcessJob.php | 291 -
app/Jobs/SubscriptionInvoiceFailedJob.php | 42 -
app/Jobs/UpdateCoolifyJob.php | 54 -
app/Jobs/VolumeCloneJob.php | 104 -
.../MaintenanceModeDisabledNotification.php | 48 -
.../MaintenanceModeEnabledNotification.php | 21 -
app/Listeners/ProxyStartedNotification.php | 22 -
app/Livewire/ActivityMonitor.php | 67 -
app/Livewire/Admin/Index.php | 81 -
app/Livewire/Boarding/Index.php | 383 -
app/Livewire/Dashboard.php | 61 -
app/Livewire/Destination/Index.php | 23 -
app/Livewire/Destination/New/Docker.php | 99 -
app/Livewire/Destination/Show.php | 95 -
app/Livewire/ForcePasswordReset.php | 64 -
app/Livewire/Help.php | 58 -
app/Livewire/LayoutPopups.php | 27 -
app/Livewire/MonacoEditor.php | 51 -
app/Livewire/NavbarDeleteTeam.php | 53 -
app/Livewire/NewActivityMonitor.php | 74 -
app/Livewire/Notifications/Discord.php | 168 -
app/Livewire/Notifications/Email.php | 372 -
app/Livewire/Notifications/Pushover.php | 184 -
app/Livewire/Notifications/Slack.php | 177 -
app/Livewire/Notifications/Telegram.php | 245 -
app/Livewire/Profile/Index.php | 82 -
app/Livewire/Project/AddEmpty.php | 34 -
app/Livewire/Project/Application/Advanced.php | 228 -
.../Project/Application/Configuration.php | 48 -
.../Project/Application/Deployment/Index.php | 113 -
.../Project/Application/Deployment/Show.php | 94 -
.../Project/Application/DeploymentNavbar.php | 91 -
app/Livewire/Project/Application/General.php | 458 -
app/Livewire/Project/Application/Heading.php | 151 -
.../Project/Application/Preview/Form.php | 63 -
app/Livewire/Project/Application/Previews.php | 279 -
.../Project/Application/PreviewsCompose.php | 61 -
app/Livewire/Project/Application/Rollback.php | 80 -
app/Livewire/Project/Application/Source.php | 95 -
app/Livewire/Project/Application/Swarm.php | 75 -
app/Livewire/Project/CloneMe.php | 568 -
.../Project/Database/Backup/Execution.php | 48 -
.../Project/Database/Backup/Index.php | 45 -
app/Livewire/Project/Database/BackupEdit.php | 218 -
.../Project/Database/BackupExecutions.php | 129 -
app/Livewire/Project/Database/BackupNow.php | 17 -
.../Project/Database/Clickhouse/General.php | 182 -
.../Project/Database/Configuration.php | 47 -
.../Database/CreateScheduledBackup.php | 84 -
.../Project/Database/Dragonfly/General.php | 177 -
app/Livewire/Project/Database/Heading.php | 88 -
app/Livewire/Project/Database/Import.php | 253 -
app/Livewire/Project/Database/InitScript.php | 56 -
.../Project/Database/Keydb/General.php | 182 -
.../Project/Database/Mariadb/General.php | 139 -
.../Project/Database/Mongodb/General.php | 140 -
.../Project/Database/Mysql/General.php | 139 -
.../Project/Database/Postgresql/General.php | 261 -
.../Project/Database/Redis/General.php | 163 -
.../Project/Database/ScheduledBackups.php | 66 -
app/Livewire/Project/DeleteEnvironment.php | 42 -
app/Livewire/Project/DeleteProject.php | 38 -
app/Livewire/Project/Edit.php | 52 -
app/Livewire/Project/EnvironmentEdit.php | 68 -
app/Livewire/Project/Index.php | 40 -
app/Livewire/Project/New/DockerCompose.php | 101 -
app/Livewire/Project/New/DockerImage.php | 80 -
app/Livewire/Project/New/EmptyProject.php | 21 -
.../Project/New/GithubPrivateRepository.php | 233 -
.../New/GithubPrivateRepositoryDeployKey.php | 215 -
.../Project/New/PublicGitRepository.php | 340 -
app/Livewire/Project/New/Select.php | 337 -
app/Livewire/Project/New/SimpleDockerfile.php | 85 -
app/Livewire/Project/Resource/Create.php | 123 -
.../Project/Resource/EnvironmentSelect.php | 35 -
app/Livewire/Project/Resource/Index.php | 132 -
.../Project/Service/Configuration.php | 109 -
app/Livewire/Project/Service/Database.php | 129 -
app/Livewire/Project/Service/EditCompose.php | 72 -
app/Livewire/Project/Service/EditDomain.php | 65 -
app/Livewire/Project/Service/FileStorage.php | 152 -
app/Livewire/Project/Service/Index.php | 62 -
app/Livewire/Project/Service/Navbar.php | 154 -
.../Service/ServiceApplicationView.php | 123 -
app/Livewire/Project/Service/StackForm.php | 101 -
app/Livewire/Project/Service/Storage.php | 65 -
.../Project/Shared/ConfigurationChecker.php | 39 -
app/Livewire/Project/Shared/Danger.php | 131 -
app/Livewire/Project/Shared/Destination.php | 155 -
.../Shared/EnvironmentVariable/Add.php | 70 -
.../Shared/EnvironmentVariable/All.php | 225 -
.../Shared/EnvironmentVariable/Show.php | 181 -
.../Shared/ExecuteContainerCommand.php | 242 -
app/Livewire/Project/Shared/GetLogs.php | 159 -
app/Livewire/Project/Shared/HealthChecks.php | 49 -
app/Livewire/Project/Shared/Logs.php | 122 -
app/Livewire/Project/Shared/Metrics.php | 59 -
.../Project/Shared/ResourceLimits.php | 62 -
.../Project/Shared/ResourceOperations.php | 526 -
.../Project/Shared/ScheduledTask/Add.php | 111 -
.../Project/Shared/ScheduledTask/All.php | 44 -
.../Shared/ScheduledTask/Executions.php | 144 -
.../Project/Shared/ScheduledTask/Show.php | 154 -
app/Livewire/Project/Shared/Storages/Add.php | 165 -
app/Livewire/Project/Shared/Storages/All.php | 12 -
app/Livewire/Project/Shared/Storages/Show.php | 55 -
app/Livewire/Project/Shared/Tags.php | 104 -
app/Livewire/Project/Shared/Terminal.php | 89 -
app/Livewire/Project/Shared/UploadConfig.php | 46 -
app/Livewire/Project/Shared/Webhooks.php | 62 -
app/Livewire/Project/Show.php | 61 -
app/Livewire/Security/ApiTokens.php | 74 -
app/Livewire/Security/PrivateKey/Create.php | 90 -
app/Livewire/Security/PrivateKey/Index.php | 24 -
app/Livewire/Security/PrivateKey/Show.php | 70 -
app/Livewire/Server/Advanced.php | 83 -
app/Livewire/Server/Charts.php | 64 -
app/Livewire/Server/CloudflareTunnels.php | 54 -
.../Server/ConfigureCloudflareTunnels.php | 54 -
app/Livewire/Server/Create.php | 30 -
app/Livewire/Server/Delete.php | 57 -
app/Livewire/Server/Destinations.php | 90 -
app/Livewire/Server/DockerCleanup.php | 99 -
.../Server/DockerCleanupExecutions.php | 132 -
app/Livewire/Server/Index.php | 22 -
app/Livewire/Server/LogDrains.php | 190 -
app/Livewire/Server/New/ByIp.php | 133 -
app/Livewire/Server/PrivateKey/Show.php | 72 -
app/Livewire/Server/Proxy.php | 119 -
app/Livewire/Server/Proxy/Deploy.php | 140 -
.../Proxy/DynamicConfigurationNavbar.php | 42 -
.../Server/Proxy/DynamicConfigurations.php | 64 -
app/Livewire/Server/Proxy/Logs.php | 31 -
.../Server/Proxy/NewDynamicConfiguration.php | 97 -
app/Livewire/Server/Proxy/Show.php | 35 -
app/Livewire/Server/Proxy/Status.php | 77 -
app/Livewire/Server/Resources.php | 102 -
app/Livewire/Server/Show.php | 282 -
app/Livewire/Server/ValidateAndInstall.php | 182 -
app/Livewire/Settings/Index.php | 243 -
app/Livewire/SettingsBackup.php | 125 -
app/Livewire/SettingsEmail.php | 241 -
app/Livewire/SettingsOauth.php | 69 -
.../SharedVariables/Environment/Index.php | 22 -
.../SharedVariables/Environment/Show.php | 53 -
app/Livewire/SharedVariables/Index.php | 13 -
.../SharedVariables/Project/Index.php | 22 -
app/Livewire/SharedVariables/Project/Show.php | 50 -
app/Livewire/SharedVariables/Team/Index.php | 44 -
app/Livewire/Source/Github/Change.php | 299 -
app/Livewire/Source/Github/Create.php | 63 -
app/Livewire/Source/Gitlab/Change.php | 13 -
app/Livewire/Storage/Create.php | 96 -
app/Livewire/Storage/Form.php | 65 -
app/Livewire/Storage/Index.php | 21 -
app/Livewire/Storage/Show.php | 24 -
app/Livewire/Subscription/Actions.php | 22 -
app/Livewire/Subscription/Index.php | 44 -
app/Livewire/Subscription/PricingPlans.php | 70 -
app/Livewire/Subscription/Show.php | 26 -
app/Livewire/SwitchTeam.php | 35 -
app/Livewire/Tags/Deployments.php | 37 -
app/Livewire/Tags/Show.php | 95 -
app/Livewire/Team/AdminView.php | 139 -
app/Livewire/Team/Create.php | 34 -
app/Livewire/Team/Index.php | 73 -
app/Livewire/Team/Invitations.php | 30 -
app/Livewire/Team/InviteLink.php | 109 -
app/Livewire/Team/Member.php | 78 -
app/Livewire/Team/Member/Index.php | 23 -
app/Livewire/Team/Storage/Show.php | 24 -
app/Livewire/Terminal/Index.php | 88 -
app/Livewire/Upgrade.php | 46 -
app/Livewire/VerifyEmail.php | 27 -
app/Models/Application.php | 1700 -
app/Models/ApplicationDeploymentQueue.php | 117 -
app/Models/ApplicationPreview.php | 75 -
app/Models/ApplicationSetting.php | 40 -
app/Models/BaseModel.php | 36 -
app/Models/DiscordNotificationSettings.php | 59 -
app/Models/DockerCleanupExecution.php | 15 -
app/Models/EmailNotificationSettings.php | 79 -
app/Models/Environment.php | 128 -
app/Models/EnvironmentVariable.php | 218 -
app/Models/GithubApp.php | 87 -
app/Models/GitlabApp.php | 26 -
app/Models/InstanceSettings.php | 127 -
app/Models/Kubernetes.php | 5 -
app/Models/LocalFileVolume.php | 172 -
app/Models/LocalPersistentVolume.php | 58 -
app/Models/OauthSetting.php | 35 -
app/Models/PersonalAccessToken.php | 16 -
app/Models/PrivateKey.php | 244 -
app/Models/Project.php | 155 -
app/Models/ProjectSetting.php | 15 -
app/Models/PushoverNotificationSettings.php | 61 -
app/Models/S3Storage.php | 87 -
app/Models/ScheduledDatabaseBackup.php | 56 -
.../ScheduledDatabaseBackupExecution.php | 15 -
app/Models/ScheduledTask.php | 51 -
app/Models/ScheduledTaskExecution.php | 15 -
app/Models/Server.php | 1333 -
app/Models/ServerSetting.php | 151 -
app/Models/Service.php | 1355 -
app/Models/ServiceApplication.php | 130 -
app/Models/ServiceDatabase.php | 146 -
app/Models/SharedEnvironmentVariable.php | 15 -
app/Models/SlackNotificationSettings.php | 59 -
app/Models/StandaloneClickhouse.php | 322 -
app/Models/StandaloneDocker.php | 92 -
app/Models/StandaloneDragonfly.php | 322 -
app/Models/StandaloneKeydb.php | 322 -
app/Models/StandaloneMariadb.php | 322 -
app/Models/StandaloneMongodb.php | 342 -
app/Models/StandaloneMysql.php | 323 -
app/Models/StandalonePostgresql.php | 323 -
app/Models/StandaloneRedis.php | 373 -
app/Models/Subscription.php | 48 -
app/Models/SwarmDocker.php | 82 -
app/Models/Tag.php | 33 -
app/Models/Team.php | 306 -
app/Models/TeamInvitation.php | 40 -
app/Models/TelegramNotificationSettings.php | 85 -
app/Models/User.php | 224 -
app/Models/Webhook.php | 15 -
.../Application/DeploymentFailed.php | 188 -
.../Application/DeploymentSuccess.php | 208 -
.../Application/StatusChanged.php | 116 -
app/Notifications/Channels/DiscordChannel.php | 25 -
app/Notifications/Channels/EmailChannel.php | 90 -
.../Channels/PushoverChannel.php | 21 -
app/Notifications/Channels/SendsDiscord.php | 8 -
app/Notifications/Channels/SendsEmail.php | 8 -
app/Notifications/Channels/SendsPushover.php | 8 -
app/Notifications/Channels/SendsSlack.php | 8 -
app/Notifications/Channels/SendsTelegram.php | 8 -
app/Notifications/Channels/SlackChannel.php | 24 -
.../Channels/TelegramChannel.php | 47 -
.../Channels/TransactionalEmailChannel.php | 42 -
.../Container/ContainerRestarted.php | 105 -
.../Container/ContainerStopped.php | 105 -
app/Notifications/CustomEmailNotification.php | 18 -
app/Notifications/Database/BackupFailed.php | 91 -
app/Notifications/Database/BackupSuccess.php | 88 -
app/Notifications/Dto/DiscordMessage.php | 83 -
app/Notifications/Dto/PushoverMessage.php | 50 -
app/Notifications/Dto/SlackMessage.php | 32 -
.../Internal/GeneralNotification.php | 61 -
.../ScheduledTask/TaskFailed.php | 117 -
.../ScheduledTask/TaskSuccess.php | 108 -
.../Server/DockerCleanupFailed.php | 69 -
.../Server/DockerCleanupSuccess.php | 69 -
app/Notifications/Server/ForceDisabled.php | 77 -
app/Notifications/Server/ForceEnabled.php | 68 -
app/Notifications/Server/HighDiskUsage.php | 91 -
app/Notifications/Server/Reachable.php | 77 -
app/Notifications/Server/Unreachable.php | 85 -
app/Notifications/Test.php | 112 -
.../TransactionalEmails/InvitationLink.php | 39 -
.../TransactionalEmails/ResetPassword.php | 75 -
.../TransactionalEmails/Test.php | 29 -
app/Policies/ApplicationPolicy.php | 69 -
app/Policies/ServerPolicy.php | 65 -
app/Policies/ServicePolicy.php | 82 -
app/Providers/AppServiceProvider.php | 74 +-
app/Providers/AuthServiceProvider.php | 26 -
app/Providers/BroadcastServiceProvider.php | 19 -
app/Providers/DuskServiceProvider.php | 21 -
app/Providers/EventServiceProvider.php | 47 -
app/Providers/FortifyServiceProvider.php | 129 -
app/Providers/HorizonServiceProvider.php | 63 -
app/Providers/RouteServiceProvider.php | 58 -
app/Providers/TelescopeServiceProvider.php | 67 -
app/Repositories/CustomJobRepository.php | 51 -
app/Services/ConfigurationGenerator.php | 194 -
app/Services/DockerImageParser.php | 78 -
app/Traits/ExecuteRemoteCommand.php | 96 -
app/Traits/HasConfiguration.php | 42 -
app/Traits/HasNotificationSettings.php | 93 -
app/Traits/SaveFromRedirect.php | 26 -
app/View/Components/Forms/Button.php | 30 -
app/View/Components/Forms/Checkbox.php | 38 -
app/View/Components/Forms/Datalist.php | 43 -
app/View/Components/Forms/Input.php | 45 -
app/View/Components/Forms/Select.php | 43 -
app/View/Components/Forms/Textarea.php | 55 -
app/View/Components/Modal.php | 34 -
app/View/Components/ResourceView.php | 28 -
app/View/Components/Services/Explanation.php | 26 -
app/View/Components/Services/Links.php | 55 -
app/View/Components/Status/Index.php | 26 -
app/View/Components/Status/Services.php | 30 -
app/View/Components/services/advanced.php | 26 -
artisan | 49 +-
bootstrap/app.php | 65 +-
bootstrap/getHelperVersion.php | 10 -
bootstrap/getRealtimeVersion.php | 10 -
bootstrap/getVersion.php | 10 -
bootstrap/helpers/api.php | 179 -
bootstrap/helpers/applications.php | 122 -
bootstrap/helpers/constants.php | 56 -
bootstrap/helpers/databases.php | 433 -
bootstrap/helpers/docker.php | 887 -
bootstrap/helpers/github.php | 131 -
bootstrap/helpers/notifications.php | 100 -
bootstrap/helpers/proxy.php | 271 -
bootstrap/helpers/remoteProcess.php | 240 -
bootstrap/helpers/services.php | 280 -
bootstrap/helpers/shared.php | 4139 --
bootstrap/helpers/socialite.php | 61 -
bootstrap/helpers/subscriptions.php | 91 -
bootstrap/helpers/timezone.php | 42 -
bootstrap/includeHelpers.php | 6 -
bootstrap/providers.php | 5 +
cliff.toml | 84 -
composer.json | 145 +-
composer.lock | 7882 +--
config/app.php | 139 +-
config/auth.php | 36 +-
config/broadcasting.php | 70 -
config/cache.php | 32 +-
config/chunk-upload.php | 45 -
config/constants.php | 83 -
config/cors.php | 34 -
config/database.php | 115 +-
config/debugbar.php | 326 -
config/filesystems.php | 50 +-
config/fortify.php | 148 -
config/hashing.php | 52 -
config/horizon.php | 217 -
config/livewire.php | 150 -
config/logging.php | 39 +-
config/mail.php | 78 +-
config/purify.php | 115 -
config/queue.php | 58 +-
config/ray.php | 108 -
config/redoc.php | 28 -
config/sanctum.php | 68 -
config/sentry.php | 85 -
config/services.php | 32 +-
config/session.php | 78 +-
config/subscription.php | 12 -
config/telescope.php | 205 -
config/testing.php | 6 -
config/view.php | 36 -
database/.gitignore | 1 -
database/factories/ApplicationFactory.php | 22 -
database/factories/ServerFactory.php | 17 -
database/factories/UserFactory.php | 37 -
.../2014_10_12_000000_create_users_table.php | 32 -
...000_create_password_reset_tokens_table.php | 28 -
..._add_two_factor_columns_to_users_table.php | 46 -
..._100000_create_telescope_entries_table.php | 70 -
...01_create_personal_access_tokens_table.php | 34 -
...03_20_112410_create_activity_log_table.php | 27 -
...add_event_column_to_activity_log_table.php | 22 -
...atch_uuid_column_to_activity_log_table.php | 22 -
...023_03_20_112809_create_sessions_table.php | 31 -
.../2023_03_20_112811_create_teams_table.php | 34 -
...23_03_20_112812_create_team_user_table.php | 32 -
...0_112813_create_team_invitations_table.php | 35 -
..._112814_create_instance_settings_table.php | 38 -
...2023_03_24_140711_create_servers_table.php | 36 -
...24_140712_create_server_settings_table.php | 33 -
...03_24_140853_create_private_keys_table.php | 33 -
...023_03_27_075351_create_projects_table.php | 33 -
...7_075443_create_project_settings_table.php | 29 -
...03_27_075444_create_environments_table.php | 30 -
...03_27_081716_create_applications_table.php | 85 -
...1717_create_application_settings_table.php | 38 -
...1718_create_application_previews_table.php | 36 -
...023_03_27_083621_create_services_table.php | 33 -
...085020_create_standalone_dockers_table.php | 33 -
...3_27_085022_create_swarm_dockers_table.php | 31 -
...3_03_28_062150_create_kubernetes_table.php | 29 -
..._03_28_083723_create_github_apps_table.php | 47 -
..._03_28_083726_create_gitlab_apps_table.php | 49 -
..._create_local_persistent_volumes_table.php | 35 -
...548_create_environment_variables_table.php | 40 -
..._05_17_104039_create_failed_jobs_table.php | 32 -
...te_application_deployment_queues_table.php | 34 -
...3_06_22_131459_move_wildcard_to_server.php | 34 -
..._wildcard_domain_from_instancesettings.php | 28 -
...2023_06_23_110548_next_channel_updates.php | 28 -
..._23_114131_change_env_var_value_length.php | 28 -
...efault_redirect_from_instance_settings.php | 28 -
...lication_deployment_queues_as_activity.php | 30 -
...4_add_disk_usage_percentage_to_servers.php | 28 -
...7_13_115117_create_subscriptions_table.php | 39 -
...023_07_13_120719_create_webhooks_table.php | 31 -
...20721_add_license_to_instance_settings.php | 30 -
...2013_smtp_discord_schemaless_to_normal.php | 193 -
...escription_field_to_applications_table.php | 28 -
...remove_foreignId_environment_variables.php | 32 -
...54_add_readonly_localpersistentvolumes.php | 28 -
..._08_07_073651_create_s3_storages_table.php | 37 -
...50_create_standalone_postgresqls_table.php | 58 -
...reate_scheduled_database_backups_table.php | 30 -
...duled_database_backup_executions_table.php | 27 -
...1311_add_backup_notifications_to_teams.php | 24 -
...8_add_dockerfile_to_applications_table.php | 25 -
...23_08_15_095902_create_waitlists_table.php | 31 -
.../2023_08_15_111125_update_users_table.php | 28 -
...te_servers_add_unreachable_count_table.php | 28 -
...023_08_22_071048_add_boarding_to_teams.php | 28 -
...2023_08_22_071049_update_webhooks_type.php | 29 -
..._22_071050_update_subscriptions_stripe.php | 52 -
...71051_add_stripe_plan_to_subscriptions.php | 28 -
.../2023_08_22_071052_add_resend_as_email.php | 30 -
...22_071053_add_resend_as_email_to_teams.php | 32 -
.../2023_08_22_071054_add_stripe_reasons.php | 30 -
...055_add_discord_notifications_to_teams.php | 34 -
...2_071056_update_telegram_notifications.php | 29 -
...057_add_nixpkgsarchive_to_applications.php | 22 -
..._nixpkgsarchive_to_applications_remove.php | 22 -
...23_08_22_071059_add_stripe_trial_ended.php | 28 -
...2_071060_change_invitation_link_length.php | 28 -
...023_09_20_082541_update_services_table.php | 34 -
..._082733_create_service_databases_table.php | 38 -
...2737_create_service_applications_table.php | 39 -
...549_update_environment_variables_table.php | 28 -
...185356_create_local_file_volumes_table.php | 34 -
...111808_update_servers_with_cloudflared.php | 28 -
...remove_destination_from_services_table.php | 29 -
...1811_update_service_applications_table.php | 32 -
..._111812_update_service_databases_table.php | 30 -
...23_111813_update_users_databases_table.php | 28 -
...111814_update_local_file_volumes_table.php | 28 -
..._add_healthcheck_disable_to_apps_table.php | 28 -
...1816_add_destination_to_services_table.php | 28 -
...use_instance_email_settings_by_default.php | 28 -
...111818_set_notifications_on_by_default.php | 30 -
.../2023_09_23_111819_add_server_emails.php | 30 -
...08_111819_add_server_unreachable_count.php | 28 -
..._10_10_100320_update_s3_storages_table.php | 30 -
...dockerfile_location_applications_table.php | 28 -
...2_132430_create_standalone_redis_table.php | 54 -
...e_redis_to_environment_variables_table.php | 28 -
...2432_add_database_selection_to_backups.php | 34 -
...9_add_custom_labels_applications_table.php | 28 -
...01331_create_standalone_mongodbs_table.php | 56 -
...mongodb_to_environment_variables_table.php | 28 -
..._103548_create_standalone_mysqls_table.php | 57 -
...20523_create_standalone_mariadbs_table.php | 57 -
...e_mysql_to_environment_variables_table.php | 30 -
...wn_once_to_environment_variables_table.php | 28 -
...100437_add_restart_to_deployment_queue.php | 28 -
..._07_123731_add_target_build_dockerfile.php | 28 -
...dd_custom_config_standalone_postgresql.php | 30 -
...2_add_public_port_to_service_databases.php | 30 -
..._12_180605_change_fqdn_to_longer_field.php | 40 -
...3_11_13_133059_add_sponsorship_disable.php | 28 -
...11_14_103450_add_manual_webhook_secret.php | 30 -
.../2023_11_14_121416_add_git_type.php | 34 -
...01819_add_high_disk_usage_notification.php | 30 -
.../2023_11_16_220647_add_log_drains.php | 46 -
...160437_add_drain_log_enable_by_service.php | 76 -
.../2023_11_20_094628_add_gpu_settings.php | 36 -
...20_add_additional_destinations_to_apps.php | 28 -
..._24_080341_add_docker_compose_location.php | 42 -
..._28_143533_add_fields_to_swarm_dockers.php | 30 -
...3_11_29_075937_change_swarm_properties.php | 30 -
...3_12_01_091723_save_logs_view_settings.php | 64 -
...dd_custom_fluentd_config_for_logdrains.php | 32 -
..._12_08_162228_add_soft_delete_services.php | 28 -
...103611_add_realtime_connection_problem.php | 28 -
.../2023_12_13_110214_add_soft_deletes.php | 70 -
...dd_custom_docker_compose_start_command.php | 30 -
..._12_18_093514_add_swarm_related_things.php | 36 -
...2_19_124111_add_swarm_cluster_grouping.php | 28 -
...134507_add_description_to_environments.php | 28 -
...31_173041_create_scheduled_tasks_table.php | 37 -
...create_scheduled_task_executions_table.php | 31 -
...1_02_113855_add_raw_compose_deployment.php | 28 -
...2024_01_12_123422_update_cpuset_limits.php | 76 -
...024_01_15_084609_add_custom_dns_server.php | 30 -
...4_01_16_115005_add_build_server_enable.php | 28 -
..._130328_add_docker_network_to_services.php | 28 -
...32_add_manual_webhook_secret_bitbucket.php | 28 -
...ate_shared_environment_variables_table.php | 37 -
...concurrent_number_of_builds_per_server.php | 28 -
...4_01_25_073212_add_server_id_to_queues.php | 28 -
...ation_name_and_deployment_url_to_queue.php | 32 -
...1_29_072322_change_env_variable_length.php | 28 -
...9_145200_add_custom_docker_run_options.php | 28 -
.../2024_02_01_111228_create_tags_table.php | 38 -
...215_add_destination_to_app_deployments.php | 28 -
..._06_132748_add_additional_destinations.php | 37 -
...23_add_post_deployment_to_applications.php | 34 -
...04_add_dynamic_timeout_for_deployments.php | 28 -
..._consistent_application_container_name.php | 28 -
...192025_add_is_gzip_enabled_to_services.php | 28 -
...0_165045_add_permissions_to_github_app.php | 34 -
...090900_add_only_this_server_deployment.php | 28 -
...custom_server_limits_to_teams_ultimate.php | 28 -
...222150_add_server_force_disabled_field.php | 28 -
..._gzip_enabled_and_stripprefix_settings.php | 44 -
...add_notifications_notification_disable.php | 28 -
.../2024_03_08_180457_nullable_password.php | 28 -
...024_03_11_150013_create_oauth_settings.php | 33 -
.../2024_03_14_214402_add_multiline_envs.php | 34 -
.../2024_03_18_101440_add_version_of_envs.php | 34 -
...3_22_080914_remove_popup_notifications.php | 30 -
...6_122110_remove_realtime_notifications.php | 28 -
...4_03_28_114620_add_watch_paths_to_apps.php | 28 -
...517_make_custom_docker_commands_longer.php | 28 -
..._071920_create_standalone_keydbs_table.php | 64 -
...20_create_standalone_dragonflies_table.php | 63 -
...19_create_standalone_clickhouses_table.php | 64 -
...4015_add_permission_local_file_volumes.php | 30 -
...337_add_config_hash_to_other_resources.php | 76 -
...024_04_15_094703_add_literal_variables.php | 34 -
...16_083919_add_service_type_on_creation.php | 28 -
.../2024_04_17_132541_add_rollback_queues.php | 28 -
...docker_network_to_application_settings.php | 28 -
...29_111956_add_custom_hc_indicator_apps.php | 28 -
...dd_custom_name_to_application_settings.php | 28 -
.../2024_05_07_124019_add_server_metrics.php | 28 -
...5_10_085215_make_stripe_comment_longer.php | 28 -
...commit_message_to_app_deployment_queue.php | 28 -
..._15_151236_add_container_escape_toggle.php | 34 -
...24_05_17_082012_add_env_sorting_toggle.php | 28 -
..._scheduled_tasks_notification_to_teams.php | 34 -
...oyment_commands_length_in_applications.php | 30 -
...1713_add_gitea_webhook_to_applications.php | 28 -
...5_101019_add_docker_compose_pr_domains.php | 28 -
...103938_change_pr_issue_commend_id_type.php | 28 -
..._06_11_081614_add_www_non_www_redirect.php | 28 -
.../2024_06_18_105948_move_server_metrics.php | 40 -
...4_06_20_102551_add_server_api_sentinel.php | 28 -
...4_06_21_143358_add_api_deployment_type.php | 28 -
...er_instance_settings_add_instance_name.php | 28 -
.../2024_06_25_184323_update_db.php | 95 -
...1_115528_add_is_api_allowed_and_iplist.php | 24 -
...05_120217_remove_unique_from_tag_names.php | 28 -
...11_083719_application_compose_versions.php | 28 -
...23828_add_is_container_labels_readonly.php | 28 -
...ettings_is_preserve_repository_enabled.php | 28 -
..._07_18_123458_add_force_cleanup_server.php | 28 -
...9_132617_disable_healtcheck_by_default.php | 28 -
..._112710_add_validation_logs_to_servers.php | 28 -
...5_142659_add_update_frequency_settings.php | 32 -
...4_08_07_155324_add_proxy_label_chooser.php | 28 -
...leanup_fields_to_server_settings_table.php | 59 -
...659_add_local_file_volume_based_on_git.php | 28 -
...mezone_to_server_and_instance_settings.php | 30 -
...d_order_to_environment_variables_table.php | 28 -
...dd_build_server_id_to_deployment_queue.php | 28 -
...05649_add_custom_docker_options_to_dbs.php | 70 -
...dd_compose_parsing_version_to_services.php | 28 -
...dd_helper_version_to_instance_settings.php | 28 -
...062534_change_server_cleanup_to_forced.php | 37 -
...4_09_07_185402_change_cleanup_schedule.php | 37 -
...pdate_server_settings_default_timezone.php | 28 -
...6_111428_encrypt_existing_private_keys.php | 24 -
..._key_fingerprint_to_private_keys_table.php | 39 -
...anup_options_to_servers_settings_table.php | 24 -
...24_09_26_083441_disable_api_by_default.php | 18 -
...add_dump_all_to_standalone_postgresqls.php | 28 -
...straint_from_service_applications_fqdn.php | 34 -
...0_11_114331_add_required_env_variables.php | 28 -
...pdate_metrics_token_in_server_settings.php | 54 -
...add_is_shared_to_environment_variables.php | 22 -
..._16_120026_move_redis_password_to_envs.php | 41 -
...on_settings_to_instance_settings_table.php | 22 -
...0_17_093722_add_soft_delete_to_servers.php | 28 -
...105745_add_server_disk_usage_threshold.php | 28 -
...223_add_server_disk_usage_notification.php | 32 -
...tinel_debug_enabled_to_server_settings.php | 28 -
..._10_30_074601_rename_token_permissions.php | 60 -
...213214_add_last_online_at_to_resources.php | 96 -
...d_custom_nginx_configuration_to_static.php | 28 -
...11_11_125366_add_index_to_activity_log.php | 28 -
..._124742_add_uuid_to_environments_table.php | 38 -
...dd_disable_build_cache_advanced_option.php | 22 -
...eate_email_notification_settings_table.php | 58 -
...te_discord_notification_settings_table.php | 45 -
...e_telegram_notification_settings_table.php | 59 -
...notification_settings_from_teams_table.php | 135 -
...notification_settings_from_teams_table.php | 92 -
...notification_settings_from_teams_table.php | 115 -
...eate_slack_notification_settings_table.php | 58 -
...2024_12_09_105711_drop_waitlists_table.php | 31 -
...ncrypt_instance_settings_email_columns.php | 72 -
.../2024_12_10_122143_drop_resale_license.php | 30 -
...e_pushover_notification_settings_table.php | 59 -
...entik_base_url_to_oauth_settings_table.php | 28 -
...pt_resend_api_key_in_instance_settings.php | 46 -
...columns_to_environment_variables_table.php | 165 -
...eck_frequency_to_server_settings_table.php | 28 -
..._142402_update_email_encryption_values.php | 114 -
...01_08_154008_switch_up_readonly_labels.php | 39 -
...35244_add_horizon_job_details_to_queue.php | 30 -
...ds_to_scheduled_database_backups_table.php | 36 -
...create_docker_cleanup_executions_table.php | 33 -
..._text_in_application_deployment_queues.php | 28 -
...8_add_finished_at_to_executions_tables.php | 38 -
...date_finished_at_timestamps_if_not_set.php | 37 -
..._22_101105_remove_wrongly_created_envs.php | 19 -
...add_index_to_scheduled_task_executions.php | 38 -
.../2025_03_01_112617_add_stripe_past_due.php | 28 -
...deletion_tracking_to_backup_executions.php | 19 -
database/seeders/ApplicationSeeder.php | 66 -
.../seeders/ApplicationSettingsSeeder.php | 19 -
database/seeders/DatabaseSeeder.php | 33 -
.../DisableTwoStepConfirmationSeeder.php | 20 -
database/seeders/GithubAppSeeder.php | 39 -
database/seeders/GitlabAppSeeder.php | 24 -
database/seeders/InstanceSettingsSeeder.php | 44 -
.../seeders/LocalPersistentVolumeSeeder.php | 23 -
database/seeders/OauthSettingSeeder.php | 66 -
.../PopulateSshKeysDirectorySeeder.php | 37 -
database/seeders/PrivateKeySeeder.php | 63 -
database/seeders/ProductionSeeder.php | 197 -
database/seeders/ProjectSeeder.php | 18 -
database/seeders/RootUserSeeder.php | 74 -
database/seeders/S3StorageSeeder.php | 25 -
database/seeders/SentinelSeeder.php | 32 -
database/seeders/ServerSeeder.php | 27 -
database/seeders/ServerSettingSeeder.php | 22 -
.../SharedEnvironmentVariableSeeder.php | 36 -
database/seeders/StandaloneDockerSeeder.php | 24 -
.../seeders/StandalonePostgresqlSeeder.php | 22 -
database/seeders/StandaloneRedisSeeder.php | 22 -
database/seeders/TeamSeeder.php | 23 -
database/seeders/UserSeeder.php | 28 -
docker-compose.dev.yml | 125 -
docker-compose.prod.yml | 90 -
docker-compose.windows.yml | 133 -
docker-compose.yml | 37 -
docker/coolify-helper/Dockerfile | 54 -
docker/coolify-realtime/Dockerfile | 28 -
docker/coolify-realtime/package-lock.json | 369 -
docker/coolify-realtime/package.json | 13 -
docker/coolify-realtime/soketi-entrypoint.sh | 35 -
docker/coolify-realtime/terminal-server.js | 239 -
docker/development/Dockerfile | 81 -
.../development/etc/nginx/conf.d/custom.conf | 4 -
.../etc/nginx/site-opts.d/http.conf | 43 -
.../etc/php/conf.d/zzz-custom-php.ini | 10 -
.../etc/s6-overlay/s6-rc.d/horizon/run | 12 -
.../etc/s6-overlay/s6-rc.d/horizon/type | 1 -
.../etc/s6-overlay/s6-rc.d/init-setup/type | 1 -
.../etc/s6-overlay/s6-rc.d/init-setup/up | 22 -
.../dependencies.d/init-setup | 0
.../s6-overlay/s6-rc.d/scheduler-worker/run | 13 -
.../s6-overlay/s6-rc.d/scheduler-worker/type | 1 -
.../s6-rc.d/user/contents.d/horizon | 0
.../s6-rc.d/user/contents.d/init-setup | 0
.../s6-rc.d/user/contents.d/scheduler-worker | 0
docker/production/Dockerfile | 140 -
.../production/entrypoint.d/99-debug-mode.sh | 8 -
.../production/etc/nginx/conf.d/custom.conf | 4 -
.../etc/nginx/site-opts.d/http.conf | 43 -
.../etc/php/conf.d/zzz-custom-php.ini | 10 -
.../etc/s6-overlay/s6-rc.d/db-migration/type | 1 -
.../etc/s6-overlay/s6-rc.d/db-migration/up | 11 -
.../horizon/dependencies.d/init-script | 0
.../etc/s6-overlay/s6-rc.d/horizon/run | 11 -
.../etc/s6-overlay/s6-rc.d/horizon/type | 1 -
.../init-script/dependencies.d/init-seeder | 0
.../etc/s6-overlay/s6-rc.d/init-script/type | 1 -
.../etc/s6-overlay/s6-rc.d/init-script/up | 12 -
.../init-seeder/dependencies.d/db-migration | 0
.../etc/s6-overlay/s6-rc.d/init-seeder/type | 1 -
.../etc/s6-overlay/s6-rc.d/init-seeder/up | 12 -
.../dependencies.d/init-script | 0
.../s6-overlay/s6-rc.d/scheduler-worker/run | 10 -
.../s6-overlay/s6-rc.d/scheduler-worker/type | 1 -
.../s6-rc.d/user/contents.d/db-migration | 0
.../s6-rc.d/user/contents.d/horizon | 0
.../s6-rc.d/user/contents.d/init-script | 0
.../s6-rc.d/user/contents.d/init-seeder | 0
.../s6-rc.d/user/contents.d/scheduler-worker | 0
docker/testing-host/Dockerfile | 36 -
hooks/pre-commit | 21 -
lang/ar.json | 40 -
lang/cs.json | 31 -
lang/de.json | 31 -
lang/en.json | 40 -
lang/es.json | 31 -
lang/fa.json | 31 -
lang/fr.json | 40 -
lang/it.json | 40 -
lang/ja.json | 31 -
lang/pt.json | 31 -
lang/ro.json | 38 -
lang/tr.json | 31 -
lang/vi.json | 31 -
lang/zh-cn.json | 31 -
lang/zh-tw.json | 31 -
openapi.json | 7988 ---
openapi.yaml | 5342 --
other/logos/advin.png | Bin 33880 -> 0 bytes
other/logos/appwrite.svg | 14 -
other/logos/arcjet.svg | 25 -
other/logos/bc.png | Bin 28644 -> 0 bytes
other/logos/blacksmith.svg | 18 -
other/logos/branddev.png | Bin 30428 -> 0 bytes
other/logos/ccc-logo.webp | Bin 1592 -> 0 bytes
other/logos/codext.jpg | Bin 105902 -> 0 bytes
other/logos/fractal.png | Bin 5643 -> 0 bytes
other/logos/fractal.svg | 40 -
other/logos/glueops.webp | Bin 118280 -> 0 bytes
other/logos/hetzner.jpg | Bin 196793 -> 0 bytes
other/logos/hostinger.svg | 2 -
other/logos/internetgarden.ico | Bin 15406 -> 0 bytes
other/logos/jobscollider.svg | 12 -
other/logos/juxtdigital.png | Bin 105748 -> 0 bytes
other/logos/latitude.svg | 1 -
other/logos/logto.webp | Bin 5156 -> 0 bytes
other/logos/massivegrid.svg | 20 -
other/logos/quant.svg | 1 -
other/logos/saasykit.png | Bin 84363 -> 0 bytes
other/logos/saasykit.webp | Bin 44522 -> 0 bytes
other/logos/supaguide.png | Bin 16916 -> 0 bytes
other/logos/tigris.svg | 16 -
other/logos/trieve_bg.png | Bin 964454 -> 0 bytes
other/logos/ubicloud.svg | 1 -
other/nightly/.env.production | 16 -
other/nightly/docker-compose.prod.yml | 90 -
other/nightly/docker-compose.windows.yml | 133 -
other/nightly/docker-compose.yml | 37 -
other/nightly/install.sh | 814 -
other/nightly/upgrade.sh | 41 -
other/nightly/versions.json | 19 -
package-lock.json | 3035 -
package.json | 27 +-
phpunit.dusk.xml | 15 -
phpunit.xml | 57 +-
pint.json | 3 -
postcss.config.cjs | 6 -
public/coolify-logo-dev-transparent.png | Bin 7866 -> 0 bytes
public/coolify-logo.svg | 9 -
public/coolify-transparent.png | Bin 7872 -> 0 bytes
.../init-setup => public/favicon.ico | 0
public/index.php | 47 +-
public/js/apexcharts.js | 16 -
public/js/dropzone.js | 1 -
public/js/echo.js | 2 -
.../browser/ui/codicons/codicon/codicon.ttf | Bin 80340 -> 0 bytes
.../min/vs/base/worker/workerMain.js | 31 -
.../min/vs/basic-languages/abap/abap.js | 10 -
.../min/vs/basic-languages/apex/apex.js | 10 -
.../min/vs/basic-languages/azcli/azcli.js | 10 -
.../min/vs/basic-languages/bat/bat.js | 10 -
.../min/vs/basic-languages/bicep/bicep.js | 11 -
.../vs/basic-languages/cameligo/cameligo.js | 10 -
.../min/vs/basic-languages/clojure/clojure.js | 10 -
.../min/vs/basic-languages/coffee/coffee.js | 10 -
.../min/vs/basic-languages/cpp/cpp.js | 10 -
.../min/vs/basic-languages/csharp/csharp.js | 10 -
.../min/vs/basic-languages/csp/csp.js | 10 -
.../min/vs/basic-languages/css/css.js | 12 -
.../min/vs/basic-languages/cypher/cypher.js | 10 -
.../min/vs/basic-languages/dart/dart.js | 10 -
.../basic-languages/dockerfile/dockerfile.js | 10 -
.../min/vs/basic-languages/ecl/ecl.js | 10 -
.../min/vs/basic-languages/elixir/elixir.js | 10 -
.../min/vs/basic-languages/flow9/flow9.js | 10 -
.../freemarker2/freemarker2.js | 12 -
.../min/vs/basic-languages/fsharp/fsharp.js | 10 -
.../min/vs/basic-languages/go/go.js | 10 -
.../min/vs/basic-languages/graphql/graphql.js | 10 -
.../basic-languages/handlebars/handlebars.js | 10 -
.../min/vs/basic-languages/hcl/hcl.js | 10 -
.../min/vs/basic-languages/html/html.js | 10 -
.../min/vs/basic-languages/ini/ini.js | 10 -
.../min/vs/basic-languages/java/java.js | 10 -
.../basic-languages/javascript/javascript.js | 10 -
.../min/vs/basic-languages/julia/julia.js | 10 -
.../min/vs/basic-languages/kotlin/kotlin.js | 10 -
.../min/vs/basic-languages/less/less.js | 11 -
.../min/vs/basic-languages/lexon/lexon.js | 10 -
.../min/vs/basic-languages/liquid/liquid.js | 10 -
.../min/vs/basic-languages/lua/lua.js | 10 -
.../min/vs/basic-languages/m3/m3.js | 10 -
.../vs/basic-languages/markdown/markdown.js | 10 -
.../min/vs/basic-languages/mdx/mdx.js | 10 -
.../min/vs/basic-languages/mips/mips.js | 10 -
.../min/vs/basic-languages/msdax/msdax.js | 10 -
.../min/vs/basic-languages/mysql/mysql.js | 10 -
.../objective-c/objective-c.js | 10 -
.../min/vs/basic-languages/pascal/pascal.js | 10 -
.../vs/basic-languages/pascaligo/pascaligo.js | 10 -
.../min/vs/basic-languages/perl/perl.js | 10 -
.../min/vs/basic-languages/pgsql/pgsql.js | 10 -
.../min/vs/basic-languages/php/php.js | 10 -
.../min/vs/basic-languages/pla/pla.js | 10 -
.../vs/basic-languages/postiats/postiats.js | 10 -
.../basic-languages/powerquery/powerquery.js | 10 -
.../basic-languages/powershell/powershell.js | 10 -
.../vs/basic-languages/protobuf/protobuf.js | 11 -
.../min/vs/basic-languages/pug/pug.js | 10 -
.../min/vs/basic-languages/python/python.js | 10 -
.../min/vs/basic-languages/qsharp/qsharp.js | 10 -
.../min/vs/basic-languages/r/r.js | 10 -
.../min/vs/basic-languages/razor/razor.js | 10 -
.../min/vs/basic-languages/redis/redis.js | 10 -
.../vs/basic-languages/redshift/redshift.js | 10 -
.../restructuredtext/restructuredtext.js | 10 -
.../min/vs/basic-languages/ruby/ruby.js | 10 -
.../min/vs/basic-languages/rust/rust.js | 10 -
.../min/vs/basic-languages/sb/sb.js | 10 -
.../min/vs/basic-languages/scala/scala.js | 10 -
.../min/vs/basic-languages/scheme/scheme.js | 10 -
.../min/vs/basic-languages/scss/scss.js | 12 -
.../min/vs/basic-languages/shell/shell.js | 10 -
.../vs/basic-languages/solidity/solidity.js | 10 -
.../min/vs/basic-languages/sophia/sophia.js | 10 -
.../min/vs/basic-languages/sparql/sparql.js | 10 -
.../min/vs/basic-languages/sql/sql.js | 10 -
.../min/vs/basic-languages/st/st.js | 10 -
.../min/vs/basic-languages/swift/swift.js | 13 -
.../systemverilog/systemverilog.js | 10 -
.../min/vs/basic-languages/tcl/tcl.js | 10 -
.../min/vs/basic-languages/twig/twig.js | 10 -
.../basic-languages/typescript/typescript.js | 10 -
.../vs/basic-languages/typespec/typespec.js | 10 -
.../min/vs/basic-languages/vb/vb.js | 10 -
.../min/vs/basic-languages/wgsl/wgsl.js | 307 -
.../min/vs/basic-languages/xml/xml.js | 10 -
.../min/vs/basic-languages/yaml/yaml.js | 10 -
.../min/vs/editor/editor.main.css | 8 -
.../min/vs/editor/editor.main.js | 798 -
.../min/vs/language/css/cssMode.js | 13 -
.../min/vs/language/css/cssWorker.js | 77 -
.../min/vs/language/html/htmlMode.js | 13 -
.../min/vs/language/html/htmlWorker.js | 454 -
.../min/vs/language/json/jsonMode.js | 19 -
.../min/vs/language/json/jsonWorker.js | 42 -
.../min/vs/language/typescript/tsMode.js | 20 -
.../min/vs/language/typescript/tsWorker.js | 51328 ----------------
.../js/monaco-editor-0.52.2/min/vs/loader.js | 11 -
.../min/vs/nls.messages.de.js | 21 -
.../min/vs/nls.messages.es.js | 21 -
.../min/vs/nls.messages.fr.js | 19 -
.../min/vs/nls.messages.it.js | 19 -
.../min/vs/nls.messages.ja.js | 21 -
.../min/vs/nls.messages.ko.js | 19 -
.../min/vs/nls.messages.ru.js | 21 -
.../min/vs/nls.messages.zh-cn.js | 21 -
.../min/vs/nls.messages.zh-tw.js | 19 -
public/js/pusher.js | 10 -
public/robots.txt | 2 +-
public/svgs/activepieces.png | Bin 21819 -> 0 bytes
public/svgs/actualbudget.png | Bin 613659 -> 0 bytes
public/svgs/affine.svg | 88 -
public/svgs/anythingllm.svg | 166 -
public/svgs/apprise.png | Bin 160907 -> 0 bytes
public/svgs/appsmith.svg | 19 -
public/svgs/appwrite.svg | 1 -
public/svgs/argilla.png | Bin 18955 -> 0 bytes
public/svgs/audiobookshelf.svg | 25 -
public/svgs/authentik.png | Bin 5736 -> 0 bytes
public/svgs/azimutt.png | Bin 12800 -> 0 bytes
public/svgs/babybuddy.png | Bin 27699 -> 0 bytes
public/svgs/beszel.svg | 1 -
public/svgs/bitcoin.svg | 15 -
public/svgs/bitwarden.svg | 59 -
public/svgs/bookstack.png | Bin 5782 -> 0 bytes
public/svgs/browserless.svg | 1 -
public/svgs/budge.png | Bin 3376 -> 0 bytes
public/svgs/budibase.svg | 21 -
public/svgs/bugsink.svg | 45 -
public/svgs/calcom.svg | 9 -
public/svgs/calibre-web.svg | 5 -
public/svgs/castopod.svg | 5 -
public/svgs/changedetection.png | Bin 31507 -> 0 bytes
public/svgs/chaskiq.png | Bin 5235 -> 0 bytes
public/svgs/chatwoot.svg | 10 -
public/svgs/checkmate.png | Bin 4867 -> 0 bytes
public/svgs/classicpress.svg | 1 -
public/svgs/clickhouse.svg | 1 -
public/svgs/cloudbeaver.svg | 7 -
public/svgs/cloudflared.svg | 26 -
public/svgs/cockpit.svg | 7 -
public/svgs/code-server.svg | 15 -
public/svgs/coder.svg | 8 -
public/svgs/convertx.png | Bin 51678 -> 0 bytes
public/svgs/convex.svg | 12 -
public/svgs/coolify.png | Bin 7872 -> 0 bytes
public/svgs/cryptgeon.png | Bin 77470 -> 0 bytes
public/svgs/cyberchef.jpeg | Bin 14831 -> 0 bytes
public/svgs/dashy.png | Bin 59523 -> 0 bytes
public/svgs/default.webp | Bin 3522 -> 0 bytes
public/svgs/denoKV.svg | 1 -
public/svgs/dify.png | Bin 7324 -> 0 bytes
public/svgs/directus.svg | 31 -
public/svgs/docker-registry.png | Bin 7191 -> 0 bytes
public/svgs/docker.svg | 1 -
public/svgs/docmost.png | Bin 1350 -> 0 bytes
public/svgs/documenso.png | Bin 10539 -> 0 bytes
public/svgs/docuseal.png | Bin 2095 -> 0 bytes
public/svgs/dokuwiki.png | Bin 3744 -> 0 bytes
public/svgs/dolibarr.png | Bin 195577 -> 0 bytes
public/svgs/dozzle.svg | 10 -
public/svgs/drupal.svg | 1 -
public/svgs/duplicati.webp | Bin 3780 -> 0 bytes
public/svgs/easyappointments.png | Bin 25264 -> 0 bytes
public/svgs/edgedb.svg | 3 -
public/svgs/emby.png | Bin 869641 -> 0 bytes
public/svgs/external-link.svg | 6 -
public/svgs/faraday.png | Bin 4015 -> 0 bytes
public/svgs/fider.svg | 1 -
public/svgs/filebrowser.svg | 147 -
public/svgs/fileflows.svg | 5 -
public/svgs/firefly.svg | 21 -
public/svgs/firefox.svg | 1 -
public/svgs/flipt.svg | 21 -
public/svgs/flowise.png | Bin 7230 -> 0 bytes
public/svgs/forgejo.svg | 1 -
public/svgs/formbricks.png | Bin 22089 -> 0 bytes
public/svgs/foundryvtt.png | Bin 35049 -> 0 bytes
public/svgs/freshrss.png | Bin 14801 -> 0 bytes
public/svgs/getoutline.jpeg | Bin 5651 -> 0 bytes
public/svgs/ghost.svg | 9 -
public/svgs/git.svg | 1 -
public/svgs/gitea.svg | 31 -
public/svgs/github.svg | 1 -
public/svgs/gitlab.svg | 1 -
public/svgs/glance.png | Bin 1167 -> 0 bytes
public/svgs/glances.png | Bin 50295 -> 0 bytes
public/svgs/glitchtip.png | Bin 16211 -> 0 bytes
public/svgs/gotenberg.png | Bin 234321 -> 0 bytes
public/svgs/grafana.svg | 1 -
public/svgs/grocy.svg | 21 -
public/svgs/heimdall.svg | 11 -
public/svgs/heyform.svg | 5 -
public/svgs/hoarder.svg | 1 -
public/svgs/homarr.svg | 11 -
public/svgs/homepage.png | Bin 30860 -> 0 bytes
public/svgs/hoppscotch.png | Bin 133464 -> 0 bytes
public/svgs/immich.svg | 66 -
public/svgs/infisical.png | Bin 4112 -> 0 bytes
public/svgs/internal-link.svg | 3 -
public/svgs/invoiceninja.png | Bin 36038 -> 0 bytes
public/svgs/it-tools.svg | 6 -
public/svgs/jellyfin.svg | 15 -
public/svgs/jenkins.svg | 283 -
public/svgs/jitsi.svg | 8 -
public/svgs/joomla.svg | 14 -
public/svgs/joplin.png | Bin 5443 -> 0 bytes
public/svgs/jupyter.svg | 90 -
public/svgs/keycloak.svg | 55 -
public/svgs/kimai.svg | 67 -
public/svgs/kuzzle.png | Bin 16439 -> 0 bytes
public/svgs/labelstudio.png | Bin 1813 -> 0 bytes
public/svgs/langfuse.png | Bin 9788 -> 0 bytes
public/svgs/libreoffice.svg | 1 -
public/svgs/libretranslate.svg | 1 -
public/svgs/listmonk.svg | 2 -
public/svgs/litellm.svg | 1 -
public/svgs/litequeen.svg | 1 -
public/svgs/logto_dark.svg | 14 -
public/svgs/lowcoder.svg | 20 -
public/svgs/macos.svg | 1 -
public/svgs/mailpit.svg | 5 -
public/svgs/mariadb.svg | 1 -
public/svgs/martin.png | Bin 187011 -> 0 bytes
public/svgs/mattermost.svg | 6 -
public/svgs/mautic.svg | 17 -
public/svgs/maybe.svg | 160 -
public/svgs/mealie.png | Bin 16365 -> 0 bytes
public/svgs/mediawiki.ico | Bin 15406 -> 0 bytes
public/svgs/meilisearch.svg | 19 -
public/svgs/metabase.svg | 1 -
public/svgs/mindsdb.svg | 12 -
public/svgs/minecraft.svg | 1 -
public/svgs/minio.svg | 1 -
public/svgs/mixpost.svg | 5 -
public/svgs/mongodb.svg | 1 -
public/svgs/moodle.png | Bin 48836 -> 0 bytes
public/svgs/mosquitto.svg | 1 -
public/svgs/mysql.svg | 1 -
public/svgs/n8n.png | Bin 7690 -> 0 bytes
public/svgs/nextcloud.svg | 73 -
public/svgs/nexus.png | Bin 6698 -> 0 bytes
public/svgs/nitropage.svg | 8 -
public/svgs/nocodb.svg | 10 -
public/svgs/nodebb.svg | 16 -
public/svgs/ntfy.svg | 1 -
public/svgs/odoo.svg | 1 -
public/svgs/ollama.svg | 14 -
public/svgs/onedev.svg | 51 -
public/svgs/openwebui.svg | 3 -
public/svgs/organizr.png | Bin 13884 -> 0 bytes
public/svgs/osticket.png | Bin 12347 -> 0 bytes
public/svgs/overseerr.svg | 6 -
public/svgs/owncloud.svg | 84 -
public/svgs/pairdrop.png | Bin 61165 -> 0 bytes
public/svgs/paperless.svg | 12 -
public/svgs/penpot.svg | 3 -
public/svgs/peppermint.png | Bin 20389 -> 0 bytes
public/svgs/phpmyadmin.svg | 1 -
public/svgs/plane.svg | 6 -
public/svgs/plex.svg | 1 -
public/svgs/plunk.svg | 1 -
public/svgs/pocketbase.svg | 9 -
public/svgs/portainer.png | Bin 6956 -> 0 bytes
public/svgs/postgres.svg | 1 -
public/svgs/postgresql.svg | 1 -
public/svgs/posthog.svg | 7 -
public/svgs/postiz.svg | 13 -
public/svgs/prefect.png | Bin 3630 -> 0 bytes
public/svgs/privatebin.svg | 1 -
public/svgs/prowlarr.svg | 1 -
public/svgs/pterodactyl.png | Bin 32004 -> 0 bytes
public/svgs/qbittorrent.svg | 16 -
public/svgs/qdrant.png | Bin 11663 -> 0 bytes
public/svgs/rabbitmq.svg | 1 -
public/svgs/radarr.svg | 1 -
public/svgs/rallly.svg | 1 -
public/svgs/readeck.svg | 9 -
public/svgs/redis.svg | 1 -
public/svgs/redlib.svg | 7 -
public/svgs/rocketchat.svg | 6 -
public/svgs/rxresume.svg | 18 -
public/svgs/searxng.svg | 56 -
public/svgs/soketi.jpeg | Bin 18264 -> 0 bytes
public/svgs/sonarr.svg | 1 -
public/svgs/statusnook.svg | 17 -
public/svgs/stirling.png | Bin 8860 -> 0 bytes
public/svgs/strapi.svg | 8 -
public/svgs/supabase.svg | 15 -
public/svgs/supertokens.svg | 17 -
public/svgs/syncthing.svg | 32 -
public/svgs/teable.png | Bin 4309 -> 0 bytes
public/svgs/tolgee.svg | 5 -
public/svgs/traccar.png | Bin 22009 -> 0 bytes
public/svgs/transmission.svg | 1 -
public/svgs/trigger.avif | Bin 6465 -> 0 bytes
public/svgs/trigger.png | Bin 1918 -> 0 bytes
public/svgs/twenty.svg | 1 -
public/svgs/umami.svg | 1 -
public/svgs/unleash.svg | 1 -
public/svgs/unsend.svg | 13 -
public/svgs/unstructured.png | Bin 14909 -> 0 bytes
public/svgs/uptime-kuma.svg | 9 -
public/svgs/vikunja.svg | 12 -
public/svgs/vvveb.svg | 1 -
public/svgs/wakapi.svg | 150 -
public/svgs/weaviate.png | Bin 18639 -> 0 bytes
public/svgs/web-check.png | Bin 21984 -> 0 bytes
public/svgs/weblate.webp | Bin 4050 -> 0 bytes
public/svgs/whoogle-search.png | Bin 23518 -> 0 bytes
public/svgs/whoogle.png | Bin 24077 -> 0 bytes
public/svgs/wikijs.svg | 119 -
public/svgs/windmill.svg | 29 -
public/svgs/windows.svg | 1 -
public/svgs/wireguard.svg | 7 -
public/svgs/wordpress.svg | 1 -
public/svgs/zep.png | Bin 10841 -> 0 bytes
public/svgs/zipline.png | Bin 27499 -> 0 bytes
public/vendor/horizon/app-dark.css | 8 -
public/vendor/horizon/app.css | 8 -
public/vendor/horizon/app.js | 2 -
public/vendor/horizon/img/favicon.png | Bin 648 -> 0 bytes
public/vendor/horizon/img/horizon.svg | 4 -
public/vendor/horizon/img/sprite.svg | 806 -
public/vendor/horizon/mix-manifest.json | 8 -
public/vendor/telescope/app-dark.css | 8 -
public/vendor/telescope/app.css | 7 -
public/vendor/telescope/app.js | 2 -
public/vendor/telescope/favicon.ico | Bin 26622 -> 0 bytes
public/vendor/telescope/mix-manifest.json | 5 -
rector.php | 34 -
resources/css/app.css | 334 +-
resources/css/fonts.css | 72 -
...k-ext_latin_latin-ext_vietnamese-100.woff2 | Bin 98024 -> 0 bytes
...k-ext_latin_latin-ext_vietnamese-200.woff2 | Bin 104156 -> 0 bytes
...k-ext_latin_latin-ext_vietnamese-300.woff2 | Bin 103704 -> 0 bytes
...k-ext_latin_latin-ext_vietnamese-500.woff2 | Bin 105412 -> 0 bytes
...k-ext_latin_latin-ext_vietnamese-600.woff2 | Bin 105940 -> 0 bytes
...k-ext_latin_latin-ext_vietnamese-700.woff2 | Bin 106308 -> 0 bytes
...k-ext_latin_latin-ext_vietnamese-800.woff2 | Bin 106012 -> 0 bytes
...k-ext_latin_latin-ext_vietnamese-900.woff2 | Bin 102324 -> 0 bytes
...t_latin_latin-ext_vietnamese-regular.woff2 | Bin 97260 -> 0 bytes
resources/js/app.js | 18 +-
resources/js/bootstrap.js | 4 +
resources/js/components/MagicBar.vue | 682 -
resources/js/terminal.js | 279 -
.../views/auth/confirm-password.blade.php | 29 -
.../views/auth/forgot-password.blade.php | 42 -
resources/views/auth/login.blade.php | 79 -
resources/views/auth/register.blade.php | 52 -
resources/views/auth/reset-password.blade.php | 41 -
.../views/auth/two-factor-challenge.blade.php | 40 -
resources/views/auth/verify-email.blade.php | 12 -
.../applications/advanced.blade.php | 36 -
.../components/applications/links.blade.php | 141 -
resources/views/components/banner.blade.php | 22 -
.../views/components/boarding-step.blade.php | 25 -
.../views/components/chevron-down.blade.php | 5 -
.../views/components/confirm-modal.blade.php | 30 -
resources/views/components/dropdown.blade.php | 23 -
.../views/components/emails/footer.blade.php | 6 -
.../views/components/emails/header.blade.php | 1 -
.../views/components/emails/layout.blade.php | 3 -
.../views/components/external-link.blade.php | 7 -
.../views/components/forms/button.blade.php | 20 -
.../views/components/forms/checkbox.blade.php | 46 -
.../views/components/forms/datalist.blade.php | 44 -
.../views/components/forms/input.blade.php | 58 -
.../components/forms/monaco-editor.blade.php | 109 -
.../views/components/forms/select.blade.php | 23 -
.../views/components/forms/textarea.blade.php | 81 -
resources/views/components/git-icon.blade.php | 31 -
resources/views/components/helper.blade.php | 18 -
.../views/components/highlighted.blade.php | 1 -
.../views/components/internal-link.blade.php | 3 -
.../views/components/layout-simple.blade.php | 1 -
resources/views/components/layout.blade.php | 1 -
.../views/components/limit-reached.blade.php | 6 -
.../components/loading-on-button.blade.php | 13 -
resources/views/components/loading.blade.php | 13 -
.../components/modal-confirmation.blade.php | 384 -
.../views/components/modal-input.blade.php | 61 -
resources/views/components/modal.blade.php | 55 -
resources/views/components/navbar.blade.php | 424 -
.../components/notification/navbar.blade.php | 33 -
.../views/components/page-loading.blade.php | 13 -
.../views/components/popup-small.blade.php | 33 -
resources/views/components/popup.blade.php | 34 -
.../views/components/pricing-plans.blade.php | 444 -
.../views/components/resource-view.blade.php | 25 -
.../resources/breadcrumbs.blade.php | 55 -
.../components/security/navbar.blade.php | 14 -
.../views/components/server/navbar.blade.php | 54 -
.../components/server/sidebar-proxy.blade.php | 16 -
.../views/components/server/sidebar.blade.php | 32 -
.../components/services/advanced.blade.php | 48 -
.../views/components/services/links.blade.php | 18 -
.../components/settings/navbar.blade.php | 27 -
.../views/components/slide-over.blade.php | 55 -
.../components/status/degraded.blade.php | 15 -
.../views/components/status/index.blade.php | 22 -
.../components/status/restarting.blade.php | 26 -
.../views/components/status/running.blade.php | 42 -
.../components/status/services.blade.php | 17 -
.../views/components/status/stopped.blade.php | 13 -
.../views/components/team/navbar.blade.php | 28 -
resources/views/components/toast.blade.php | 483 -
.../views/components/use-magic-bar.blade.php | 11 -
resources/views/components/version.blade.php | 4 -
.../application-deployment-failed.blade.php | 10 -
.../application-deployment-success.blade.php | 11 -
.../application-status-changes.blade.php | 7 -
.../views/emails/backup-failed.blade.php | 7 -
.../views/emails/backup-success.blade.php | 3 -
.../emails/before-trial-conversion.blade.php | 7 -
.../emails/container-restarted.blade.php | 9 -
.../views/emails/container-stopped.blade.php | 7 -
resources/views/emails/daily-backup.blade.php | 19 -
.../emails/docker-cleanup-failed.blade.php | 8 -
.../emails/docker-cleanup-success.blade.php | 9 -
.../views/emails/email-verification.blade.php | 3 -
resources/views/emails/help.blade.php | 5 -
.../views/emails/high-disk-usage.blade.php | 7 -
.../views/emails/invitation-link.blade.php | 9 -
.../views/emails/reset-password.blade.php | 7 -
.../emails/s3-connection-error.blade.php | 6 -
.../emails/scheduled-task-failed.blade.php | 9 -
.../emails/scheduled-task-success.blade.php | 9 -
.../emails/server-force-disabled.blade.php | 5 -
.../emails/server-force-enabled.blade.php | 3 -
.../emails/server-lost-connection.blade.php | 9 -
.../views/emails/server-revived.blade.php | 3 -
.../subscription-invoice-failed.blade.php | 5 -
resources/views/emails/test.blade.php | 3 -
resources/views/emails/trial-ended.blade.php | 5 -
.../views/emails/trial-ends-soon.blade.php | 5 -
resources/views/emails/updates.blade.php | 3 -
resources/views/errors/400.blade.php | 23 -
resources/views/errors/401.blade.php | 18 -
resources/views/errors/402.blade.php | 17 -
resources/views/errors/403.blade.php | 18 -
resources/views/errors/404.blade.php | 19 -
resources/views/errors/419.blade.php | 19 -
resources/views/errors/429.blade.php | 19 -
resources/views/errors/500.blade.php | 22 -
resources/views/errors/503.blade.php | 16 -
resources/views/layouts/app.blade.php | 62 -
resources/views/layouts/base.blade.php | 254 -
resources/views/layouts/boarding.blade.php | 7 -
resources/views/layouts/simple.blade.php | 8 -
.../views/livewire/activity-monitor.blade.php | 24 -
.../views/livewire/admin/index.blade.php | 35 -
.../views/livewire/boarding/index.blade.php | 400 -
resources/views/livewire/dashboard.blade.php | 179 -
.../livewire/destination/index.blade.php | 42 -
.../livewire/destination/new/docker.blade.php | 18 -
.../views/livewire/destination/show.blade.php | 29 -
.../livewire/force-password-reset.blade.php | 19 -
resources/views/livewire/help.blade.php | 11 -
.../views/livewire/layout-popups.blade.php | 142 -
.../livewire/navbar-delete-team.blade.php | 13 -
.../livewire/new-activity-monitor.blade.php | 18 -
.../livewire/notifications/discord.blade.php | 81 -
.../livewire/notifications/email.blade.php | 161 -
.../livewire/notifications/pushover.blade.php | 86 -
.../livewire/notifications/slack.blade.php | 79 -
.../livewire/notifications/telegram.blade.php | 166 -
.../views/livewire/profile/index.blade.php | 154 -
.../livewire/project/add-empty.blade.php | 9 -
.../project/application/advanced.blade.php | 105 -
.../application/configuration.blade.php | 123 -
.../application/deployment-navbar.blade.php | 15 -
.../application/deployment/index.blade.php | 161 -
.../application/deployment/show.blade.php | 129 -
.../project/application/destination.blade.php | 8 -
.../project/application/general.blade.php | 400 -
.../project/application/heading.blade.php | 125 -
.../application/preview/form.blade.php | 15 -
.../application/previews-compose.blade.php | 7 -
.../project/application/previews.blade.php | 196 -
.../project/application/rollback.blade.php | 47 -
.../project/application/source.blade.php | 52 -
.../project/application/swarm.blade.php | 22 -
.../views/livewire/project/clone-me.blade.php | 92 -
.../project/database/backup-edit.blade.php | 119 -
.../database/backup-executions.blade.php | 128 -
.../project/database/backup-now.blade.php | 1 -
.../database/backup/execution.blade.php | 12 -
.../project/database/backup/index.blade.php | 17 -
.../database/clickhouse/general.blade.php | 84 -
.../project/database/configuration.blade.php | 85 -
.../create-scheduled-backup.blade.php | 21 -
.../database/dragonfly/general.blade.php | 81 -
.../project/database/heading.blade.php | 112 -
.../project/database/import.blade.php | 118 -
.../project/database/init-script.blade.php | 14 -
.../project/database/keydb/general.blade.php | 84 -
.../database/mariadb/general.blade.php | 99 -
.../database/mongodb/general.blade.php | 89 -
.../project/database/mysql/general.blade.php | 99 -
.../database/postgresql/general.blade.php | 130 -
.../project/database/redis/general.blade.php | 86 -
.../database/scheduled-backups.blade.php | 41 -
.../project/delete-environment.blade.php | 5 -
.../livewire/project/delete-project.blade.php | 7 -
.../views/livewire/project/edit.blade.php | 19 -
.../project/environment-edit.blade.php | 52 -
.../views/livewire/project/index.blade.php | 58 -
.../project/new/docker-compose.blade.php | 40 -
.../project/new/docker-image.blade.php | 11 -
.../project/new/empty-project.blade.php | 1 -
...ub-private-repository-deploy-key.blade.php | 86 -
.../new/github-private-repository.blade.php | 127 -
.../new/public-git-repository.blade.php | 84 -
.../livewire/project/new/select.blade.php | 360 -
.../project/new/simple-dockerfile.blade.php | 15 -
.../project/resource/create.blade.php | 20 -
.../resource/environment-select.blade.php | 7 -
.../livewire/project/resource/index.blade.php | 265 -
.../project/service/configuration.blade.php | 202 -
.../project/service/database.blade.php | 43 -
.../project/service/edit-compose.blade.php | 49 -
.../project/service/edit-domain.blade.php | 7 -
.../project/service/file-storage.blade.php | 78 -
.../livewire/project/service/index.blade.php | 51 -
.../livewire/project/service/navbar.blade.php | 182 -
.../service-application-view.blade.php | 51 -
.../project/service/stack-form.blade.php | 40 -
.../project/service/storage.blade.php | 62 -
.../shared/configuration-checker.blade.php | 22 -
.../livewire/project/shared/danger.blade.php | 11 -
.../project/shared/destination.blade.php | 99 -
.../shared/environment-variable/add.blade.php | 20 -
.../shared/environment-variable/all.blade.php | 77 -
.../environment-variable/show.blade.php | 110 -
.../execute-container-command.blade.php | 73 -
.../project/shared/get-logs.blade.php | 108 -
.../project/shared/health-checks.blade.php | 37 -
.../livewire/project/shared/logs.blade.php | 59 -
.../livewire/project/shared/metrics.blade.php | 257 -
.../project/shared/resource-limits.blade.php | 42 -
.../shared/resource-operations.blade.php | 112 -
.../shared/scheduled-task/add.blade.php | 29 -
.../shared/scheduled-task/all.blade.php | 48 -
.../scheduled-task/executions.blade.php | 92 -
.../shared/scheduled-task/show.blade.php | 54 -
.../project/shared/storages/add.blade.php | 59 -
.../project/shared/storages/all.blade.php | 14 -
.../project/shared/storages/show.blade.php | 59 -
.../livewire/project/shared/tags.blade.php | 37 -
.../project/shared/terminal.blade.php | 47 -
.../project/shared/upload-config.blade.php | 6 -
.../project/shared/webhooks.blade.php | 56 -
.../views/livewire/project/show.blade.php | 42 -
.../livewire/security/api-tokens.blade.php | 93 -
.../security/private-key/create.blade.php | 26 -
.../security/private-key/index.blade.php | 41 -
.../security/private-key/show.blade.php | 61 -
.../views/livewire/server/advanced.blade.php | 43 -
.../views/livewire/server/charts.blade.php | 257 -
.../server/cloudflare-tunnels.blade.php | 53 -
.../configure-cloudflare-tunnels.blade.php | 6 -
.../views/livewire/server/create.blade.php | 3 -
.../views/livewire/server/delete.blade.php | 31 -
.../livewire/server/destinations.blade.php | 49 -
.../docker-cleanup-executions.blade.php | 128 -
.../livewire/server/docker-cleanup.blade.php | 85 -
.../views/livewire/server/index.blade.php | 58 -
.../livewire/server/log-drains.blade.php | 118 -
.../views/livewire/server/new/by-ip.blade.php | 73 -
.../server/private-key/show.blade.php | 43 -
.../views/livewire/server/proxy.blade.php | 97 -
.../livewire/server/proxy/deploy.blade.php | 92 -
.../dynamic-configuration-navbar.blade.php | 10 -
.../proxy/dynamic-configurations.blade.php | 55 -
.../livewire/server/proxy/logs.blade.php | 13 -
.../proxy/new-dynamic-configuration.blade.php | 5 -
.../livewire/server/proxy/show.blade.php | 16 -
.../livewire/server/proxy/status.blade.php | 15 -
.../views/livewire/server/resources.blade.php | 167 -
.../views/livewire/server/show.blade.php | 242 -
.../server/validate-and-install.blade.php | 152 -
.../views/livewire/settings-backup.blade.php | 40 -
.../views/livewire/settings-email.blade.php | 81 -
.../views/livewire/settings-oauth.blade.php | 49 -
.../views/livewire/settings/index.blade.php | 159 -
.../environment/index.blade.php | 34 -
.../environment/show.blade.php | 23 -
.../livewire/shared-variables/index.blade.php | 31 -
.../shared-variables/project/index.blade.php | 26 -
.../shared-variables/project/show.blade.php | 25 -
.../shared-variables/team/index.blade.php | 24 -
.../livewire/source/github/change.blade.php | 316 -
.../livewire/source/github/create.blade.php | 52 -
.../livewire/source/gitlab/change.blade.php | 3 -
.../views/livewire/storage/create.blade.php | 24 -
.../views/livewire/storage/form.blade.php | 41 -
.../views/livewire/storage/index.blade.php | 33 -
.../views/livewire/storage/show.blade.php | 6 -
.../livewire/subscription/actions.blade.php | 52 -
.../livewire/subscription/index.blade.php | 39 -
.../subscription/pricing-plans.blade.php | 155 -
.../livewire/subscription/show.blade.php | 8 -
.../views/livewire/switch-team.blade.php | 6 -
.../views/livewire/tags/deployments.blade.php | 27 -
resources/views/livewire/tags/show.blade.php | 96 -
.../views/livewire/team/admin-view.blade.php | 36 -
.../views/livewire/team/create.blade.php | 7 -
resources/views/livewire/team/index.blade.php | 77 -
.../views/livewire/team/invitations.blade.php | 71 -
.../views/livewire/team/invite-link.blade.php | 18 -
.../views/livewire/team/member.blade.php | 48 -
.../livewire/team/member/index.blade.php | 57 -
.../views/livewire/terminal/index.blade.php | 39 -
resources/views/livewire/upgrade.blade.php | 145 -
.../views/livewire/verify-email.blade.php | 3 -
resources/views/security/index.blade.php | 8 -
resources/views/server/create.blade.php | 9 -
resources/views/source/all.blade.php | 44 -
resources/views/source/github/show.blade.php | 4 -
resources/views/source/gitlab/new.blade.php | 4 -
resources/views/source/gitlab/show.blade.php | 3 -
.../views/vendor/mail/html/button.blade.php | 21 -
.../views/vendor/mail/html/footer.blade.php | 11 -
.../views/vendor/mail/html/header.blade.php | 12 -
.../views/vendor/mail/html/layout.blade.php | 63 -
.../views/vendor/mail/html/message.blade.php | 27 -
.../views/vendor/mail/html/panel.blade.php | 13 -
.../views/vendor/mail/html/subcopy.blade.php | 7 -
.../views/vendor/mail/html/table.blade.php | 3 -
.../views/vendor/mail/html/themes/default.css | 291 -
.../views/vendor/mail/text/button.blade.php | 1 -
.../views/vendor/mail/text/footer.blade.php | 1 -
.../views/vendor/mail/text/header.blade.php | 1 -
.../views/vendor/mail/text/layout.blade.php | 8 -
.../views/vendor/mail/text/message.blade.php | 27 -
.../views/vendor/mail/text/panel.blade.php | 1 -
.../views/vendor/mail/text/subcopy.blade.php | 1 -
.../views/vendor/mail/text/table.blade.php | 1 -
routes/api.php | 179 -
routes/channels.php | 32 -
routes/console.php | 19 -
routes/web.php | 359 -
routes/webhooks.php | 21 -
scripts/cloud_upgrade.sh | 6 -
scripts/install-1.6.sh | 571 -
scripts/install-1.7.sh | 789 -
scripts/install.sh | 814 -
scripts/run | 69 -
scripts/sync_volume.sh | 57 -
scripts/upgrade.sh | 42 -
storage/app/.gitignore | 1 +
storage/{debugbar => app/private}/.gitignore | 0
.../{pail => framework/cache/data}/.gitignore | 0
tailwind.config.js | 38 -
templates/compose/activepieces.yaml | 63 -
templates/compose/actualbudget.yaml | 19 -
templates/compose/affine.yaml | 78 -
templates/compose/anythingllm.yaml | 33 -
templates/compose/apprise-api.yaml | 21 -
templates/compose/appsmith.yaml | 22 -
templates/compose/appwrite.yaml | 718 -
templates/compose/argilla.yaml | 126 -
templates/compose/audiobookshelf.yaml | 23 -
templates/compose/authentik.yaml | 98 -
templates/compose/azimutt.yaml | 103 -
templates/compose/babybuddy.yaml | 21 -
templates/compose/beszel.yaml | 23 -
templates/compose/bitcoin-core.yaml | 27 -
templates/compose/bluesky-pds.yaml | 36 -
templates/compose/bookstack.yaml | 69 -
templates/compose/browserless.yaml | 19 -
templates/compose/budge.yaml | 20 -
templates/compose/budibase.yaml | 145 -
templates/compose/bugsink.yaml | 41 -
templates/compose/calcom.yaml | 65 -
templates/compose/calibre-web.yaml | 28 -
templates/compose/castopod.yaml | 63 -
templates/compose/changedetection.yaml | 43 -
templates/compose/chaskiq.yaml | 152 -
templates/compose/chatwoot.yaml | 115 -
templates/compose/checkmate.yaml | 46 -
.../compose/classicpress-with-mariadb.yaml | 38 -
.../compose/classicpress-with-mysql.yaml | 37 -
.../classicpress-without-database.yaml | 17 -
templates/compose/cloudbeaver.yaml | 18 -
templates/compose/cloudflared.yaml | 18 -
templates/compose/cockpit.yaml | 19 -
templates/compose/code-server.yaml | 24 -
templates/compose/coder.yaml | 46 -
templates/compose/convertx.yml | 19 -
templates/compose/convex.yaml | 40 -
templates/compose/cryptgeon.yaml | 41 -
templates/compose/cyberchef.yaml | 23 -
templates/compose/dashy.yaml | 21 -
templates/compose/denoKV.yaml | 25 -
templates/compose/dify.yaml | 640 -
.../compose/directus-with-postgresql.yaml | 62 -
templates/compose/directus.yaml | 29 -
templates/compose/docker-registry.yaml | 50 -
templates/compose/docmost.yaml | 58 -
templates/compose/documenso.yaml | 42 -
templates/compose/docuseal-with-postgres.yaml | 36 -
templates/compose/docuseal.yaml | 19 -
templates/compose/dokuwiki.yaml | 20 -
templates/compose/dolibarr.yaml | 43 -
templates/compose/dozzle-with-auth.yaml | 31 -
templates/compose/dozzle.yaml | 19 -
templates/compose/drupal-with-postgresql.yaml | 53 -
templates/compose/duplicati.yaml | 24 -
templates/compose/easyappointments.yaml | 35 -
templates/compose/edgedb.yaml | 41 -
templates/compose/emby.yaml | 23 -
templates/compose/embystat.yaml | 20 -
templates/compose/faraday.yaml | 58 -
templates/compose/fider.yaml | 44 -
templates/compose/filebrowser.yaml | 35 -
templates/compose/fileflows.yaml | 28 -
templates/compose/firefly.yaml | 76 -
templates/compose/firefox.yaml | 23 -
templates/compose/flipt.yaml | 23 -
templates/compose/flowise-with-databases.yaml | 79 -
templates/compose/flowise.yaml | 28 -
templates/compose/forgejo-with-mariadb.yaml | 50 -
templates/compose/forgejo-with-mysql.yaml | 50 -
.../compose/forgejo-with-postgresql.yaml | 49 -
.../forgejo-with-runner-with-mariadb.yaml | 137 -
.../forgejo-with-runner-with-mysql.yaml | 137 -
.../forgejo-with-runner-with-postgresql.yaml | 136 -
templates/compose/forgejo-with-runner.yaml | 114 -
templates/compose/forgejo.yaml | 27 -
templates/compose/formbricks.yaml | 86 -
templates/compose/foundryvtt.yaml | 57 -
templates/compose/freshrss-with-mariadb.yaml | 41 -
templates/compose/freshrss-with-mysql.yaml | 41 -
.../compose/freshrss-with-postgresql.yaml | 41 -
templates/compose/freshrss.yaml | 20 -
templates/compose/getoutline.yaml | 101 -
templates/compose/ghost.yaml | 48 -
templates/compose/gitea-with-mariadb.yaml | 46 -
templates/compose/gitea-with-mysql.yaml | 46 -
templates/compose/gitea-with-postgresql.yaml | 45 -
templates/compose/gitea.yaml | 23 -
templates/compose/gitlab.yaml | 34 -
templates/compose/glance.yaml | 92 -
templates/compose/glances.yaml | 31 -
templates/compose/glitchtip.yaml | 93 -
templates/compose/gotenberg.yaml | 26 -
.../compose/grafana-with-postgresql.yaml | 41 -
templates/compose/grafana.yaml | 21 -
templates/compose/grocy.yaml | 20 -
templates/compose/heimdall.yaml | 20 -
templates/compose/heyform.yaml | 55 -
templates/compose/hoarder.yaml | 46 -
templates/compose/homarr.yaml | 21 -
templates/compose/homepage.yaml | 122 -
templates/compose/hoppscotch.yaml | 95 -
templates/compose/huly.yaml | 117 -
templates/compose/immich.yaml | 76 -
templates/compose/infisical.yaml | 61 -
templates/compose/invoice-ninja.yaml | 182 -
templates/compose/it-tools.yaml | 18 -
templates/compose/jellyfin.yaml | 24 -
templates/compose/jenkins.yaml | 20 -
templates/compose/jitsi.yaml | 126 -
templates/compose/joomla-with-mariadb.yaml | 48 -
templates/compose/joplin.yaml | 46 -
.../compose/jupyter-notebook-python.yaml | 19 -
templates/compose/keycloak-with-postgres.yaml | 54 -
templates/compose/keycloak.yaml | 31 -
templates/compose/kimai.yaml | 44 -
templates/compose/kuzzle.yaml | 63 -
templates/compose/labelstudio.yaml | 49 -
templates/compose/langfuse.yaml | 55 -
templates/compose/libreoffice.yaml | 21 -
templates/compose/libretranslate.yaml | 19 -
templates/compose/listmonk.yaml | 54 -
templates/compose/litellm.yaml | 167 -
templates/compose/litequeen.yaml | 24 -
templates/compose/logto.yaml | 39 -
templates/compose/lowcoder.yaml | 21 -
templates/compose/macos.yaml | 25 -
templates/compose/mailpit.yaml | 35 -
templates/compose/martin.yaml | 36 -
templates/compose/mattermost.yaml | 46 -
templates/compose/mautic5.yaml | 120 -
templates/compose/maybe.yaml | 45 -
templates/compose/mealie.yaml | 24 -
templates/compose/mediawiki.yaml | 21 -
templates/compose/meilisearch.yaml | 21 -
templates/compose/metabase.yaml | 37 -
templates/compose/metube.yaml | 19 -
templates/compose/mindsdb.yaml | 48 -
templates/compose/minecraft.yaml | 48 -
templates/compose/minio.yaml | 21 -
templates/compose/mixpost.yaml | 56 -
templates/compose/moodle.yaml | 39 -
templates/compose/mosquitto.yaml | 48 -
templates/compose/n8n-with-postgresql.yaml | 46 -
templates/compose/n8n.yaml | 23 -
.../compose/next-image-transformation.yaml | 30 -
templates/compose/nextcloud-with-mariadb.yaml | 61 -
templates/compose/nextcloud-with-mysql.yaml | 61 -
.../compose/nextcloud-with-postgres.yaml | 60 -
templates/compose/nextcloud.yaml | 22 -
templates/compose/nexus-arm.yaml | 21 -
templates/compose/nexus.yaml | 22 -
.../compose/nitropage-with-postgresql.yaml | 37 -
templates/compose/nitropage.yaml | 21 -
templates/compose/nocodb.yaml | 18 -
templates/compose/nodebb.yaml | 54 -
templates/compose/ntfy.yaml | 46 -
templates/compose/odoo.yaml | 34 -
templates/compose/ollama-with-open-webui.yaml | 34 -
templates/compose/onedev.yaml | 43 -
templates/compose/open-webui.yaml | 24 -
templates/compose/organizr.yaml | 19 -
templates/compose/osticket.yaml | 53 -
templates/compose/overseerr.yaml | 30 -
templates/compose/owncloud.yaml | 72 -
templates/compose/pairdrop.yaml | 20 -
templates/compose/paperless.yaml | 43 -
templates/compose/penpot.yaml | 108 -
templates/compose/peppermint.yaml | 42 -
templates/compose/phpmyadmin.yaml | 22 -
templates/compose/plane.yaml | 221 -
templates/compose/plausible.yaml | 87 -
templates/compose/plex.yaml | 27 -
templates/compose/plunk.yaml | 61 -
templates/compose/pocketbase.yaml | 14 -
templates/compose/portainer.yaml | 19 -
templates/compose/posthog.yaml | 2124 -
templates/compose/postiz.yaml | 134 -
templates/compose/prefect.yaml | 80 -
templates/compose/privatebin.yaml | 18 -
templates/compose/prowlarr.yaml | 22 -
templates/compose/pterodactyl.yaml | 147 -
templates/compose/qbittorrent.yaml | 48 -
templates/compose/qdrant.yaml | 21 -
templates/compose/rabbitmq.yaml | 24 -
templates/compose/radarr.yaml | 24 -
templates/compose/rallly.yaml | 47 -
templates/compose/reactive-resume.yaml | 81 -
templates/compose/readeck.yaml | 24 -
templates/compose/redlib.yaml | 42 -
templates/compose/rocketchat.yaml | 49 -
templates/compose/searxng.yaml | 72 -
templates/compose/shlink.yaml | 31 -
templates/compose/slash.yaml | 17 -
templates/compose/snapdrop.yaml | 19 -
templates/compose/soketi.yaml | 23 -
templates/compose/sonarqube.yaml | 42 -
templates/compose/sonarr.yaml | 24 -
templates/compose/statusnook.yaml | 23 -
templates/compose/stirling-pdf.yaml | 22 -
templates/compose/strapi.yaml | 60 -
templates/compose/supabase.yaml | 1429 -
templates/compose/supertokens-with-mysql.yaml | 40 -
.../compose/supertokens-with-postgresql.yaml | 34 -
templates/compose/syncthing.yaml | 27 -
templates/compose/teable.yaml | 88 -
templates/compose/tolgee.yaml | 42 -
templates/compose/traccar.yaml | 50 -
templates/compose/transmission.yaml | 31 -
.../trigger-with-external-database.yaml | 36 -
templates/compose/trigger.yaml | 145 -
templates/compose/twenty.yaml | 92 -
templates/compose/umami.yaml | 35 -
.../compose/unleash-with-postgresql.yaml | 50 -
.../compose/unleash-without-database.yaml | 27 -
templates/compose/unsend.yaml | 60 -
templates/compose/unstructured.yaml | 21 -
templates/compose/uptime-kuma.yaml | 18 -
templates/compose/vaultwarden.yaml | 26 -
.../compose/vikunja-with-postgresql.yaml | 37 -
templates/compose/vikunja.yaml | 27 -
templates/compose/vvveb-with-mariadb.yaml | 41 -
templates/compose/vvveb-with-mysql.yaml | 41 -
templates/compose/vvveb.yaml | 18 -
templates/compose/wakapi.yaml | 60 -
templates/compose/weaviate.yaml | 45 -
templates/compose/web-check.yaml | 18 -
templates/compose/weblate.yaml | 58 -
templates/compose/whoogle.yaml | 16 -
templates/compose/wikijs.yaml | 37 -
templates/compose/windmill.yaml | 126 -
templates/compose/windows.yaml | 25 -
templates/compose/wireguard-easy.yaml | 25 -
templates/compose/wordpress-with-mariadb.yaml | 37 -
templates/compose/wordpress-with-mysql.yaml | 37 -
.../compose/wordpress-without-database.yaml | 17 -
templates/compose/zep.yaml | 188 -
templates/compose/zipline.yaml | 42 -
templates/service-templates.json | 3346 -
tests/Browser/LoginTest.php | 27 -
tests/Browser/Project/ProjectAddNewTest.php | 34 -
tests/Browser/Project/ProjectSearchTest.php | 29 -
tests/Browser/Project/ProjectTest.php | 27 -
tests/Browser/console/.gitignore | 2 -
tests/Browser/screenshots/.gitignore | 2 -
tests/Browser/source/.gitignore | 2 -
tests/CreatesApplication.php | 21 -
tests/DuskTestCase.php | 57 -
tests/Feature/ConvertArraysTest.php | 7 -
tests/Feature/ConvertingGitUrlsTest.php | 62 -
tests/Feature/DockerComposeParseTest.php | 386 -
tests/Feature/DockerCustomCommandsTest.php | 98 -
tests/Feature/ExecuteContainerCommandTest.php | 57 -
tests/Pest.php | 44 -
tests/TestCase.php | 10 -
tests/Traits/HandlesTestDatabase.php | 78 -
tests/Unit/Services/DockerImageParserTest.php | 94 -
versions.json | 19 -
vite.config.js | 50 +-
1852 files changed, 699 insertions(+), 213255 deletions(-)
delete mode 100644 .coolify-logo
delete mode 100644 .dockerignore
delete mode 100644 .env.development.example
delete mode 100644 .env.dusk.ci
create mode 100644 .env.example
delete mode 100644 .env.production
delete mode 100644 .env.windows-docker-desktop.example
delete mode 100644 .github/FUNDING.yaml
delete mode 100644 .github/ISSUE_TEMPLATE/01_BUG_REPORT.yml
delete mode 100644 .github/ISSUE_TEMPLATE/02_ENHANCEMENT_BOUNTY.yml
delete mode 100644 .github/ISSUE_TEMPLATE/config.yml
delete mode 100644 .github/pull_request_template.md
delete mode 100644 .github/workflows/browser-tests.yml
delete mode 100644 .github/workflows/chore-lock-closed-issues-discussions-and-prs.yml
delete mode 100644 .github/workflows/chore-manage-stale-issues-and-prs.yml
delete mode 100644 .github/workflows/chore-remove-labels-and-assignees-on-close.yml
delete mode 100644 .github/workflows/coolify-helper-next.yml
delete mode 100644 .github/workflows/coolify-helper.yml
delete mode 100644 .github/workflows/coolify-production-build.yml
delete mode 100644 .github/workflows/coolify-realtime-next.yml
delete mode 100644 .github/workflows/coolify-realtime.yml
delete mode 100644 .github/workflows/coolify-staging-build.yml
delete mode 100644 .github/workflows/coolify-testing-host.yml
delete mode 100644 .github/workflows/generate-changelog.yml
delete mode 100644 CHANGELOG.md
delete mode 100644 CODE_OF_CONDUCT.md
delete mode 100644 CONTRIBUTING.md
delete mode 100644 LICENSE
delete mode 100644 RELEASE.md
delete mode 100644 SECURITY.md
delete mode 100644 TECH_STACK.md
delete mode 100644 app/Actions/Application/GenerateConfig.php
delete mode 100644 app/Actions/Application/IsHorizonQueueEmpty.php
delete mode 100644 app/Actions/Application/LoadComposeFile.php
delete mode 100644 app/Actions/Application/StopApplication.php
delete mode 100644 app/Actions/Application/StopApplicationOneServer.php
delete mode 100644 app/Actions/CoolifyTask/PrepareCoolifyTask.php
delete mode 100644 app/Actions/CoolifyTask/RunRemoteProcess.php
delete mode 100644 app/Actions/Database/RestartDatabase.php
delete mode 100644 app/Actions/Database/StartClickhouse.php
delete mode 100644 app/Actions/Database/StartDatabase.php
delete mode 100644 app/Actions/Database/StartDatabaseProxy.php
delete mode 100644 app/Actions/Database/StartDragonfly.php
delete mode 100644 app/Actions/Database/StartKeydb.php
delete mode 100644 app/Actions/Database/StartMariadb.php
delete mode 100644 app/Actions/Database/StartMongodb.php
delete mode 100644 app/Actions/Database/StartMysql.php
delete mode 100644 app/Actions/Database/StartPostgresql.php
delete mode 100644 app/Actions/Database/StartRedis.php
delete mode 100644 app/Actions/Database/StopDatabase.php
delete mode 100644 app/Actions/Database/StopDatabaseProxy.php
delete mode 100644 app/Actions/Docker/GetContainersStatus.php
delete mode 100644 app/Actions/Fortify/CreateNewUser.php
delete mode 100644 app/Actions/Fortify/ResetUserPassword.php
delete mode 100644 app/Actions/Fortify/UpdateUserPassword.php
delete mode 100644 app/Actions/Fortify/UpdateUserProfileInformation.php
delete mode 100644 app/Actions/Proxy/CheckConfiguration.php
delete mode 100644 app/Actions/Proxy/CheckProxy.php
delete mode 100644 app/Actions/Proxy/SaveConfiguration.php
delete mode 100644 app/Actions/Proxy/StartProxy.php
delete mode 100644 app/Actions/Server/CleanupDocker.php
delete mode 100644 app/Actions/Server/ConfigureCloudflared.php
delete mode 100644 app/Actions/Server/DeleteServer.php
delete mode 100644 app/Actions/Server/InstallDocker.php
delete mode 100644 app/Actions/Server/ResourcesCheck.php
delete mode 100644 app/Actions/Server/RestartContainer.php
delete mode 100644 app/Actions/Server/RunCommand.php
delete mode 100644 app/Actions/Server/ServerCheck.php
delete mode 100644 app/Actions/Server/StartLogDrain.php
delete mode 100644 app/Actions/Server/StartSentinel.php
delete mode 100644 app/Actions/Server/StopLogDrain.php
delete mode 100644 app/Actions/Server/StopSentinel.php
delete mode 100644 app/Actions/Server/UpdateCoolify.php
delete mode 100644 app/Actions/Server/ValidateServer.php
delete mode 100644 app/Actions/Service/DeleteService.php
delete mode 100644 app/Actions/Service/RestartService.php
delete mode 100644 app/Actions/Service/StartService.php
delete mode 100644 app/Actions/Service/StopService.php
delete mode 100644 app/Actions/Shared/ComplexStatusCheck.php
delete mode 100644 app/Console/Commands/AdminRemoveUser.php
delete mode 100644 app/Console/Commands/CheckApplicationDeploymentQueue.php
delete mode 100644 app/Console/Commands/CleanupApplicationDeploymentQueue.php
delete mode 100644 app/Console/Commands/CleanupDatabase.php
delete mode 100644 app/Console/Commands/CleanupRedis.php
delete mode 100644 app/Console/Commands/CleanupStuckedResources.php
delete mode 100644 app/Console/Commands/CleanupUnreachableServers.php
delete mode 100644 app/Console/Commands/CloudCheckSubscription.php
delete mode 100644 app/Console/Commands/CloudCleanupSubscriptions.php
delete mode 100644 app/Console/Commands/Dev.php
delete mode 100644 app/Console/Commands/Emails.php
delete mode 100644 app/Console/Commands/Horizon.php
delete mode 100644 app/Console/Commands/HorizonManage.php
delete mode 100644 app/Console/Commands/Init.php
delete mode 100644 app/Console/Commands/Migration.php
delete mode 100644 app/Console/Commands/NotifyDemo.php
delete mode 100644 app/Console/Commands/OpenApi.php
delete mode 100644 app/Console/Commands/RootChangeEmail.php
delete mode 100644 app/Console/Commands/RootResetPassword.php
delete mode 100644 app/Console/Commands/Scheduler.php
delete mode 100644 app/Console/Commands/Seeder.php
delete mode 100644 app/Console/Commands/ServicesDelete.php
delete mode 100644 app/Console/Commands/ServicesGenerate.php
delete mode 100644 app/Console/Commands/SyncBunny.php
delete mode 100644 app/Console/Kernel.php
delete mode 100644 app/Contracts/CustomJobRepositoryInterface.php
delete mode 100644 app/Data/CoolifyTaskArgs.php
delete mode 100644 app/Data/ServerMetadata.php
delete mode 100644 app/Enums/ActivityTypes.php
delete mode 100644 app/Enums/ApplicationDeploymentStatus.php
delete mode 100644 app/Enums/BuildPackTypes.php
delete mode 100644 app/Enums/ContainerStatusTypes.php
delete mode 100644 app/Enums/NewDatabaseTypes.php
delete mode 100644 app/Enums/NewResourceTypes.php
delete mode 100644 app/Enums/ProcessStatus.php
delete mode 100644 app/Enums/ProxyTypes.php
delete mode 100644 app/Enums/RedirectTypes.php
delete mode 100644 app/Enums/Role.php
delete mode 100644 app/Enums/StaticImageTypes.php
delete mode 100644 app/Events/ApplicationStatusChanged.php
delete mode 100644 app/Events/BackupCreated.php
delete mode 100644 app/Events/CloudflareTunnelConfigured.php
delete mode 100644 app/Events/DatabaseProxyStopped.php
delete mode 100644 app/Events/DatabaseStatusChanged.php
delete mode 100644 app/Events/DockerCleanupDone.php
delete mode 100644 app/Events/FileStorageChanged.php
delete mode 100644 app/Events/ProxyStarted.php
delete mode 100644 app/Events/ProxyStatusChanged.php
delete mode 100644 app/Events/RestoreJobFinished.php
delete mode 100644 app/Events/ScheduledTaskDone.php
delete mode 100644 app/Events/ServerReachabilityChanged.php
delete mode 100644 app/Events/ServiceStatusChanged.php
delete mode 100644 app/Events/TestEvent.php
delete mode 100644 app/Exceptions/Handler.php
delete mode 100644 app/Exceptions/ProcessException.php
delete mode 100644 app/Helpers/SshMultiplexingHelper.php
delete mode 100644 app/Http/Controllers/Api/ApplicationsController.php
delete mode 100644 app/Http/Controllers/Api/DatabasesController.php
delete mode 100644 app/Http/Controllers/Api/DeployController.php
delete mode 100644 app/Http/Controllers/Api/OpenApi.php
delete mode 100644 app/Http/Controllers/Api/OtherController.php
delete mode 100644 app/Http/Controllers/Api/ProjectController.php
delete mode 100644 app/Http/Controllers/Api/ResourcesController.php
delete mode 100644 app/Http/Controllers/Api/SecurityController.php
delete mode 100644 app/Http/Controllers/Api/ServersController.php
delete mode 100644 app/Http/Controllers/Api/ServicesController.php
delete mode 100644 app/Http/Controllers/Api/TeamController.php
delete mode 100644 app/Http/Controllers/Controller.php
delete mode 100644 app/Http/Controllers/MagicController.php
delete mode 100644 app/Http/Controllers/OauthController.php
delete mode 100644 app/Http/Controllers/UploadController.php
delete mode 100644 app/Http/Controllers/Webhook/Bitbucket.php
delete mode 100644 app/Http/Controllers/Webhook/Gitea.php
delete mode 100644 app/Http/Controllers/Webhook/Github.php
delete mode 100644 app/Http/Controllers/Webhook/Gitlab.php
delete mode 100644 app/Http/Controllers/Webhook/Stripe.php
delete mode 100644 app/Http/Kernel.php
delete mode 100644 app/Http/Middleware/ApiAbility.php
delete mode 100644 app/Http/Middleware/ApiAllowed.php
delete mode 100644 app/Http/Middleware/ApiSensitiveData.php
delete mode 100644 app/Http/Middleware/Authenticate.php
delete mode 100644 app/Http/Middleware/CheckForcePasswordReset.php
delete mode 100644 app/Http/Middleware/DecideWhatToDoWithUser.php
delete mode 100644 app/Http/Middleware/EncryptCookies.php
delete mode 100644 app/Http/Middleware/PreventRequestsDuringMaintenance.php
delete mode 100644 app/Http/Middleware/RedirectIfAuthenticated.php
delete mode 100644 app/Http/Middleware/TrimStrings.php
delete mode 100644 app/Http/Middleware/TrustHosts.php
delete mode 100644 app/Http/Middleware/TrustProxies.php
delete mode 100644 app/Http/Middleware/ValidateSignature.php
delete mode 100644 app/Http/Middleware/VerifyCsrfToken.php
delete mode 100644 app/Jobs/ApplicationDeploymentJob.php
delete mode 100755 app/Jobs/ApplicationPullRequestUpdateJob.php
delete mode 100644 app/Jobs/CheckAndStartSentinelJob.php
delete mode 100644 app/Jobs/CheckForUpdatesJob.php
delete mode 100644 app/Jobs/CheckHelperImageJob.php
delete mode 100644 app/Jobs/CleanupHelperContainersJob.php
delete mode 100644 app/Jobs/CleanupInstanceStuffsJob.php
delete mode 100644 app/Jobs/CleanupStaleMultiplexedConnections.php
delete mode 100644 app/Jobs/ContainerStatusJob.php
delete mode 100755 app/Jobs/CoolifyTask.php
delete mode 100644 app/Jobs/DatabaseBackupJob.php
delete mode 100644 app/Jobs/DeleteResourceJob.php
delete mode 100644 app/Jobs/DockerCleanupJob.php
delete mode 100644 app/Jobs/GithubAppPermissionJob.php
delete mode 100644 app/Jobs/PullHelperImageJob.php
delete mode 100644 app/Jobs/PullTemplatesFromCDN.php
delete mode 100644 app/Jobs/PushServerUpdateJob.php
delete mode 100644 app/Jobs/ScheduledTaskJob.php
delete mode 100644 app/Jobs/SendMessageToDiscordJob.php
delete mode 100644 app/Jobs/SendMessageToPushoverJob.php
delete mode 100644 app/Jobs/SendMessageToSlackJob.php
delete mode 100644 app/Jobs/SendMessageToTelegramJob.php
delete mode 100644 app/Jobs/ServerCheckJob.php
delete mode 100644 app/Jobs/ServerCheckNewJob.php
delete mode 100644 app/Jobs/ServerCleanupMux.php
delete mode 100644 app/Jobs/ServerFilesFromServerJob.php
delete mode 100644 app/Jobs/ServerLimitCheckJob.php
delete mode 100644 app/Jobs/ServerStorageCheckJob.php
delete mode 100644 app/Jobs/ServerStorageSaveJob.php
delete mode 100644 app/Jobs/StripeProcessJob.php
delete mode 100755 app/Jobs/SubscriptionInvoiceFailedJob.php
delete mode 100644 app/Jobs/UpdateCoolifyJob.php
delete mode 100644 app/Jobs/VolumeCloneJob.php
delete mode 100644 app/Listeners/MaintenanceModeDisabledNotification.php
delete mode 100644 app/Listeners/MaintenanceModeEnabledNotification.php
delete mode 100644 app/Listeners/ProxyStartedNotification.php
delete mode 100644 app/Livewire/ActivityMonitor.php
delete mode 100644 app/Livewire/Admin/Index.php
delete mode 100644 app/Livewire/Boarding/Index.php
delete mode 100644 app/Livewire/Dashboard.php
delete mode 100644 app/Livewire/Destination/Index.php
delete mode 100644 app/Livewire/Destination/New/Docker.php
delete mode 100644 app/Livewire/Destination/Show.php
delete mode 100644 app/Livewire/ForcePasswordReset.php
delete mode 100644 app/Livewire/Help.php
delete mode 100644 app/Livewire/LayoutPopups.php
delete mode 100644 app/Livewire/MonacoEditor.php
delete mode 100644 app/Livewire/NavbarDeleteTeam.php
delete mode 100644 app/Livewire/NewActivityMonitor.php
delete mode 100644 app/Livewire/Notifications/Discord.php
delete mode 100644 app/Livewire/Notifications/Email.php
delete mode 100644 app/Livewire/Notifications/Pushover.php
delete mode 100644 app/Livewire/Notifications/Slack.php
delete mode 100644 app/Livewire/Notifications/Telegram.php
delete mode 100644 app/Livewire/Profile/Index.php
delete mode 100644 app/Livewire/Project/AddEmpty.php
delete mode 100644 app/Livewire/Project/Application/Advanced.php
delete mode 100644 app/Livewire/Project/Application/Configuration.php
delete mode 100644 app/Livewire/Project/Application/Deployment/Index.php
delete mode 100644 app/Livewire/Project/Application/Deployment/Show.php
delete mode 100644 app/Livewire/Project/Application/DeploymentNavbar.php
delete mode 100644 app/Livewire/Project/Application/General.php
delete mode 100644 app/Livewire/Project/Application/Heading.php
delete mode 100644 app/Livewire/Project/Application/Preview/Form.php
delete mode 100644 app/Livewire/Project/Application/Previews.php
delete mode 100644 app/Livewire/Project/Application/PreviewsCompose.php
delete mode 100644 app/Livewire/Project/Application/Rollback.php
delete mode 100644 app/Livewire/Project/Application/Source.php
delete mode 100644 app/Livewire/Project/Application/Swarm.php
delete mode 100644 app/Livewire/Project/CloneMe.php
delete mode 100644 app/Livewire/Project/Database/Backup/Execution.php
delete mode 100644 app/Livewire/Project/Database/Backup/Index.php
delete mode 100644 app/Livewire/Project/Database/BackupEdit.php
delete mode 100644 app/Livewire/Project/Database/BackupExecutions.php
delete mode 100644 app/Livewire/Project/Database/BackupNow.php
delete mode 100644 app/Livewire/Project/Database/Clickhouse/General.php
delete mode 100644 app/Livewire/Project/Database/Configuration.php
delete mode 100644 app/Livewire/Project/Database/CreateScheduledBackup.php
delete mode 100644 app/Livewire/Project/Database/Dragonfly/General.php
delete mode 100644 app/Livewire/Project/Database/Heading.php
delete mode 100644 app/Livewire/Project/Database/Import.php
delete mode 100644 app/Livewire/Project/Database/InitScript.php
delete mode 100644 app/Livewire/Project/Database/Keydb/General.php
delete mode 100644 app/Livewire/Project/Database/Mariadb/General.php
delete mode 100644 app/Livewire/Project/Database/Mongodb/General.php
delete mode 100644 app/Livewire/Project/Database/Mysql/General.php
delete mode 100644 app/Livewire/Project/Database/Postgresql/General.php
delete mode 100644 app/Livewire/Project/Database/Redis/General.php
delete mode 100644 app/Livewire/Project/Database/ScheduledBackups.php
delete mode 100644 app/Livewire/Project/DeleteEnvironment.php
delete mode 100644 app/Livewire/Project/DeleteProject.php
delete mode 100644 app/Livewire/Project/Edit.php
delete mode 100644 app/Livewire/Project/EnvironmentEdit.php
delete mode 100644 app/Livewire/Project/Index.php
delete mode 100644 app/Livewire/Project/New/DockerCompose.php
delete mode 100644 app/Livewire/Project/New/DockerImage.php
delete mode 100644 app/Livewire/Project/New/EmptyProject.php
delete mode 100644 app/Livewire/Project/New/GithubPrivateRepository.php
delete mode 100644 app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
delete mode 100644 app/Livewire/Project/New/PublicGitRepository.php
delete mode 100644 app/Livewire/Project/New/Select.php
delete mode 100644 app/Livewire/Project/New/SimpleDockerfile.php
delete mode 100644 app/Livewire/Project/Resource/Create.php
delete mode 100644 app/Livewire/Project/Resource/EnvironmentSelect.php
delete mode 100644 app/Livewire/Project/Resource/Index.php
delete mode 100644 app/Livewire/Project/Service/Configuration.php
delete mode 100644 app/Livewire/Project/Service/Database.php
delete mode 100644 app/Livewire/Project/Service/EditCompose.php
delete mode 100644 app/Livewire/Project/Service/EditDomain.php
delete mode 100644 app/Livewire/Project/Service/FileStorage.php
delete mode 100644 app/Livewire/Project/Service/Index.php
delete mode 100644 app/Livewire/Project/Service/Navbar.php
delete mode 100644 app/Livewire/Project/Service/ServiceApplicationView.php
delete mode 100644 app/Livewire/Project/Service/StackForm.php
delete mode 100644 app/Livewire/Project/Service/Storage.php
delete mode 100644 app/Livewire/Project/Shared/ConfigurationChecker.php
delete mode 100644 app/Livewire/Project/Shared/Danger.php
delete mode 100644 app/Livewire/Project/Shared/Destination.php
delete mode 100644 app/Livewire/Project/Shared/EnvironmentVariable/Add.php
delete mode 100644 app/Livewire/Project/Shared/EnvironmentVariable/All.php
delete mode 100644 app/Livewire/Project/Shared/EnvironmentVariable/Show.php
delete mode 100644 app/Livewire/Project/Shared/ExecuteContainerCommand.php
delete mode 100644 app/Livewire/Project/Shared/GetLogs.php
delete mode 100644 app/Livewire/Project/Shared/HealthChecks.php
delete mode 100644 app/Livewire/Project/Shared/Logs.php
delete mode 100644 app/Livewire/Project/Shared/Metrics.php
delete mode 100644 app/Livewire/Project/Shared/ResourceLimits.php
delete mode 100644 app/Livewire/Project/Shared/ResourceOperations.php
delete mode 100644 app/Livewire/Project/Shared/ScheduledTask/Add.php
delete mode 100644 app/Livewire/Project/Shared/ScheduledTask/All.php
delete mode 100644 app/Livewire/Project/Shared/ScheduledTask/Executions.php
delete mode 100644 app/Livewire/Project/Shared/ScheduledTask/Show.php
delete mode 100644 app/Livewire/Project/Shared/Storages/Add.php
delete mode 100644 app/Livewire/Project/Shared/Storages/All.php
delete mode 100644 app/Livewire/Project/Shared/Storages/Show.php
delete mode 100644 app/Livewire/Project/Shared/Tags.php
delete mode 100644 app/Livewire/Project/Shared/Terminal.php
delete mode 100644 app/Livewire/Project/Shared/UploadConfig.php
delete mode 100644 app/Livewire/Project/Shared/Webhooks.php
delete mode 100644 app/Livewire/Project/Show.php
delete mode 100644 app/Livewire/Security/ApiTokens.php
delete mode 100644 app/Livewire/Security/PrivateKey/Create.php
delete mode 100644 app/Livewire/Security/PrivateKey/Index.php
delete mode 100644 app/Livewire/Security/PrivateKey/Show.php
delete mode 100644 app/Livewire/Server/Advanced.php
delete mode 100644 app/Livewire/Server/Charts.php
delete mode 100644 app/Livewire/Server/CloudflareTunnels.php
delete mode 100644 app/Livewire/Server/ConfigureCloudflareTunnels.php
delete mode 100644 app/Livewire/Server/Create.php
delete mode 100644 app/Livewire/Server/Delete.php
delete mode 100644 app/Livewire/Server/Destinations.php
delete mode 100644 app/Livewire/Server/DockerCleanup.php
delete mode 100644 app/Livewire/Server/DockerCleanupExecutions.php
delete mode 100644 app/Livewire/Server/Index.php
delete mode 100644 app/Livewire/Server/LogDrains.php
delete mode 100644 app/Livewire/Server/New/ByIp.php
delete mode 100644 app/Livewire/Server/PrivateKey/Show.php
delete mode 100644 app/Livewire/Server/Proxy.php
delete mode 100644 app/Livewire/Server/Proxy/Deploy.php
delete mode 100644 app/Livewire/Server/Proxy/DynamicConfigurationNavbar.php
delete mode 100644 app/Livewire/Server/Proxy/DynamicConfigurations.php
delete mode 100644 app/Livewire/Server/Proxy/Logs.php
delete mode 100644 app/Livewire/Server/Proxy/NewDynamicConfiguration.php
delete mode 100644 app/Livewire/Server/Proxy/Show.php
delete mode 100644 app/Livewire/Server/Proxy/Status.php
delete mode 100644 app/Livewire/Server/Resources.php
delete mode 100644 app/Livewire/Server/Show.php
delete mode 100644 app/Livewire/Server/ValidateAndInstall.php
delete mode 100644 app/Livewire/Settings/Index.php
delete mode 100644 app/Livewire/SettingsBackup.php
delete mode 100644 app/Livewire/SettingsEmail.php
delete mode 100644 app/Livewire/SettingsOauth.php
delete mode 100644 app/Livewire/SharedVariables/Environment/Index.php
delete mode 100644 app/Livewire/SharedVariables/Environment/Show.php
delete mode 100644 app/Livewire/SharedVariables/Index.php
delete mode 100644 app/Livewire/SharedVariables/Project/Index.php
delete mode 100644 app/Livewire/SharedVariables/Project/Show.php
delete mode 100644 app/Livewire/SharedVariables/Team/Index.php
delete mode 100644 app/Livewire/Source/Github/Change.php
delete mode 100644 app/Livewire/Source/Github/Create.php
delete mode 100644 app/Livewire/Source/Gitlab/Change.php
delete mode 100644 app/Livewire/Storage/Create.php
delete mode 100644 app/Livewire/Storage/Form.php
delete mode 100644 app/Livewire/Storage/Index.php
delete mode 100644 app/Livewire/Storage/Show.php
delete mode 100644 app/Livewire/Subscription/Actions.php
delete mode 100644 app/Livewire/Subscription/Index.php
delete mode 100644 app/Livewire/Subscription/PricingPlans.php
delete mode 100644 app/Livewire/Subscription/Show.php
delete mode 100644 app/Livewire/SwitchTeam.php
delete mode 100644 app/Livewire/Tags/Deployments.php
delete mode 100644 app/Livewire/Tags/Show.php
delete mode 100644 app/Livewire/Team/AdminView.php
delete mode 100644 app/Livewire/Team/Create.php
delete mode 100644 app/Livewire/Team/Index.php
delete mode 100644 app/Livewire/Team/Invitations.php
delete mode 100644 app/Livewire/Team/InviteLink.php
delete mode 100644 app/Livewire/Team/Member.php
delete mode 100644 app/Livewire/Team/Member/Index.php
delete mode 100644 app/Livewire/Team/Storage/Show.php
delete mode 100644 app/Livewire/Terminal/Index.php
delete mode 100644 app/Livewire/Upgrade.php
delete mode 100644 app/Livewire/VerifyEmail.php
delete mode 100644 app/Models/Application.php
delete mode 100644 app/Models/ApplicationDeploymentQueue.php
delete mode 100644 app/Models/ApplicationPreview.php
delete mode 100644 app/Models/ApplicationSetting.php
delete mode 100644 app/Models/BaseModel.php
delete mode 100644 app/Models/DiscordNotificationSettings.php
delete mode 100644 app/Models/DockerCleanupExecution.php
delete mode 100644 app/Models/EmailNotificationSettings.php
delete mode 100644 app/Models/Environment.php
delete mode 100644 app/Models/EnvironmentVariable.php
delete mode 100644 app/Models/GithubApp.php
delete mode 100644 app/Models/GitlabApp.php
delete mode 100644 app/Models/InstanceSettings.php
delete mode 100644 app/Models/Kubernetes.php
delete mode 100644 app/Models/LocalFileVolume.php
delete mode 100644 app/Models/LocalPersistentVolume.php
delete mode 100644 app/Models/OauthSetting.php
delete mode 100644 app/Models/PersonalAccessToken.php
delete mode 100644 app/Models/PrivateKey.php
delete mode 100644 app/Models/Project.php
delete mode 100644 app/Models/ProjectSetting.php
delete mode 100644 app/Models/PushoverNotificationSettings.php
delete mode 100644 app/Models/S3Storage.php
delete mode 100644 app/Models/ScheduledDatabaseBackup.php
delete mode 100644 app/Models/ScheduledDatabaseBackupExecution.php
delete mode 100644 app/Models/ScheduledTask.php
delete mode 100644 app/Models/ScheduledTaskExecution.php
delete mode 100644 app/Models/Server.php
delete mode 100644 app/Models/ServerSetting.php
delete mode 100644 app/Models/Service.php
delete mode 100644 app/Models/ServiceApplication.php
delete mode 100644 app/Models/ServiceDatabase.php
delete mode 100644 app/Models/SharedEnvironmentVariable.php
delete mode 100644 app/Models/SlackNotificationSettings.php
delete mode 100644 app/Models/StandaloneClickhouse.php
delete mode 100644 app/Models/StandaloneDocker.php
delete mode 100644 app/Models/StandaloneDragonfly.php
delete mode 100644 app/Models/StandaloneKeydb.php
delete mode 100644 app/Models/StandaloneMariadb.php
delete mode 100644 app/Models/StandaloneMongodb.php
delete mode 100644 app/Models/StandaloneMysql.php
delete mode 100644 app/Models/StandalonePostgresql.php
delete mode 100644 app/Models/StandaloneRedis.php
delete mode 100644 app/Models/Subscription.php
delete mode 100644 app/Models/SwarmDocker.php
delete mode 100644 app/Models/Tag.php
delete mode 100644 app/Models/Team.php
delete mode 100644 app/Models/TeamInvitation.php
delete mode 100644 app/Models/TelegramNotificationSettings.php
delete mode 100644 app/Models/User.php
delete mode 100644 app/Models/Webhook.php
delete mode 100644 app/Notifications/Application/DeploymentFailed.php
delete mode 100644 app/Notifications/Application/DeploymentSuccess.php
delete mode 100644 app/Notifications/Application/StatusChanged.php
delete mode 100644 app/Notifications/Channels/DiscordChannel.php
delete mode 100644 app/Notifications/Channels/EmailChannel.php
delete mode 100644 app/Notifications/Channels/PushoverChannel.php
delete mode 100644 app/Notifications/Channels/SendsDiscord.php
delete mode 100644 app/Notifications/Channels/SendsEmail.php
delete mode 100644 app/Notifications/Channels/SendsPushover.php
delete mode 100644 app/Notifications/Channels/SendsSlack.php
delete mode 100644 app/Notifications/Channels/SendsTelegram.php
delete mode 100644 app/Notifications/Channels/SlackChannel.php
delete mode 100644 app/Notifications/Channels/TelegramChannel.php
delete mode 100644 app/Notifications/Channels/TransactionalEmailChannel.php
delete mode 100644 app/Notifications/Container/ContainerRestarted.php
delete mode 100644 app/Notifications/Container/ContainerStopped.php
delete mode 100644 app/Notifications/CustomEmailNotification.php
delete mode 100644 app/Notifications/Database/BackupFailed.php
delete mode 100644 app/Notifications/Database/BackupSuccess.php
delete mode 100644 app/Notifications/Dto/DiscordMessage.php
delete mode 100644 app/Notifications/Dto/PushoverMessage.php
delete mode 100644 app/Notifications/Dto/SlackMessage.php
delete mode 100644 app/Notifications/Internal/GeneralNotification.php
delete mode 100644 app/Notifications/ScheduledTask/TaskFailed.php
delete mode 100644 app/Notifications/ScheduledTask/TaskSuccess.php
delete mode 100644 app/Notifications/Server/DockerCleanupFailed.php
delete mode 100644 app/Notifications/Server/DockerCleanupSuccess.php
delete mode 100644 app/Notifications/Server/ForceDisabled.php
delete mode 100644 app/Notifications/Server/ForceEnabled.php
delete mode 100644 app/Notifications/Server/HighDiskUsage.php
delete mode 100644 app/Notifications/Server/Reachable.php
delete mode 100644 app/Notifications/Server/Unreachable.php
delete mode 100644 app/Notifications/Test.php
delete mode 100644 app/Notifications/TransactionalEmails/InvitationLink.php
delete mode 100644 app/Notifications/TransactionalEmails/ResetPassword.php
delete mode 100644 app/Notifications/TransactionalEmails/Test.php
delete mode 100644 app/Policies/ApplicationPolicy.php
delete mode 100644 app/Policies/ServerPolicy.php
delete mode 100644 app/Policies/ServicePolicy.php
delete mode 100644 app/Providers/AuthServiceProvider.php
delete mode 100644 app/Providers/BroadcastServiceProvider.php
delete mode 100644 app/Providers/DuskServiceProvider.php
delete mode 100644 app/Providers/EventServiceProvider.php
delete mode 100644 app/Providers/FortifyServiceProvider.php
delete mode 100644 app/Providers/HorizonServiceProvider.php
delete mode 100644 app/Providers/RouteServiceProvider.php
delete mode 100644 app/Providers/TelescopeServiceProvider.php
delete mode 100644 app/Repositories/CustomJobRepository.php
delete mode 100644 app/Services/ConfigurationGenerator.php
delete mode 100644 app/Services/DockerImageParser.php
delete mode 100644 app/Traits/ExecuteRemoteCommand.php
delete mode 100644 app/Traits/HasConfiguration.php
delete mode 100644 app/Traits/HasNotificationSettings.php
delete mode 100644 app/Traits/SaveFromRedirect.php
delete mode 100644 app/View/Components/Forms/Button.php
delete mode 100644 app/View/Components/Forms/Checkbox.php
delete mode 100644 app/View/Components/Forms/Datalist.php
delete mode 100644 app/View/Components/Forms/Input.php
delete mode 100644 app/View/Components/Forms/Select.php
delete mode 100644 app/View/Components/Forms/Textarea.php
delete mode 100644 app/View/Components/Modal.php
delete mode 100644 app/View/Components/ResourceView.php
delete mode 100644 app/View/Components/Services/Explanation.php
delete mode 100644 app/View/Components/Services/Links.php
delete mode 100644 app/View/Components/Status/Index.php
delete mode 100644 app/View/Components/Status/Services.php
delete mode 100644 app/View/Components/services/advanced.php
delete mode 100644 bootstrap/getHelperVersion.php
delete mode 100644 bootstrap/getRealtimeVersion.php
delete mode 100644 bootstrap/getVersion.php
delete mode 100644 bootstrap/helpers/api.php
delete mode 100644 bootstrap/helpers/applications.php
delete mode 100644 bootstrap/helpers/constants.php
delete mode 100644 bootstrap/helpers/databases.php
delete mode 100644 bootstrap/helpers/docker.php
delete mode 100644 bootstrap/helpers/github.php
delete mode 100644 bootstrap/helpers/notifications.php
delete mode 100644 bootstrap/helpers/proxy.php
delete mode 100644 bootstrap/helpers/remoteProcess.php
delete mode 100644 bootstrap/helpers/services.php
delete mode 100644 bootstrap/helpers/shared.php
delete mode 100644 bootstrap/helpers/socialite.php
delete mode 100644 bootstrap/helpers/subscriptions.php
delete mode 100644 bootstrap/helpers/timezone.php
delete mode 100644 bootstrap/includeHelpers.php
create mode 100644 bootstrap/providers.php
delete mode 100644 cliff.toml
delete mode 100644 config/broadcasting.php
delete mode 100644 config/chunk-upload.php
delete mode 100644 config/constants.php
delete mode 100644 config/cors.php
delete mode 100644 config/debugbar.php
delete mode 100644 config/fortify.php
delete mode 100644 config/hashing.php
delete mode 100644 config/horizon.php
delete mode 100644 config/livewire.php
delete mode 100644 config/purify.php
delete mode 100644 config/ray.php
delete mode 100644 config/redoc.php
delete mode 100644 config/sanctum.php
delete mode 100644 config/sentry.php
delete mode 100644 config/subscription.php
delete mode 100644 config/telescope.php
delete mode 100644 config/testing.php
delete mode 100644 config/view.php
delete mode 100644 database/.gitignore
delete mode 100644 database/factories/ApplicationFactory.php
delete mode 100644 database/factories/ServerFactory.php
delete mode 100644 database/factories/UserFactory.php
delete mode 100644 database/migrations/2014_10_12_000000_create_users_table.php
delete mode 100644 database/migrations/2014_10_12_100000_create_password_reset_tokens_table.php
delete mode 100644 database/migrations/2014_10_12_200000_add_two_factor_columns_to_users_table.php
delete mode 100644 database/migrations/2018_08_08_100000_create_telescope_entries_table.php
delete mode 100644 database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php
delete mode 100755 database/migrations/2023_03_20_112410_create_activity_log_table.php
delete mode 100755 database/migrations/2023_03_20_112411_add_event_column_to_activity_log_table.php
delete mode 100755 database/migrations/2023_03_20_112412_add_batch_uuid_column_to_activity_log_table.php
delete mode 100644 database/migrations/2023_03_20_112809_create_sessions_table.php
delete mode 100644 database/migrations/2023_03_20_112811_create_teams_table.php
delete mode 100644 database/migrations/2023_03_20_112812_create_team_user_table.php
delete mode 100644 database/migrations/2023_03_20_112813_create_team_invitations_table.php
delete mode 100644 database/migrations/2023_03_20_112814_create_instance_settings_table.php
delete mode 100644 database/migrations/2023_03_24_140711_create_servers_table.php
delete mode 100644 database/migrations/2023_03_24_140712_create_server_settings_table.php
delete mode 100644 database/migrations/2023_03_24_140853_create_private_keys_table.php
delete mode 100644 database/migrations/2023_03_27_075351_create_projects_table.php
delete mode 100644 database/migrations/2023_03_27_075443_create_project_settings_table.php
delete mode 100644 database/migrations/2023_03_27_075444_create_environments_table.php
delete mode 100644 database/migrations/2023_03_27_081716_create_applications_table.php
delete mode 100644 database/migrations/2023_03_27_081717_create_application_settings_table.php
delete mode 100644 database/migrations/2023_03_27_081718_create_application_previews_table.php
delete mode 100644 database/migrations/2023_03_27_083621_create_services_table.php
delete mode 100644 database/migrations/2023_03_27_085020_create_standalone_dockers_table.php
delete mode 100644 database/migrations/2023_03_27_085022_create_swarm_dockers_table.php
delete mode 100644 database/migrations/2023_03_28_062150_create_kubernetes_table.php
delete mode 100644 database/migrations/2023_03_28_083723_create_github_apps_table.php
delete mode 100644 database/migrations/2023_03_28_083726_create_gitlab_apps_table.php
delete mode 100644 database/migrations/2023_04_03_111012_create_local_persistent_volumes_table.php
delete mode 100644 database/migrations/2023_05_04_194548_create_environment_variables_table.php
delete mode 100644 database/migrations/2023_05_17_104039_create_failed_jobs_table.php
delete mode 100644 database/migrations/2023_05_24_083426_create_application_deployment_queues_table.php
delete mode 100644 database/migrations/2023_06_22_131459_move_wildcard_to_server.php
delete mode 100644 database/migrations/2023_06_23_084605_remove_wildcard_domain_from_instancesettings.php
delete mode 100644 database/migrations/2023_06_23_110548_next_channel_updates.php
delete mode 100644 database/migrations/2023_06_23_114131_change_env_var_value_length.php
delete mode 100644 database/migrations/2023_06_23_114132_remove_default_redirect_from_instance_settings.php
delete mode 100644 database/migrations/2023_06_23_114133_use_application_deployment_queues_as_activity.php
delete mode 100644 database/migrations/2023_06_23_114134_add_disk_usage_percentage_to_servers.php
delete mode 100644 database/migrations/2023_07_13_115117_create_subscriptions_table.php
delete mode 100644 database/migrations/2023_07_13_120719_create_webhooks_table.php
delete mode 100644 database/migrations/2023_07_13_120721_add_license_to_instance_settings.php
delete mode 100644 database/migrations/2023_07_27_182013_smtp_discord_schemaless_to_normal.php
delete mode 100644 database/migrations/2023_08_06_142951_add_description_field_to_applications_table.php
delete mode 100644 database/migrations/2023_08_06_142952_remove_foreignId_environment_variables.php
delete mode 100644 database/migrations/2023_08_06_142954_add_readonly_localpersistentvolumes.php
delete mode 100644 database/migrations/2023_08_07_073651_create_s3_storages_table.php
delete mode 100644 database/migrations/2023_08_07_142950_create_standalone_postgresqls_table.php
delete mode 100644 database/migrations/2023_08_08_150103_create_scheduled_database_backups_table.php
delete mode 100644 database/migrations/2023_08_10_113306_create_scheduled_database_backup_executions_table.php
delete mode 100644 database/migrations/2023_08_10_201311_add_backup_notifications_to_teams.php
delete mode 100644 database/migrations/2023_08_11_190528_add_dockerfile_to_applications_table.php
delete mode 100644 database/migrations/2023_08_15_095902_create_waitlists_table.php
delete mode 100644 database/migrations/2023_08_15_111125_update_users_table.php
delete mode 100644 database/migrations/2023_08_15_111126_update_servers_add_unreachable_count_table.php
delete mode 100644 database/migrations/2023_08_22_071048_add_boarding_to_teams.php
delete mode 100644 database/migrations/2023_08_22_071049_update_webhooks_type.php
delete mode 100644 database/migrations/2023_08_22_071050_update_subscriptions_stripe.php
delete mode 100644 database/migrations/2023_08_22_071051_add_stripe_plan_to_subscriptions.php
delete mode 100644 database/migrations/2023_08_22_071052_add_resend_as_email.php
delete mode 100644 database/migrations/2023_08_22_071053_add_resend_as_email_to_teams.php
delete mode 100644 database/migrations/2023_08_22_071054_add_stripe_reasons.php
delete mode 100644 database/migrations/2023_08_22_071055_add_discord_notifications_to_teams.php
delete mode 100644 database/migrations/2023_08_22_071056_update_telegram_notifications.php
delete mode 100644 database/migrations/2023_08_22_071057_add_nixpkgsarchive_to_applications.php
delete mode 100644 database/migrations/2023_08_22_071058_add_nixpkgsarchive_to_applications_remove.php
delete mode 100644 database/migrations/2023_08_22_071059_add_stripe_trial_ended.php
delete mode 100644 database/migrations/2023_08_22_071060_change_invitation_link_length.php
delete mode 100644 database/migrations/2023_09_20_082541_update_services_table.php
delete mode 100644 database/migrations/2023_09_20_082733_create_service_databases_table.php
delete mode 100644 database/migrations/2023_09_20_082737_create_service_applications_table.php
delete mode 100644 database/migrations/2023_09_20_083549_update_environment_variables_table.php
delete mode 100644 database/migrations/2023_09_22_185356_create_local_file_volumes_table.php
delete mode 100644 database/migrations/2023_09_23_111808_update_servers_with_cloudflared.php
delete mode 100644 database/migrations/2023_09_23_111809_remove_destination_from_services_table.php
delete mode 100644 database/migrations/2023_09_23_111811_update_service_applications_table.php
delete mode 100644 database/migrations/2023_09_23_111812_update_service_databases_table.php
delete mode 100644 database/migrations/2023_09_23_111813_update_users_databases_table.php
delete mode 100644 database/migrations/2023_09_23_111814_update_local_file_volumes_table.php
delete mode 100644 database/migrations/2023_09_23_111815_add_healthcheck_disable_to_apps_table.php
delete mode 100644 database/migrations/2023_09_23_111816_add_destination_to_services_table.php
delete mode 100644 database/migrations/2023_09_23_111817_use_instance_email_settings_by_default.php
delete mode 100644 database/migrations/2023_09_23_111818_set_notifications_on_by_default.php
delete mode 100644 database/migrations/2023_09_23_111819_add_server_emails.php
delete mode 100644 database/migrations/2023_10_08_111819_add_server_unreachable_count.php
delete mode 100644 database/migrations/2023_10_10_100320_update_s3_storages_table.php
delete mode 100644 database/migrations/2023_10_10_113144_add_dockerfile_location_applications_table.php
delete mode 100644 database/migrations/2023_10_12_132430_create_standalone_redis_table.php
delete mode 100644 database/migrations/2023_10_12_132431_add_standalone_redis_to_environment_variables_table.php
delete mode 100644 database/migrations/2023_10_12_132432_add_database_selection_to_backups.php
delete mode 100644 database/migrations/2023_10_18_072519_add_custom_labels_applications_table.php
delete mode 100644 database/migrations/2023_10_19_101331_create_standalone_mongodbs_table.php
delete mode 100644 database/migrations/2023_10_19_101332_add_standalone_mongodb_to_environment_variables_table.php
delete mode 100644 database/migrations/2023_10_24_103548_create_standalone_mysqls_table.php
delete mode 100644 database/migrations/2023_10_24_120523_create_standalone_mariadbs_table.php
delete mode 100644 database/migrations/2023_10_24_120524_add_standalone_mysql_to_environment_variables_table.php
delete mode 100644 database/migrations/2023_10_24_124934_add_is_shown_once_to_environment_variables_table.php
delete mode 100644 database/migrations/2023_11_01_100437_add_restart_to_deployment_queue.php
delete mode 100644 database/migrations/2023_11_07_123731_add_target_build_dockerfile.php
delete mode 100644 database/migrations/2023_11_08_112815_add_custom_config_standalone_postgresql.php
delete mode 100644 database/migrations/2023_11_09_133332_add_public_port_to_service_databases.php
delete mode 100644 database/migrations/2023_11_12_180605_change_fqdn_to_longer_field.php
delete mode 100644 database/migrations/2023_11_13_133059_add_sponsorship_disable.php
delete mode 100644 database/migrations/2023_11_14_103450_add_manual_webhook_secret.php
delete mode 100644 database/migrations/2023_11_14_121416_add_git_type.php
delete mode 100644 database/migrations/2023_11_16_101819_add_high_disk_usage_notification.php
delete mode 100644 database/migrations/2023_11_16_220647_add_log_drains.php
delete mode 100644 database/migrations/2023_11_17_160437_add_drain_log_enable_by_service.php
delete mode 100644 database/migrations/2023_11_20_094628_add_gpu_settings.php
delete mode 100644 database/migrations/2023_11_21_121920_add_additional_destinations_to_apps.php
delete mode 100644 database/migrations/2023_11_24_080341_add_docker_compose_location.php
delete mode 100644 database/migrations/2023_11_28_143533_add_fields_to_swarm_dockers.php
delete mode 100644 database/migrations/2023_11_29_075937_change_swarm_properties.php
delete mode 100644 database/migrations/2023_12_01_091723_save_logs_view_settings.php
delete mode 100644 database/migrations/2023_12_01_095356_add_custom_fluentd_config_for_logdrains.php
delete mode 100644 database/migrations/2023_12_08_162228_add_soft_delete_services.php
delete mode 100644 database/migrations/2023_12_11_103611_add_realtime_connection_problem.php
delete mode 100644 database/migrations/2023_12_13_110214_add_soft_deletes.php
delete mode 100644 database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php
delete mode 100644 database/migrations/2023_12_18_093514_add_swarm_related_things.php
delete mode 100644 database/migrations/2023_12_19_124111_add_swarm_cluster_grouping.php
delete mode 100644 database/migrations/2023_12_30_134507_add_description_to_environments.php
delete mode 100644 database/migrations/2023_12_31_173041_create_scheduled_tasks_table.php
delete mode 100644 database/migrations/2024_01_01_231053_create_scheduled_task_executions_table.php
delete mode 100644 database/migrations/2024_01_02_113855_add_raw_compose_deployment.php
delete mode 100644 database/migrations/2024_01_12_123422_update_cpuset_limits.php
delete mode 100644 database/migrations/2024_01_15_084609_add_custom_dns_server.php
delete mode 100644 database/migrations/2024_01_16_115005_add_build_server_enable.php
delete mode 100644 database/migrations/2024_01_21_130328_add_docker_network_to_services.php
delete mode 100755 database/migrations/2024_01_23_095832_add_manual_webhook_secret_bitbucket.php
delete mode 100644 database/migrations/2024_01_23_113129_create_shared_environment_variables_table.php
delete mode 100644 database/migrations/2024_01_24_095449_add_concurrent_number_of_builds_per_server.php
delete mode 100644 database/migrations/2024_01_25_073212_add_server_id_to_queues.php
delete mode 100644 database/migrations/2024_01_27_164724_add_application_name_and_deployment_url_to_queue.php
delete mode 100644 database/migrations/2024_01_29_072322_change_env_variable_length.php
delete mode 100644 database/migrations/2024_01_29_145200_add_custom_docker_run_options.php
delete mode 100644 database/migrations/2024_02_01_111228_create_tags_table.php
delete mode 100644 database/migrations/2024_02_05_105215_add_destination_to_app_deployments.php
delete mode 100644 database/migrations/2024_02_06_132748_add_additional_destinations.php
delete mode 100644 database/migrations/2024_02_08_075523_add_post_deployment_to_applications.php
delete mode 100644 database/migrations/2024_02_08_112304_add_dynamic_timeout_for_deployments.php
delete mode 100644 database/migrations/2024_02_15_101921_add_consistent_application_container_name.php
delete mode 100644 database/migrations/2024_02_15_192025_add_is_gzip_enabled_to_services.php
delete mode 100644 database/migrations/2024_02_20_165045_add_permissions_to_github_app.php
delete mode 100644 database/migrations/2024_02_22_090900_add_only_this_server_deployment.php
delete mode 100644 database/migrations/2024_02_23_143119_add_custom_server_limits_to_teams_ultimate.php
delete mode 100644 database/migrations/2024_02_25_222150_add_server_force_disabled_field.php
delete mode 100644 database/migrations/2024_03_04_092244_add_gzip_enabled_and_stripprefix_settings.php
delete mode 100644 database/migrations/2024_03_07_115054_add_notifications_notification_disable.php
delete mode 100644 database/migrations/2024_03_08_180457_nullable_password.php
delete mode 100644 database/migrations/2024_03_11_150013_create_oauth_settings.php
delete mode 100644 database/migrations/2024_03_14_214402_add_multiline_envs.php
delete mode 100644 database/migrations/2024_03_18_101440_add_version_of_envs.php
delete mode 100644 database/migrations/2024_03_22_080914_remove_popup_notifications.php
delete mode 100644 database/migrations/2024_03_26_122110_remove_realtime_notifications.php
delete mode 100644 database/migrations/2024_03_28_114620_add_watch_paths_to_apps.php
delete mode 100644 database/migrations/2024_04_09_095517_make_custom_docker_commands_longer.php
delete mode 100644 database/migrations/2024_04_10_071920_create_standalone_keydbs_table.php
delete mode 100644 database/migrations/2024_04_10_082220_create_standalone_dragonflies_table.php
delete mode 100644 database/migrations/2024_04_10_091519_create_standalone_clickhouses_table.php
delete mode 100644 database/migrations/2024_04_10_124015_add_permission_local_file_volumes.php
delete mode 100644 database/migrations/2024_04_12_092337_add_config_hash_to_other_resources.php
delete mode 100644 database/migrations/2024_04_15_094703_add_literal_variables.php
delete mode 100644 database/migrations/2024_04_16_083919_add_service_type_on_creation.php
delete mode 100644 database/migrations/2024_04_17_132541_add_rollback_queues.php
delete mode 100644 database/migrations/2024_04_25_073615_add_docker_network_to_application_settings.php
delete mode 100644 database/migrations/2024_04_29_111956_add_custom_hc_indicator_apps.php
delete mode 100644 database/migrations/2024_05_06_093236_add_custom_name_to_application_settings.php
delete mode 100644 database/migrations/2024_05_07_124019_add_server_metrics.php
delete mode 100644 database/migrations/2024_05_10_085215_make_stripe_comment_longer.php
delete mode 100644 database/migrations/2024_05_15_091757_add_commit_message_to_app_deployment_queue.php
delete mode 100644 database/migrations/2024_05_15_151236_add_container_escape_toggle.php
delete mode 100644 database/migrations/2024_05_17_082012_add_env_sorting_toggle.php
delete mode 100644 database/migrations/2024_05_21_125739_add_scheduled_tasks_notification_to_teams.php
delete mode 100644 database/migrations/2024_05_22_103942_change_pre_post_deployment_commands_length_in_applications.php
delete mode 100644 database/migrations/2024_05_23_091713_add_gitea_webhook_to_applications.php
delete mode 100644 database/migrations/2024_06_05_101019_add_docker_compose_pr_domains.php
delete mode 100644 database/migrations/2024_06_06_103938_change_pr_issue_commend_id_type.php
delete mode 100644 database/migrations/2024_06_11_081614_add_www_non_www_redirect.php
delete mode 100644 database/migrations/2024_06_18_105948_move_server_metrics.php
delete mode 100644 database/migrations/2024_06_20_102551_add_server_api_sentinel.php
delete mode 100644 database/migrations/2024_06_21_143358_add_api_deployment_type.php
delete mode 100644 database/migrations/2024_06_22_081140_alter_instance_settings_add_instance_name.php
delete mode 100644 database/migrations/2024_06_25_184323_update_db.php
delete mode 100644 database/migrations/2024_07_01_115528_add_is_api_allowed_and_iplist.php
delete mode 100644 database/migrations/2024_07_05_120217_remove_unique_from_tag_names.php
delete mode 100644 database/migrations/2024_07_11_083719_application_compose_versions.php
delete mode 100644 database/migrations/2024_07_17_123828_add_is_container_labels_readonly.php
delete mode 100644 database/migrations/2024_07_18_110424_create_application_settings_is_preserve_repository_enabled.php
delete mode 100644 database/migrations/2024_07_18_123458_add_force_cleanup_server.php
delete mode 100644 database/migrations/2024_07_19_132617_disable_healtcheck_by_default.php
delete mode 100644 database/migrations/2024_07_23_112710_add_validation_logs_to_servers.php
delete mode 100644 database/migrations/2024_08_05_142659_add_update_frequency_settings.php
delete mode 100644 database/migrations/2024_08_07_155324_add_proxy_label_chooser.php
delete mode 100644 database/migrations/2024_08_09_215659_add_server_cleanup_fields_to_server_settings_table.php
delete mode 100644 database/migrations/2024_08_12_131659_add_local_file_volume_based_on_git.php
delete mode 100644 database/migrations/2024_08_12_155023_add_timezone_to_server_and_instance_settings.php
delete mode 100644 database/migrations/2024_08_14_183120_add_order_to_environment_variables_table.php
delete mode 100644 database/migrations/2024_08_15_115907_add_build_server_id_to_deployment_queue.php
delete mode 100644 database/migrations/2024_08_16_105649_add_custom_docker_options_to_dbs.php
delete mode 100644 database/migrations/2024_08_27_090528_add_compose_parsing_version_to_services.php
delete mode 100644 database/migrations/2024_09_05_085700_add_helper_version_to_instance_settings.php
delete mode 100644 database/migrations/2024_09_06_062534_change_server_cleanup_to_forced.php
delete mode 100644 database/migrations/2024_09_07_185402_change_cleanup_schedule.php
delete mode 100644 database/migrations/2024_09_08_130756_update_server_settings_default_timezone.php
delete mode 100644 database/migrations/2024_09_16_111428_encrypt_existing_private_keys.php
delete mode 100644 database/migrations/2024_09_17_111226_add_ssh_key_fingerprint_to_private_keys_table.php
delete mode 100644 database/migrations/2024_09_22_165240_add_advanced_options_to_cleanup_options_to_servers_settings_table.php
delete mode 100644 database/migrations/2024_09_26_083441_disable_api_by_default.php
delete mode 100644 database/migrations/2024_10_03_095427_add_dump_all_to_standalone_postgresqls.php
delete mode 100644 database/migrations/2024_10_10_081444_remove_constraint_from_service_applications_fqdn.php
delete mode 100644 database/migrations/2024_10_11_114331_add_required_env_variables.php
delete mode 100644 database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php
delete mode 100644 database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php
delete mode 100644 database/migrations/2024_10_16_120026_move_redis_password_to_envs.php
delete mode 100644 database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php
delete mode 100644 database/migrations/2024_10_17_093722_add_soft_delete_to_servers.php
delete mode 100644 database/migrations/2024_10_22_105745_add_server_disk_usage_threshold.php
delete mode 100644 database/migrations/2024_10_22_121223_add_server_disk_usage_notification.php
delete mode 100644 database/migrations/2024_10_29_093927_add_is_sentinel_debug_enabled_to_server_settings.php
delete mode 100644 database/migrations/2024_10_30_074601_rename_token_permissions.php
delete mode 100644 database/migrations/2024_11_02_213214_add_last_online_at_to_resources.php
delete mode 100644 database/migrations/2024_11_11_125335_add_custom_nginx_configuration_to_static.php
delete mode 100644 database/migrations/2024_11_11_125366_add_index_to_activity_log.php
delete mode 100644 database/migrations/2024_11_22_124742_add_uuid_to_environments_table.php
delete mode 100644 database/migrations/2024_12_05_091823_add_disable_build_cache_advanced_option.php
delete mode 100644 database/migrations/2024_12_05_212355_create_email_notification_settings_table.php
delete mode 100644 database/migrations/2024_12_05_212416_create_discord_notification_settings_table.php
delete mode 100644 database/migrations/2024_12_05_212440_create_telegram_notification_settings_table.php
delete mode 100644 database/migrations/2024_12_05_212546_migrate_email_notification_settings_from_teams_table.php
delete mode 100644 database/migrations/2024_12_05_212631_migrate_discord_notification_settings_from_teams_table.php
delete mode 100644 database/migrations/2024_12_05_212705_migrate_telegram_notification_settings_from_teams_table.php
delete mode 100644 database/migrations/2024_12_06_142014_create_slack_notification_settings_table.php
delete mode 100644 database/migrations/2024_12_09_105711_drop_waitlists_table.php
delete mode 100644 database/migrations/2024_12_10_122142_encrypt_instance_settings_email_columns.php
delete mode 100644 database/migrations/2024_12_10_122143_drop_resale_license.php
delete mode 100644 database/migrations/2024_12_11_135026_create_pushover_notification_settings_table.php
delete mode 100644 database/migrations/2024_12_11_161418_add_authentik_base_url_to_oauth_settings_table.php
delete mode 100644 database/migrations/2024_12_13_103007_encrypt_resend_api_key_in_instance_settings.php
delete mode 100644 database/migrations/2024_12_16_134437_add_resourceable_columns_to_environment_variables_table.php
delete mode 100644 database/migrations/2024_12_17_140637_add_server_disk_usage_check_frequency_to_server_settings_table.php
delete mode 100644 database/migrations/2024_12_23_142402_update_email_encryption_values.php
delete mode 100644 database/migrations/2025_01_08_154008_switch_up_readonly_labels.php
delete mode 100644 database/migrations/2025_01_10_135244_add_horizon_job_details_to_queue.php
delete mode 100644 database/migrations/2025_01_13_130238_add_backup_retention_fields_to_scheduled_database_backups_table.php
delete mode 100644 database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php
delete mode 100644 database/migrations/2025_01_16_110406_change_commit_message_to_text_in_application_deployment_queues.php
delete mode 100644 database/migrations/2025_01_16_130238_add_finished_at_to_executions_tables.php
delete mode 100644 database/migrations/2025_01_21_125205_update_finished_at_timestamps_if_not_set.php
delete mode 100644 database/migrations/2025_01_22_101105_remove_wrongly_created_envs.php
delete mode 100644 database/migrations/2025_02_27_125249_add_index_to_scheduled_task_executions.php
delete mode 100644 database/migrations/2025_03_01_112617_add_stripe_past_due.php
delete mode 100644 database/migrations/2025_03_14_140150_add_storage_deletion_tracking_to_backup_executions.php
delete mode 100644 database/seeders/ApplicationSeeder.php
delete mode 100644 database/seeders/ApplicationSettingsSeeder.php
delete mode 100644 database/seeders/DatabaseSeeder.php
delete mode 100644 database/seeders/DisableTwoStepConfirmationSeeder.php
delete mode 100644 database/seeders/GithubAppSeeder.php
delete mode 100644 database/seeders/GitlabAppSeeder.php
delete mode 100644 database/seeders/InstanceSettingsSeeder.php
delete mode 100644 database/seeders/LocalPersistentVolumeSeeder.php
delete mode 100644 database/seeders/OauthSettingSeeder.php
delete mode 100644 database/seeders/PopulateSshKeysDirectorySeeder.php
delete mode 100644 database/seeders/PrivateKeySeeder.php
delete mode 100644 database/seeders/ProductionSeeder.php
delete mode 100644 database/seeders/ProjectSeeder.php
delete mode 100644 database/seeders/RootUserSeeder.php
delete mode 100644 database/seeders/S3StorageSeeder.php
delete mode 100644 database/seeders/SentinelSeeder.php
delete mode 100644 database/seeders/ServerSeeder.php
delete mode 100644 database/seeders/ServerSettingSeeder.php
delete mode 100644 database/seeders/SharedEnvironmentVariableSeeder.php
delete mode 100644 database/seeders/StandaloneDockerSeeder.php
delete mode 100644 database/seeders/StandalonePostgresqlSeeder.php
delete mode 100644 database/seeders/StandaloneRedisSeeder.php
delete mode 100644 database/seeders/TeamSeeder.php
delete mode 100644 database/seeders/UserSeeder.php
delete mode 100644 docker-compose.dev.yml
delete mode 100644 docker-compose.prod.yml
delete mode 100644 docker-compose.windows.yml
delete mode 100644 docker-compose.yml
delete mode 100644 docker/coolify-helper/Dockerfile
delete mode 100644 docker/coolify-realtime/Dockerfile
delete mode 100644 docker/coolify-realtime/package-lock.json
delete mode 100644 docker/coolify-realtime/package.json
delete mode 100644 docker/coolify-realtime/soketi-entrypoint.sh
delete mode 100755 docker/coolify-realtime/terminal-server.js
delete mode 100644 docker/development/Dockerfile
delete mode 100644 docker/development/etc/nginx/conf.d/custom.conf
delete mode 100644 docker/development/etc/nginx/site-opts.d/http.conf
delete mode 100644 docker/development/etc/php/conf.d/zzz-custom-php.ini
delete mode 100644 docker/development/etc/s6-overlay/s6-rc.d/horizon/run
delete mode 100644 docker/development/etc/s6-overlay/s6-rc.d/horizon/type
delete mode 100644 docker/development/etc/s6-overlay/s6-rc.d/init-setup/type
delete mode 100644 docker/development/etc/s6-overlay/s6-rc.d/init-setup/up
delete mode 100644 docker/development/etc/s6-overlay/s6-rc.d/scheduler-worker/dependencies.d/init-setup
delete mode 100644 docker/development/etc/s6-overlay/s6-rc.d/scheduler-worker/run
delete mode 100644 docker/development/etc/s6-overlay/s6-rc.d/scheduler-worker/type
delete mode 100644 docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/horizon
delete mode 100644 docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/init-setup
delete mode 100644 docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/scheduler-worker
delete mode 100644 docker/production/Dockerfile
delete mode 100644 docker/production/entrypoint.d/99-debug-mode.sh
delete mode 100644 docker/production/etc/nginx/conf.d/custom.conf
delete mode 100644 docker/production/etc/nginx/site-opts.d/http.conf
delete mode 100644 docker/production/etc/php/conf.d/zzz-custom-php.ini
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/db-migration/type
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/db-migration/up
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/horizon/dependencies.d/init-script
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/horizon/run
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/horizon/type
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/init-script/dependencies.d/init-seeder
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/init-script/type
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/init-script/up
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/init-seeder/dependencies.d/db-migration
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/init-seeder/type
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/init-seeder/up
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/scheduler-worker/dependencies.d/init-script
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/scheduler-worker/run
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/scheduler-worker/type
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/db-migration
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/horizon
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/init-script
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/init-seeder
delete mode 100644 docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/scheduler-worker
delete mode 100644 docker/testing-host/Dockerfile
delete mode 100644 hooks/pre-commit
delete mode 100644 lang/ar.json
delete mode 100644 lang/cs.json
delete mode 100644 lang/de.json
delete mode 100644 lang/en.json
delete mode 100644 lang/es.json
delete mode 100644 lang/fa.json
delete mode 100644 lang/fr.json
delete mode 100644 lang/it.json
delete mode 100644 lang/ja.json
delete mode 100644 lang/pt.json
delete mode 100644 lang/ro.json
delete mode 100644 lang/tr.json
delete mode 100644 lang/vi.json
delete mode 100644 lang/zh-cn.json
delete mode 100644 lang/zh-tw.json
delete mode 100644 openapi.json
delete mode 100644 openapi.yaml
delete mode 100644 other/logos/advin.png
delete mode 100644 other/logos/appwrite.svg
delete mode 100644 other/logos/arcjet.svg
delete mode 100644 other/logos/bc.png
delete mode 100644 other/logos/blacksmith.svg
delete mode 100644 other/logos/branddev.png
delete mode 100644 other/logos/ccc-logo.webp
delete mode 100644 other/logos/codext.jpg
delete mode 100644 other/logos/fractal.png
delete mode 100644 other/logos/fractal.svg
delete mode 100644 other/logos/glueops.webp
delete mode 100644 other/logos/hetzner.jpg
delete mode 100644 other/logos/hostinger.svg
delete mode 100644 other/logos/internetgarden.ico
delete mode 100644 other/logos/jobscollider.svg
delete mode 100644 other/logos/juxtdigital.png
delete mode 100644 other/logos/latitude.svg
delete mode 100644 other/logos/logto.webp
delete mode 100644 other/logos/massivegrid.svg
delete mode 100644 other/logos/quant.svg
delete mode 100644 other/logos/saasykit.png
delete mode 100644 other/logos/saasykit.webp
delete mode 100644 other/logos/supaguide.png
delete mode 100644 other/logos/tigris.svg
delete mode 100644 other/logos/trieve_bg.png
delete mode 100644 other/logos/ubicloud.svg
delete mode 100644 other/nightly/.env.production
delete mode 100644 other/nightly/docker-compose.prod.yml
delete mode 100644 other/nightly/docker-compose.windows.yml
delete mode 100644 other/nightly/docker-compose.yml
delete mode 100755 other/nightly/install.sh
delete mode 100644 other/nightly/upgrade.sh
delete mode 100644 other/nightly/versions.json
delete mode 100644 package-lock.json
delete mode 100644 phpunit.dusk.xml
delete mode 100644 pint.json
delete mode 100644 postcss.config.cjs
delete mode 100644 public/coolify-logo-dev-transparent.png
delete mode 100644 public/coolify-logo.svg
delete mode 100644 public/coolify-transparent.png
rename docker/development/etc/s6-overlay/s6-rc.d/horizon/dependencies.d/init-setup => public/favicon.ico (100%)
delete mode 100644 public/js/apexcharts.js
delete mode 100644 public/js/dropzone.js
delete mode 100644 public/js/echo.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/base/browser/ui/codicons/codicon/codicon.ttf
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/base/worker/workerMain.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/abap/abap.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/apex/apex.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/azcli/azcli.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/bat/bat.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/bicep/bicep.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/cameligo/cameligo.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/clojure/clojure.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/coffee/coffee.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/cpp/cpp.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/csharp/csharp.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/csp/csp.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/css/css.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/cypher/cypher.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/dart/dart.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/dockerfile/dockerfile.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/ecl/ecl.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/elixir/elixir.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/flow9/flow9.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/freemarker2/freemarker2.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/fsharp/fsharp.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/go/go.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/graphql/graphql.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/handlebars/handlebars.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/hcl/hcl.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/html/html.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/ini/ini.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/java/java.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/javascript/javascript.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/julia/julia.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/kotlin/kotlin.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/less/less.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/lexon/lexon.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/liquid/liquid.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/lua/lua.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/m3/m3.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/markdown/markdown.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/mdx/mdx.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/mips/mips.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/msdax/msdax.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/mysql/mysql.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/objective-c/objective-c.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/pascal/pascal.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/pascaligo/pascaligo.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/perl/perl.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/pgsql/pgsql.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/php/php.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/pla/pla.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/postiats/postiats.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/powerquery/powerquery.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/powershell/powershell.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/protobuf/protobuf.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/pug/pug.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/python/python.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/qsharp/qsharp.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/r/r.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/razor/razor.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/redis/redis.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/redshift/redshift.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/restructuredtext/restructuredtext.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/ruby/ruby.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/rust/rust.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/sb/sb.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/scala/scala.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/scheme/scheme.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/scss/scss.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/shell/shell.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/solidity/solidity.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/sophia/sophia.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/sparql/sparql.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/sql/sql.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/st/st.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/swift/swift.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/systemverilog/systemverilog.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/tcl/tcl.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/twig/twig.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/typescript/typescript.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/typespec/typespec.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/vb/vb.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/wgsl/wgsl.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/xml/xml.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/basic-languages/yaml/yaml.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/editor/editor.main.css
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/editor/editor.main.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/language/css/cssMode.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/language/css/cssWorker.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/language/html/htmlMode.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/language/html/htmlWorker.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/language/json/jsonMode.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/language/json/jsonWorker.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/language/typescript/tsMode.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/language/typescript/tsWorker.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/loader.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/nls.messages.de.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/nls.messages.es.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/nls.messages.fr.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/nls.messages.it.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/nls.messages.ja.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/nls.messages.ko.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/nls.messages.ru.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/nls.messages.zh-cn.js
delete mode 100644 public/js/monaco-editor-0.52.2/min/vs/nls.messages.zh-tw.js
delete mode 100644 public/js/pusher.js
delete mode 100644 public/svgs/activepieces.png
delete mode 100644 public/svgs/actualbudget.png
delete mode 100644 public/svgs/affine.svg
delete mode 100644 public/svgs/anythingllm.svg
delete mode 100644 public/svgs/apprise.png
delete mode 100644 public/svgs/appsmith.svg
delete mode 100644 public/svgs/appwrite.svg
delete mode 100644 public/svgs/argilla.png
delete mode 100644 public/svgs/audiobookshelf.svg
delete mode 100644 public/svgs/authentik.png
delete mode 100644 public/svgs/azimutt.png
delete mode 100644 public/svgs/babybuddy.png
delete mode 100644 public/svgs/beszel.svg
delete mode 100644 public/svgs/bitcoin.svg
delete mode 100644 public/svgs/bitwarden.svg
delete mode 100644 public/svgs/bookstack.png
delete mode 100644 public/svgs/browserless.svg
delete mode 100644 public/svgs/budge.png
delete mode 100644 public/svgs/budibase.svg
delete mode 100644 public/svgs/bugsink.svg
delete mode 100644 public/svgs/calcom.svg
delete mode 100644 public/svgs/calibre-web.svg
delete mode 100644 public/svgs/castopod.svg
delete mode 100644 public/svgs/changedetection.png
delete mode 100644 public/svgs/chaskiq.png
delete mode 100644 public/svgs/chatwoot.svg
delete mode 100644 public/svgs/checkmate.png
delete mode 100644 public/svgs/classicpress.svg
delete mode 100644 public/svgs/clickhouse.svg
delete mode 100644 public/svgs/cloudbeaver.svg
delete mode 100644 public/svgs/cloudflared.svg
delete mode 100755 public/svgs/cockpit.svg
delete mode 100644 public/svgs/code-server.svg
delete mode 100644 public/svgs/coder.svg
delete mode 100644 public/svgs/convertx.png
delete mode 100644 public/svgs/convex.svg
delete mode 100644 public/svgs/coolify.png
delete mode 100644 public/svgs/cryptgeon.png
delete mode 100644 public/svgs/cyberchef.jpeg
delete mode 100644 public/svgs/dashy.png
delete mode 100644 public/svgs/default.webp
delete mode 100644 public/svgs/denoKV.svg
delete mode 100644 public/svgs/dify.png
delete mode 100644 public/svgs/directus.svg
delete mode 100644 public/svgs/docker-registry.png
delete mode 100644 public/svgs/docker.svg
delete mode 100644 public/svgs/docmost.png
delete mode 100644 public/svgs/documenso.png
delete mode 100644 public/svgs/docuseal.png
delete mode 100644 public/svgs/dokuwiki.png
delete mode 100644 public/svgs/dolibarr.png
delete mode 100644 public/svgs/dozzle.svg
delete mode 100644 public/svgs/drupal.svg
delete mode 100644 public/svgs/duplicati.webp
delete mode 100644 public/svgs/easyappointments.png
delete mode 100644 public/svgs/edgedb.svg
delete mode 100644 public/svgs/emby.png
delete mode 100644 public/svgs/external-link.svg
delete mode 100644 public/svgs/faraday.png
delete mode 100644 public/svgs/fider.svg
delete mode 100644 public/svgs/filebrowser.svg
delete mode 100644 public/svgs/fileflows.svg
delete mode 100644 public/svgs/firefly.svg
delete mode 100644 public/svgs/firefox.svg
delete mode 100644 public/svgs/flipt.svg
delete mode 100644 public/svgs/flowise.png
delete mode 100644 public/svgs/forgejo.svg
delete mode 100644 public/svgs/formbricks.png
delete mode 100644 public/svgs/foundryvtt.png
delete mode 100644 public/svgs/freshrss.png
delete mode 100644 public/svgs/getoutline.jpeg
delete mode 100644 public/svgs/ghost.svg
delete mode 100644 public/svgs/git.svg
delete mode 100644 public/svgs/gitea.svg
delete mode 100644 public/svgs/github.svg
delete mode 100644 public/svgs/gitlab.svg
delete mode 100644 public/svgs/glance.png
delete mode 100644 public/svgs/glances.png
delete mode 100644 public/svgs/glitchtip.png
delete mode 100644 public/svgs/gotenberg.png
delete mode 100644 public/svgs/grafana.svg
delete mode 100644 public/svgs/grocy.svg
delete mode 100644 public/svgs/heimdall.svg
delete mode 100644 public/svgs/heyform.svg
delete mode 100644 public/svgs/hoarder.svg
delete mode 100644 public/svgs/homarr.svg
delete mode 100644 public/svgs/homepage.png
delete mode 100644 public/svgs/hoppscotch.png
delete mode 100644 public/svgs/immich.svg
delete mode 100644 public/svgs/infisical.png
delete mode 100644 public/svgs/internal-link.svg
delete mode 100644 public/svgs/invoiceninja.png
delete mode 100644 public/svgs/it-tools.svg
delete mode 100644 public/svgs/jellyfin.svg
delete mode 100644 public/svgs/jenkins.svg
delete mode 100644 public/svgs/jitsi.svg
delete mode 100644 public/svgs/joomla.svg
delete mode 100644 public/svgs/joplin.png
delete mode 100644 public/svgs/jupyter.svg
delete mode 100644 public/svgs/keycloak.svg
delete mode 100644 public/svgs/kimai.svg
delete mode 100644 public/svgs/kuzzle.png
delete mode 100644 public/svgs/labelstudio.png
delete mode 100644 public/svgs/langfuse.png
delete mode 100644 public/svgs/libreoffice.svg
delete mode 100644 public/svgs/libretranslate.svg
delete mode 100644 public/svgs/listmonk.svg
delete mode 100644 public/svgs/litellm.svg
delete mode 100644 public/svgs/litequeen.svg
delete mode 100644 public/svgs/logto_dark.svg
delete mode 100644 public/svgs/lowcoder.svg
delete mode 100644 public/svgs/macos.svg
delete mode 100644 public/svgs/mailpit.svg
delete mode 100644 public/svgs/mariadb.svg
delete mode 100644 public/svgs/martin.png
delete mode 100644 public/svgs/mattermost.svg
delete mode 100644 public/svgs/mautic.svg
delete mode 100644 public/svgs/maybe.svg
delete mode 100644 public/svgs/mealie.png
delete mode 100644 public/svgs/mediawiki.ico
delete mode 100644 public/svgs/meilisearch.svg
delete mode 100644 public/svgs/metabase.svg
delete mode 100644 public/svgs/mindsdb.svg
delete mode 100644 public/svgs/minecraft.svg
delete mode 100644 public/svgs/minio.svg
delete mode 100644 public/svgs/mixpost.svg
delete mode 100644 public/svgs/mongodb.svg
delete mode 100644 public/svgs/moodle.png
delete mode 100644 public/svgs/mosquitto.svg
delete mode 100644 public/svgs/mysql.svg
delete mode 100644 public/svgs/n8n.png
delete mode 100644 public/svgs/nextcloud.svg
delete mode 100644 public/svgs/nexus.png
delete mode 100644 public/svgs/nitropage.svg
delete mode 100644 public/svgs/nocodb.svg
delete mode 100644 public/svgs/nodebb.svg
delete mode 100644 public/svgs/ntfy.svg
delete mode 100644 public/svgs/odoo.svg
delete mode 100644 public/svgs/ollama.svg
delete mode 100644 public/svgs/onedev.svg
delete mode 100644 public/svgs/openwebui.svg
delete mode 100644 public/svgs/organizr.png
delete mode 100644 public/svgs/osticket.png
delete mode 100644 public/svgs/overseerr.svg
delete mode 100644 public/svgs/owncloud.svg
delete mode 100644 public/svgs/pairdrop.png
delete mode 100644 public/svgs/paperless.svg
delete mode 100644 public/svgs/penpot.svg
delete mode 100644 public/svgs/peppermint.png
delete mode 100644 public/svgs/phpmyadmin.svg
delete mode 100644 public/svgs/plane.svg
delete mode 100644 public/svgs/plex.svg
delete mode 100644 public/svgs/plunk.svg
delete mode 100644 public/svgs/pocketbase.svg
delete mode 100644 public/svgs/portainer.png
delete mode 100644 public/svgs/postgres.svg
delete mode 100644 public/svgs/postgresql.svg
delete mode 100644 public/svgs/posthog.svg
delete mode 100644 public/svgs/postiz.svg
delete mode 100644 public/svgs/prefect.png
delete mode 100644 public/svgs/privatebin.svg
delete mode 100644 public/svgs/prowlarr.svg
delete mode 100644 public/svgs/pterodactyl.png
delete mode 100644 public/svgs/qbittorrent.svg
delete mode 100644 public/svgs/qdrant.png
delete mode 100644 public/svgs/rabbitmq.svg
delete mode 100644 public/svgs/radarr.svg
delete mode 100644 public/svgs/rallly.svg
delete mode 100644 public/svgs/readeck.svg
delete mode 100644 public/svgs/redis.svg
delete mode 100644 public/svgs/redlib.svg
delete mode 100644 public/svgs/rocketchat.svg
delete mode 100644 public/svgs/rxresume.svg
delete mode 100644 public/svgs/searxng.svg
delete mode 100644 public/svgs/soketi.jpeg
delete mode 100644 public/svgs/sonarr.svg
delete mode 100644 public/svgs/statusnook.svg
delete mode 100644 public/svgs/stirling.png
delete mode 100644 public/svgs/strapi.svg
delete mode 100644 public/svgs/supabase.svg
delete mode 100644 public/svgs/supertokens.svg
delete mode 100644 public/svgs/syncthing.svg
delete mode 100644 public/svgs/teable.png
delete mode 100644 public/svgs/tolgee.svg
delete mode 100644 public/svgs/traccar.png
delete mode 100644 public/svgs/transmission.svg
delete mode 100644 public/svgs/trigger.avif
delete mode 100644 public/svgs/trigger.png
delete mode 100644 public/svgs/twenty.svg
delete mode 100644 public/svgs/umami.svg
delete mode 100644 public/svgs/unleash.svg
delete mode 100644 public/svgs/unsend.svg
delete mode 100644 public/svgs/unstructured.png
delete mode 100644 public/svgs/uptime-kuma.svg
delete mode 100644 public/svgs/vikunja.svg
delete mode 100644 public/svgs/vvveb.svg
delete mode 100644 public/svgs/wakapi.svg
delete mode 100644 public/svgs/weaviate.png
delete mode 100644 public/svgs/web-check.png
delete mode 100644 public/svgs/weblate.webp
delete mode 100644 public/svgs/whoogle-search.png
delete mode 100644 public/svgs/whoogle.png
delete mode 100644 public/svgs/wikijs.svg
delete mode 100644 public/svgs/windmill.svg
delete mode 100644 public/svgs/windows.svg
delete mode 100644 public/svgs/wireguard.svg
delete mode 100644 public/svgs/wordpress.svg
delete mode 100644 public/svgs/zep.png
delete mode 100644 public/svgs/zipline.png
delete mode 100644 public/vendor/horizon/app-dark.css
delete mode 100644 public/vendor/horizon/app.css
delete mode 100644 public/vendor/horizon/app.js
delete mode 100644 public/vendor/horizon/img/favicon.png
delete mode 100644 public/vendor/horizon/img/horizon.svg
delete mode 100644 public/vendor/horizon/img/sprite.svg
delete mode 100644 public/vendor/horizon/mix-manifest.json
delete mode 100644 public/vendor/telescope/app-dark.css
delete mode 100644 public/vendor/telescope/app.css
delete mode 100644 public/vendor/telescope/app.js
delete mode 100644 public/vendor/telescope/favicon.ico
delete mode 100644 public/vendor/telescope/mix-manifest.json
delete mode 100644 rector.php
delete mode 100644 resources/css/fonts.css
delete mode 100644 resources/fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-100.woff2
delete mode 100644 resources/fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-200.woff2
delete mode 100644 resources/fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-300.woff2
delete mode 100644 resources/fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-500.woff2
delete mode 100644 resources/fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-600.woff2
delete mode 100644 resources/fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-700.woff2
delete mode 100644 resources/fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-800.woff2
delete mode 100644 resources/fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-900.woff2
delete mode 100644 resources/fonts/inter-v13-cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese-regular.woff2
create mode 100644 resources/js/bootstrap.js
delete mode 100644 resources/js/components/MagicBar.vue
delete mode 100644 resources/js/terminal.js
delete mode 100644 resources/views/auth/confirm-password.blade.php
delete mode 100644 resources/views/auth/forgot-password.blade.php
delete mode 100644 resources/views/auth/login.blade.php
delete mode 100644 resources/views/auth/register.blade.php
delete mode 100644 resources/views/auth/reset-password.blade.php
delete mode 100644 resources/views/auth/two-factor-challenge.blade.php
delete mode 100644 resources/views/auth/verify-email.blade.php
delete mode 100644 resources/views/components/applications/advanced.blade.php
delete mode 100644 resources/views/components/applications/links.blade.php
delete mode 100644 resources/views/components/banner.blade.php
delete mode 100644 resources/views/components/boarding-step.blade.php
delete mode 100644 resources/views/components/chevron-down.blade.php
delete mode 100644 resources/views/components/confirm-modal.blade.php
delete mode 100644 resources/views/components/dropdown.blade.php
delete mode 100644 resources/views/components/emails/footer.blade.php
delete mode 100644 resources/views/components/emails/header.blade.php
delete mode 100644 resources/views/components/emails/layout.blade.php
delete mode 100644 resources/views/components/external-link.blade.php
delete mode 100644 resources/views/components/forms/button.blade.php
delete mode 100644 resources/views/components/forms/checkbox.blade.php
delete mode 100644 resources/views/components/forms/datalist.blade.php
delete mode 100644 resources/views/components/forms/input.blade.php
delete mode 100644 resources/views/components/forms/monaco-editor.blade.php
delete mode 100644 resources/views/components/forms/select.blade.php
delete mode 100644 resources/views/components/forms/textarea.blade.php
delete mode 100644 resources/views/components/git-icon.blade.php
delete mode 100644 resources/views/components/helper.blade.php
delete mode 100644 resources/views/components/highlighted.blade.php
delete mode 100644 resources/views/components/internal-link.blade.php
delete mode 100644 resources/views/components/layout-simple.blade.php
delete mode 100644 resources/views/components/layout.blade.php
delete mode 100644 resources/views/components/limit-reached.blade.php
delete mode 100644 resources/views/components/loading-on-button.blade.php
delete mode 100644 resources/views/components/loading.blade.php
delete mode 100644 resources/views/components/modal-confirmation.blade.php
delete mode 100644 resources/views/components/modal-input.blade.php
delete mode 100644 resources/views/components/modal.blade.php
delete mode 100644 resources/views/components/navbar.blade.php
delete mode 100644 resources/views/components/notification/navbar.blade.php
delete mode 100644 resources/views/components/page-loading.blade.php
delete mode 100644 resources/views/components/popup-small.blade.php
delete mode 100644 resources/views/components/popup.blade.php
delete mode 100644 resources/views/components/pricing-plans.blade.php
delete mode 100644 resources/views/components/resource-view.blade.php
delete mode 100644 resources/views/components/resources/breadcrumbs.blade.php
delete mode 100644 resources/views/components/security/navbar.blade.php
delete mode 100644 resources/views/components/server/navbar.blade.php
delete mode 100644 resources/views/components/server/sidebar-proxy.blade.php
delete mode 100644 resources/views/components/server/sidebar.blade.php
delete mode 100644 resources/views/components/services/advanced.blade.php
delete mode 100644 resources/views/components/services/links.blade.php
delete mode 100644 resources/views/components/settings/navbar.blade.php
delete mode 100644 resources/views/components/slide-over.blade.php
delete mode 100644 resources/views/components/status/degraded.blade.php
delete mode 100644 resources/views/components/status/index.blade.php
delete mode 100644 resources/views/components/status/restarting.blade.php
delete mode 100644 resources/views/components/status/running.blade.php
delete mode 100644 resources/views/components/status/services.blade.php
delete mode 100644 resources/views/components/status/stopped.blade.php
delete mode 100644 resources/views/components/team/navbar.blade.php
delete mode 100644 resources/views/components/toast.blade.php
delete mode 100644 resources/views/components/use-magic-bar.blade.php
delete mode 100644 resources/views/components/version.blade.php
delete mode 100644 resources/views/emails/application-deployment-failed.blade.php
delete mode 100644 resources/views/emails/application-deployment-success.blade.php
delete mode 100644 resources/views/emails/application-status-changes.blade.php
delete mode 100644 resources/views/emails/backup-failed.blade.php
delete mode 100644 resources/views/emails/backup-success.blade.php
delete mode 100644 resources/views/emails/before-trial-conversion.blade.php
delete mode 100644 resources/views/emails/container-restarted.blade.php
delete mode 100644 resources/views/emails/container-stopped.blade.php
delete mode 100644 resources/views/emails/daily-backup.blade.php
delete mode 100644 resources/views/emails/docker-cleanup-failed.blade.php
delete mode 100644 resources/views/emails/docker-cleanup-success.blade.php
delete mode 100644 resources/views/emails/email-verification.blade.php
delete mode 100644 resources/views/emails/help.blade.php
delete mode 100644 resources/views/emails/high-disk-usage.blade.php
delete mode 100644 resources/views/emails/invitation-link.blade.php
delete mode 100644 resources/views/emails/reset-password.blade.php
delete mode 100644 resources/views/emails/s3-connection-error.blade.php
delete mode 100644 resources/views/emails/scheduled-task-failed.blade.php
delete mode 100644 resources/views/emails/scheduled-task-success.blade.php
delete mode 100644 resources/views/emails/server-force-disabled.blade.php
delete mode 100644 resources/views/emails/server-force-enabled.blade.php
delete mode 100644 resources/views/emails/server-lost-connection.blade.php
delete mode 100644 resources/views/emails/server-revived.blade.php
delete mode 100644 resources/views/emails/subscription-invoice-failed.blade.php
delete mode 100644 resources/views/emails/test.blade.php
delete mode 100644 resources/views/emails/trial-ended.blade.php
delete mode 100644 resources/views/emails/trial-ends-soon.blade.php
delete mode 100644 resources/views/emails/updates.blade.php
delete mode 100644 resources/views/errors/400.blade.php
delete mode 100644 resources/views/errors/401.blade.php
delete mode 100644 resources/views/errors/402.blade.php
delete mode 100644 resources/views/errors/403.blade.php
delete mode 100644 resources/views/errors/404.blade.php
delete mode 100644 resources/views/errors/419.blade.php
delete mode 100644 resources/views/errors/429.blade.php
delete mode 100644 resources/views/errors/500.blade.php
delete mode 100644 resources/views/errors/503.blade.php
delete mode 100644 resources/views/layouts/app.blade.php
delete mode 100644 resources/views/layouts/base.blade.php
delete mode 100644 resources/views/layouts/boarding.blade.php
delete mode 100644 resources/views/layouts/simple.blade.php
delete mode 100644 resources/views/livewire/activity-monitor.blade.php
delete mode 100644 resources/views/livewire/admin/index.blade.php
delete mode 100644 resources/views/livewire/boarding/index.blade.php
delete mode 100644 resources/views/livewire/dashboard.blade.php
delete mode 100644 resources/views/livewire/destination/index.blade.php
delete mode 100644 resources/views/livewire/destination/new/docker.blade.php
delete mode 100644 resources/views/livewire/destination/show.blade.php
delete mode 100644 resources/views/livewire/force-password-reset.blade.php
delete mode 100644 resources/views/livewire/help.blade.php
delete mode 100644 resources/views/livewire/layout-popups.blade.php
delete mode 100644 resources/views/livewire/navbar-delete-team.blade.php
delete mode 100644 resources/views/livewire/new-activity-monitor.blade.php
delete mode 100644 resources/views/livewire/notifications/discord.blade.php
delete mode 100644 resources/views/livewire/notifications/email.blade.php
delete mode 100644 resources/views/livewire/notifications/pushover.blade.php
delete mode 100644 resources/views/livewire/notifications/slack.blade.php
delete mode 100644 resources/views/livewire/notifications/telegram.blade.php
delete mode 100644 resources/views/livewire/profile/index.blade.php
delete mode 100644 resources/views/livewire/project/add-empty.blade.php
delete mode 100644 resources/views/livewire/project/application/advanced.blade.php
delete mode 100644 resources/views/livewire/project/application/configuration.blade.php
delete mode 100644 resources/views/livewire/project/application/deployment-navbar.blade.php
delete mode 100644 resources/views/livewire/project/application/deployment/index.blade.php
delete mode 100644 resources/views/livewire/project/application/deployment/show.blade.php
delete mode 100644 resources/views/livewire/project/application/destination.blade.php
delete mode 100644 resources/views/livewire/project/application/general.blade.php
delete mode 100644 resources/views/livewire/project/application/heading.blade.php
delete mode 100644 resources/views/livewire/project/application/preview/form.blade.php
delete mode 100644 resources/views/livewire/project/application/previews-compose.blade.php
delete mode 100644 resources/views/livewire/project/application/previews.blade.php
delete mode 100644 resources/views/livewire/project/application/rollback.blade.php
delete mode 100644 resources/views/livewire/project/application/source.blade.php
delete mode 100644 resources/views/livewire/project/application/swarm.blade.php
delete mode 100644 resources/views/livewire/project/clone-me.blade.php
delete mode 100644 resources/views/livewire/project/database/backup-edit.blade.php
delete mode 100644 resources/views/livewire/project/database/backup-executions.blade.php
delete mode 100644 resources/views/livewire/project/database/backup-now.blade.php
delete mode 100644 resources/views/livewire/project/database/backup/execution.blade.php
delete mode 100644 resources/views/livewire/project/database/backup/index.blade.php
delete mode 100644 resources/views/livewire/project/database/clickhouse/general.blade.php
delete mode 100644 resources/views/livewire/project/database/configuration.blade.php
delete mode 100644 resources/views/livewire/project/database/create-scheduled-backup.blade.php
delete mode 100644 resources/views/livewire/project/database/dragonfly/general.blade.php
delete mode 100644 resources/views/livewire/project/database/heading.blade.php
delete mode 100644 resources/views/livewire/project/database/import.blade.php
delete mode 100644 resources/views/livewire/project/database/init-script.blade.php
delete mode 100644 resources/views/livewire/project/database/keydb/general.blade.php
delete mode 100644 resources/views/livewire/project/database/mariadb/general.blade.php
delete mode 100644 resources/views/livewire/project/database/mongodb/general.blade.php
delete mode 100644 resources/views/livewire/project/database/mysql/general.blade.php
delete mode 100644 resources/views/livewire/project/database/postgresql/general.blade.php
delete mode 100644 resources/views/livewire/project/database/redis/general.blade.php
delete mode 100644 resources/views/livewire/project/database/scheduled-backups.blade.php
delete mode 100644 resources/views/livewire/project/delete-environment.blade.php
delete mode 100644 resources/views/livewire/project/delete-project.blade.php
delete mode 100644 resources/views/livewire/project/edit.blade.php
delete mode 100644 resources/views/livewire/project/environment-edit.blade.php
delete mode 100644 resources/views/livewire/project/index.blade.php
delete mode 100644 resources/views/livewire/project/new/docker-compose.blade.php
delete mode 100644 resources/views/livewire/project/new/docker-image.blade.php
delete mode 100644 resources/views/livewire/project/new/empty-project.blade.php
delete mode 100644 resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
delete mode 100644 resources/views/livewire/project/new/github-private-repository.blade.php
delete mode 100644 resources/views/livewire/project/new/public-git-repository.blade.php
delete mode 100644 resources/views/livewire/project/new/select.blade.php
delete mode 100644 resources/views/livewire/project/new/simple-dockerfile.blade.php
delete mode 100644 resources/views/livewire/project/resource/create.blade.php
delete mode 100644 resources/views/livewire/project/resource/environment-select.blade.php
delete mode 100644 resources/views/livewire/project/resource/index.blade.php
delete mode 100644 resources/views/livewire/project/service/configuration.blade.php
delete mode 100644 resources/views/livewire/project/service/database.blade.php
delete mode 100644 resources/views/livewire/project/service/edit-compose.blade.php
delete mode 100644 resources/views/livewire/project/service/edit-domain.blade.php
delete mode 100644 resources/views/livewire/project/service/file-storage.blade.php
delete mode 100644 resources/views/livewire/project/service/index.blade.php
delete mode 100644 resources/views/livewire/project/service/navbar.blade.php
delete mode 100644 resources/views/livewire/project/service/service-application-view.blade.php
delete mode 100644 resources/views/livewire/project/service/stack-form.blade.php
delete mode 100644 resources/views/livewire/project/service/storage.blade.php
delete mode 100644 resources/views/livewire/project/shared/configuration-checker.blade.php
delete mode 100644 resources/views/livewire/project/shared/danger.blade.php
delete mode 100644 resources/views/livewire/project/shared/destination.blade.php
delete mode 100644 resources/views/livewire/project/shared/environment-variable/add.blade.php
delete mode 100644 resources/views/livewire/project/shared/environment-variable/all.blade.php
delete mode 100644 resources/views/livewire/project/shared/environment-variable/show.blade.php
delete mode 100644 resources/views/livewire/project/shared/execute-container-command.blade.php
delete mode 100644 resources/views/livewire/project/shared/get-logs.blade.php
delete mode 100644 resources/views/livewire/project/shared/health-checks.blade.php
delete mode 100644 resources/views/livewire/project/shared/logs.blade.php
delete mode 100644 resources/views/livewire/project/shared/metrics.blade.php
delete mode 100644 resources/views/livewire/project/shared/resource-limits.blade.php
delete mode 100644 resources/views/livewire/project/shared/resource-operations.blade.php
delete mode 100644 resources/views/livewire/project/shared/scheduled-task/add.blade.php
delete mode 100644 resources/views/livewire/project/shared/scheduled-task/all.blade.php
delete mode 100644 resources/views/livewire/project/shared/scheduled-task/executions.blade.php
delete mode 100644 resources/views/livewire/project/shared/scheduled-task/show.blade.php
delete mode 100644 resources/views/livewire/project/shared/storages/add.blade.php
delete mode 100644 resources/views/livewire/project/shared/storages/all.blade.php
delete mode 100644 resources/views/livewire/project/shared/storages/show.blade.php
delete mode 100644 resources/views/livewire/project/shared/tags.blade.php
delete mode 100644 resources/views/livewire/project/shared/terminal.blade.php
delete mode 100644 resources/views/livewire/project/shared/upload-config.blade.php
delete mode 100644 resources/views/livewire/project/shared/webhooks.blade.php
delete mode 100644 resources/views/livewire/project/show.blade.php
delete mode 100644 resources/views/livewire/security/api-tokens.blade.php
delete mode 100644 resources/views/livewire/security/private-key/create.blade.php
delete mode 100644 resources/views/livewire/security/private-key/index.blade.php
delete mode 100644 resources/views/livewire/security/private-key/show.blade.php
delete mode 100644 resources/views/livewire/server/advanced.blade.php
delete mode 100644 resources/views/livewire/server/charts.blade.php
delete mode 100644 resources/views/livewire/server/cloudflare-tunnels.blade.php
delete mode 100644 resources/views/livewire/server/configure-cloudflare-tunnels.blade.php
delete mode 100644 resources/views/livewire/server/create.blade.php
delete mode 100644 resources/views/livewire/server/delete.blade.php
delete mode 100644 resources/views/livewire/server/destinations.blade.php
delete mode 100644 resources/views/livewire/server/docker-cleanup-executions.blade.php
delete mode 100644 resources/views/livewire/server/docker-cleanup.blade.php
delete mode 100644 resources/views/livewire/server/index.blade.php
delete mode 100644 resources/views/livewire/server/log-drains.blade.php
delete mode 100644 resources/views/livewire/server/new/by-ip.blade.php
delete mode 100644 resources/views/livewire/server/private-key/show.blade.php
delete mode 100644 resources/views/livewire/server/proxy.blade.php
delete mode 100644 resources/views/livewire/server/proxy/deploy.blade.php
delete mode 100644 resources/views/livewire/server/proxy/dynamic-configuration-navbar.blade.php
delete mode 100644 resources/views/livewire/server/proxy/dynamic-configurations.blade.php
delete mode 100644 resources/views/livewire/server/proxy/logs.blade.php
delete mode 100644 resources/views/livewire/server/proxy/new-dynamic-configuration.blade.php
delete mode 100644 resources/views/livewire/server/proxy/show.blade.php
delete mode 100644 resources/views/livewire/server/proxy/status.blade.php
delete mode 100644 resources/views/livewire/server/resources.blade.php
delete mode 100644 resources/views/livewire/server/show.blade.php
delete mode 100644 resources/views/livewire/server/validate-and-install.blade.php
delete mode 100644 resources/views/livewire/settings-backup.blade.php
delete mode 100644 resources/views/livewire/settings-email.blade.php
delete mode 100644 resources/views/livewire/settings-oauth.blade.php
delete mode 100644 resources/views/livewire/settings/index.blade.php
delete mode 100644 resources/views/livewire/shared-variables/environment/index.blade.php
delete mode 100644 resources/views/livewire/shared-variables/environment/show.blade.php
delete mode 100644 resources/views/livewire/shared-variables/index.blade.php
delete mode 100644 resources/views/livewire/shared-variables/project/index.blade.php
delete mode 100644 resources/views/livewire/shared-variables/project/show.blade.php
delete mode 100644 resources/views/livewire/shared-variables/team/index.blade.php
delete mode 100644 resources/views/livewire/source/github/change.blade.php
delete mode 100644 resources/views/livewire/source/github/create.blade.php
delete mode 100644 resources/views/livewire/source/gitlab/change.blade.php
delete mode 100644 resources/views/livewire/storage/create.blade.php
delete mode 100644 resources/views/livewire/storage/form.blade.php
delete mode 100644 resources/views/livewire/storage/index.blade.php
delete mode 100644 resources/views/livewire/storage/show.blade.php
delete mode 100644 resources/views/livewire/subscription/actions.blade.php
delete mode 100644 resources/views/livewire/subscription/index.blade.php
delete mode 100644 resources/views/livewire/subscription/pricing-plans.blade.php
delete mode 100644 resources/views/livewire/subscription/show.blade.php
delete mode 100644 resources/views/livewire/switch-team.blade.php
delete mode 100644 resources/views/livewire/tags/deployments.blade.php
delete mode 100644 resources/views/livewire/tags/show.blade.php
delete mode 100644 resources/views/livewire/team/admin-view.blade.php
delete mode 100644 resources/views/livewire/team/create.blade.php
delete mode 100644 resources/views/livewire/team/index.blade.php
delete mode 100644 resources/views/livewire/team/invitations.blade.php
delete mode 100644 resources/views/livewire/team/invite-link.blade.php
delete mode 100644 resources/views/livewire/team/member.blade.php
delete mode 100644 resources/views/livewire/team/member/index.blade.php
delete mode 100644 resources/views/livewire/terminal/index.blade.php
delete mode 100644 resources/views/livewire/upgrade.blade.php
delete mode 100644 resources/views/livewire/verify-email.blade.php
delete mode 100644 resources/views/security/index.blade.php
delete mode 100644 resources/views/server/create.blade.php
delete mode 100644 resources/views/source/all.blade.php
delete mode 100644 resources/views/source/github/show.blade.php
delete mode 100644 resources/views/source/gitlab/new.blade.php
delete mode 100644 resources/views/source/gitlab/show.blade.php
delete mode 100644 resources/views/vendor/mail/html/button.blade.php
delete mode 100644 resources/views/vendor/mail/html/footer.blade.php
delete mode 100644 resources/views/vendor/mail/html/header.blade.php
delete mode 100644 resources/views/vendor/mail/html/layout.blade.php
delete mode 100644 resources/views/vendor/mail/html/message.blade.php
delete mode 100644 resources/views/vendor/mail/html/panel.blade.php
delete mode 100644 resources/views/vendor/mail/html/subcopy.blade.php
delete mode 100644 resources/views/vendor/mail/html/table.blade.php
delete mode 100644 resources/views/vendor/mail/html/themes/default.css
delete mode 100644 resources/views/vendor/mail/text/button.blade.php
delete mode 100644 resources/views/vendor/mail/text/footer.blade.php
delete mode 100644 resources/views/vendor/mail/text/header.blade.php
delete mode 100644 resources/views/vendor/mail/text/layout.blade.php
delete mode 100644 resources/views/vendor/mail/text/message.blade.php
delete mode 100644 resources/views/vendor/mail/text/panel.blade.php
delete mode 100644 resources/views/vendor/mail/text/subcopy.blade.php
delete mode 100644 resources/views/vendor/mail/text/table.blade.php
delete mode 100644 routes/api.php
delete mode 100644 routes/channels.php
delete mode 100644 routes/console.php
delete mode 100644 routes/webhooks.php
delete mode 100644 scripts/cloud_upgrade.sh
delete mode 100644 scripts/install-1.6.sh
delete mode 100755 scripts/install-1.7.sh
delete mode 100755 scripts/install.sh
delete mode 100755 scripts/run
delete mode 100644 scripts/sync_volume.sh
delete mode 100644 scripts/upgrade.sh
rename storage/{debugbar => app/private}/.gitignore (100%)
rename storage/{pail => framework/cache/data}/.gitignore (100%)
delete mode 100644 tailwind.config.js
delete mode 100644 templates/compose/activepieces.yaml
delete mode 100644 templates/compose/actualbudget.yaml
delete mode 100644 templates/compose/affine.yaml
delete mode 100644 templates/compose/anythingllm.yaml
delete mode 100644 templates/compose/apprise-api.yaml
delete mode 100644 templates/compose/appsmith.yaml
delete mode 100644 templates/compose/appwrite.yaml
delete mode 100644 templates/compose/argilla.yaml
delete mode 100644 templates/compose/audiobookshelf.yaml
delete mode 100644 templates/compose/authentik.yaml
delete mode 100644 templates/compose/azimutt.yaml
delete mode 100644 templates/compose/babybuddy.yaml
delete mode 100644 templates/compose/beszel.yaml
delete mode 100644 templates/compose/bitcoin-core.yaml
delete mode 100644 templates/compose/bluesky-pds.yaml
delete mode 100644 templates/compose/bookstack.yaml
delete mode 100644 templates/compose/browserless.yaml
delete mode 100644 templates/compose/budge.yaml
delete mode 100644 templates/compose/budibase.yaml
delete mode 100644 templates/compose/bugsink.yaml
delete mode 100644 templates/compose/calcom.yaml
delete mode 100644 templates/compose/calibre-web.yaml
delete mode 100644 templates/compose/castopod.yaml
delete mode 100644 templates/compose/changedetection.yaml
delete mode 100644 templates/compose/chaskiq.yaml
delete mode 100644 templates/compose/chatwoot.yaml
delete mode 100644 templates/compose/checkmate.yaml
delete mode 100644 templates/compose/classicpress-with-mariadb.yaml
delete mode 100644 templates/compose/classicpress-with-mysql.yaml
delete mode 100644 templates/compose/classicpress-without-database.yaml
delete mode 100644 templates/compose/cloudbeaver.yaml
delete mode 100644 templates/compose/cloudflared.yaml
delete mode 100644 templates/compose/cockpit.yaml
delete mode 100644 templates/compose/code-server.yaml
delete mode 100644 templates/compose/coder.yaml
delete mode 100644 templates/compose/convertx.yml
delete mode 100644 templates/compose/convex.yaml
delete mode 100644 templates/compose/cryptgeon.yaml
delete mode 100644 templates/compose/cyberchef.yaml
delete mode 100644 templates/compose/dashy.yaml
delete mode 100644 templates/compose/denoKV.yaml
delete mode 100644 templates/compose/dify.yaml
delete mode 100644 templates/compose/directus-with-postgresql.yaml
delete mode 100644 templates/compose/directus.yaml
delete mode 100644 templates/compose/docker-registry.yaml
delete mode 100644 templates/compose/docmost.yaml
delete mode 100644 templates/compose/documenso.yaml
delete mode 100644 templates/compose/docuseal-with-postgres.yaml
delete mode 100644 templates/compose/docuseal.yaml
delete mode 100644 templates/compose/dokuwiki.yaml
delete mode 100644 templates/compose/dolibarr.yaml
delete mode 100644 templates/compose/dozzle-with-auth.yaml
delete mode 100644 templates/compose/dozzle.yaml
delete mode 100644 templates/compose/drupal-with-postgresql.yaml
delete mode 100644 templates/compose/duplicati.yaml
delete mode 100644 templates/compose/easyappointments.yaml
delete mode 100644 templates/compose/edgedb.yaml
delete mode 100644 templates/compose/emby.yaml
delete mode 100644 templates/compose/embystat.yaml
delete mode 100644 templates/compose/faraday.yaml
delete mode 100644 templates/compose/fider.yaml
delete mode 100644 templates/compose/filebrowser.yaml
delete mode 100644 templates/compose/fileflows.yaml
delete mode 100644 templates/compose/firefly.yaml
delete mode 100644 templates/compose/firefox.yaml
delete mode 100644 templates/compose/flipt.yaml
delete mode 100644 templates/compose/flowise-with-databases.yaml
delete mode 100644 templates/compose/flowise.yaml
delete mode 100644 templates/compose/forgejo-with-mariadb.yaml
delete mode 100644 templates/compose/forgejo-with-mysql.yaml
delete mode 100644 templates/compose/forgejo-with-postgresql.yaml
delete mode 100644 templates/compose/forgejo-with-runner-with-mariadb.yaml
delete mode 100644 templates/compose/forgejo-with-runner-with-mysql.yaml
delete mode 100644 templates/compose/forgejo-with-runner-with-postgresql.yaml
delete mode 100644 templates/compose/forgejo-with-runner.yaml
delete mode 100644 templates/compose/forgejo.yaml
delete mode 100644 templates/compose/formbricks.yaml
delete mode 100644 templates/compose/foundryvtt.yaml
delete mode 100644 templates/compose/freshrss-with-mariadb.yaml
delete mode 100644 templates/compose/freshrss-with-mysql.yaml
delete mode 100644 templates/compose/freshrss-with-postgresql.yaml
delete mode 100644 templates/compose/freshrss.yaml
delete mode 100644 templates/compose/getoutline.yaml
delete mode 100644 templates/compose/ghost.yaml
delete mode 100644 templates/compose/gitea-with-mariadb.yaml
delete mode 100644 templates/compose/gitea-with-mysql.yaml
delete mode 100644 templates/compose/gitea-with-postgresql.yaml
delete mode 100644 templates/compose/gitea.yaml
delete mode 100644 templates/compose/gitlab.yaml
delete mode 100644 templates/compose/glance.yaml
delete mode 100644 templates/compose/glances.yaml
delete mode 100644 templates/compose/glitchtip.yaml
delete mode 100644 templates/compose/gotenberg.yaml
delete mode 100644 templates/compose/grafana-with-postgresql.yaml
delete mode 100644 templates/compose/grafana.yaml
delete mode 100644 templates/compose/grocy.yaml
delete mode 100644 templates/compose/heimdall.yaml
delete mode 100644 templates/compose/heyform.yaml
delete mode 100644 templates/compose/hoarder.yaml
delete mode 100644 templates/compose/homarr.yaml
delete mode 100644 templates/compose/homepage.yaml
delete mode 100644 templates/compose/hoppscotch.yaml
delete mode 100644 templates/compose/huly.yaml
delete mode 100644 templates/compose/immich.yaml
delete mode 100644 templates/compose/infisical.yaml
delete mode 100644 templates/compose/invoice-ninja.yaml
delete mode 100644 templates/compose/it-tools.yaml
delete mode 100644 templates/compose/jellyfin.yaml
delete mode 100644 templates/compose/jenkins.yaml
delete mode 100644 templates/compose/jitsi.yaml
delete mode 100644 templates/compose/joomla-with-mariadb.yaml
delete mode 100644 templates/compose/joplin.yaml
delete mode 100644 templates/compose/jupyter-notebook-python.yaml
delete mode 100644 templates/compose/keycloak-with-postgres.yaml
delete mode 100644 templates/compose/keycloak.yaml
delete mode 100644 templates/compose/kimai.yaml
delete mode 100644 templates/compose/kuzzle.yaml
delete mode 100644 templates/compose/labelstudio.yaml
delete mode 100644 templates/compose/langfuse.yaml
delete mode 100644 templates/compose/libreoffice.yaml
delete mode 100644 templates/compose/libretranslate.yaml
delete mode 100644 templates/compose/listmonk.yaml
delete mode 100644 templates/compose/litellm.yaml
delete mode 100644 templates/compose/litequeen.yaml
delete mode 100644 templates/compose/logto.yaml
delete mode 100644 templates/compose/lowcoder.yaml
delete mode 100644 templates/compose/macos.yaml
delete mode 100644 templates/compose/mailpit.yaml
delete mode 100644 templates/compose/martin.yaml
delete mode 100644 templates/compose/mattermost.yaml
delete mode 100644 templates/compose/mautic5.yaml
delete mode 100644 templates/compose/maybe.yaml
delete mode 100644 templates/compose/mealie.yaml
delete mode 100644 templates/compose/mediawiki.yaml
delete mode 100644 templates/compose/meilisearch.yaml
delete mode 100644 templates/compose/metabase.yaml
delete mode 100644 templates/compose/metube.yaml
delete mode 100644 templates/compose/mindsdb.yaml
delete mode 100644 templates/compose/minecraft.yaml
delete mode 100644 templates/compose/minio.yaml
delete mode 100644 templates/compose/mixpost.yaml
delete mode 100644 templates/compose/moodle.yaml
delete mode 100644 templates/compose/mosquitto.yaml
delete mode 100644 templates/compose/n8n-with-postgresql.yaml
delete mode 100644 templates/compose/n8n.yaml
delete mode 100644 templates/compose/next-image-transformation.yaml
delete mode 100644 templates/compose/nextcloud-with-mariadb.yaml
delete mode 100644 templates/compose/nextcloud-with-mysql.yaml
delete mode 100644 templates/compose/nextcloud-with-postgres.yaml
delete mode 100644 templates/compose/nextcloud.yaml
delete mode 100644 templates/compose/nexus-arm.yaml
delete mode 100644 templates/compose/nexus.yaml
delete mode 100644 templates/compose/nitropage-with-postgresql.yaml
delete mode 100644 templates/compose/nitropage.yaml
delete mode 100644 templates/compose/nocodb.yaml
delete mode 100644 templates/compose/nodebb.yaml
delete mode 100644 templates/compose/ntfy.yaml
delete mode 100644 templates/compose/odoo.yaml
delete mode 100644 templates/compose/ollama-with-open-webui.yaml
delete mode 100644 templates/compose/onedev.yaml
delete mode 100644 templates/compose/open-webui.yaml
delete mode 100644 templates/compose/organizr.yaml
delete mode 100644 templates/compose/osticket.yaml
delete mode 100644 templates/compose/overseerr.yaml
delete mode 100644 templates/compose/owncloud.yaml
delete mode 100644 templates/compose/pairdrop.yaml
delete mode 100644 templates/compose/paperless.yaml
delete mode 100644 templates/compose/penpot.yaml
delete mode 100644 templates/compose/peppermint.yaml
delete mode 100644 templates/compose/phpmyadmin.yaml
delete mode 100644 templates/compose/plane.yaml
delete mode 100644 templates/compose/plausible.yaml
delete mode 100644 templates/compose/plex.yaml
delete mode 100644 templates/compose/plunk.yaml
delete mode 100644 templates/compose/pocketbase.yaml
delete mode 100644 templates/compose/portainer.yaml
delete mode 100644 templates/compose/posthog.yaml
delete mode 100644 templates/compose/postiz.yaml
delete mode 100644 templates/compose/prefect.yaml
delete mode 100644 templates/compose/privatebin.yaml
delete mode 100644 templates/compose/prowlarr.yaml
delete mode 100644 templates/compose/pterodactyl.yaml
delete mode 100644 templates/compose/qbittorrent.yaml
delete mode 100644 templates/compose/qdrant.yaml
delete mode 100644 templates/compose/rabbitmq.yaml
delete mode 100644 templates/compose/radarr.yaml
delete mode 100644 templates/compose/rallly.yaml
delete mode 100644 templates/compose/reactive-resume.yaml
delete mode 100644 templates/compose/readeck.yaml
delete mode 100644 templates/compose/redlib.yaml
delete mode 100644 templates/compose/rocketchat.yaml
delete mode 100644 templates/compose/searxng.yaml
delete mode 100644 templates/compose/shlink.yaml
delete mode 100644 templates/compose/slash.yaml
delete mode 100644 templates/compose/snapdrop.yaml
delete mode 100644 templates/compose/soketi.yaml
delete mode 100644 templates/compose/sonarqube.yaml
delete mode 100644 templates/compose/sonarr.yaml
delete mode 100644 templates/compose/statusnook.yaml
delete mode 100644 templates/compose/stirling-pdf.yaml
delete mode 100644 templates/compose/strapi.yaml
delete mode 100644 templates/compose/supabase.yaml
delete mode 100644 templates/compose/supertokens-with-mysql.yaml
delete mode 100644 templates/compose/supertokens-with-postgresql.yaml
delete mode 100644 templates/compose/syncthing.yaml
delete mode 100644 templates/compose/teable.yaml
delete mode 100644 templates/compose/tolgee.yaml
delete mode 100644 templates/compose/traccar.yaml
delete mode 100644 templates/compose/transmission.yaml
delete mode 100644 templates/compose/trigger-with-external-database.yaml
delete mode 100644 templates/compose/trigger.yaml
delete mode 100644 templates/compose/twenty.yaml
delete mode 100644 templates/compose/umami.yaml
delete mode 100644 templates/compose/unleash-with-postgresql.yaml
delete mode 100644 templates/compose/unleash-without-database.yaml
delete mode 100644 templates/compose/unsend.yaml
delete mode 100644 templates/compose/unstructured.yaml
delete mode 100644 templates/compose/uptime-kuma.yaml
delete mode 100644 templates/compose/vaultwarden.yaml
delete mode 100644 templates/compose/vikunja-with-postgresql.yaml
delete mode 100644 templates/compose/vikunja.yaml
delete mode 100644 templates/compose/vvveb-with-mariadb.yaml
delete mode 100644 templates/compose/vvveb-with-mysql.yaml
delete mode 100644 templates/compose/vvveb.yaml
delete mode 100644 templates/compose/wakapi.yaml
delete mode 100644 templates/compose/weaviate.yaml
delete mode 100644 templates/compose/web-check.yaml
delete mode 100644 templates/compose/weblate.yaml
delete mode 100644 templates/compose/whoogle.yaml
delete mode 100644 templates/compose/wikijs.yaml
delete mode 100644 templates/compose/windmill.yaml
delete mode 100644 templates/compose/windows.yaml
delete mode 100644 templates/compose/wireguard-easy.yaml
delete mode 100644 templates/compose/wordpress-with-mariadb.yaml
delete mode 100644 templates/compose/wordpress-with-mysql.yaml
delete mode 100644 templates/compose/wordpress-without-database.yaml
delete mode 100644 templates/compose/zep.yaml
delete mode 100644 templates/compose/zipline.yaml
delete mode 100644 templates/service-templates.json
delete mode 100644 tests/Browser/LoginTest.php
delete mode 100644 tests/Browser/Project/ProjectAddNewTest.php
delete mode 100644 tests/Browser/Project/ProjectSearchTest.php
delete mode 100644 tests/Browser/Project/ProjectTest.php
delete mode 100644 tests/Browser/console/.gitignore
delete mode 100644 tests/Browser/screenshots/.gitignore
delete mode 100644 tests/Browser/source/.gitignore
delete mode 100644 tests/CreatesApplication.php
delete mode 100644 tests/DuskTestCase.php
delete mode 100644 tests/Feature/ConvertArraysTest.php
delete mode 100644 tests/Feature/ConvertingGitUrlsTest.php
delete mode 100644 tests/Feature/DockerComposeParseTest.php
delete mode 100644 tests/Feature/DockerCustomCommandsTest.php
delete mode 100644 tests/Feature/ExecuteContainerCommandTest.php
delete mode 100644 tests/Pest.php
delete mode 100644 tests/TestCase.php
delete mode 100644 tests/Traits/HandlesTestDatabase.php
delete mode 100644 tests/Unit/Services/DockerImageParserTest.php
delete mode 100644 versions.json
diff --git a/.coolify-logo b/.coolify-logo
deleted file mode 100644
index fe8daf6984..0000000000
--- a/.coolify-logo
+++ /dev/null
@@ -1,8 +0,0 @@
- _____ _ _ __
- / ____| | (_)/ _|
- | | ___ ___ | |_| |_ _ _
- | | / _ \ / _ \| | | _| | | |
- | |___| (_) | (_) | | | | | |_| |
- \_____\___/ \___/|_|_|_| \__, |
- __/ |
- |___/
diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index 6f3c903f0f..0000000000
--- a/.dockerignore
+++ /dev/null
@@ -1,38 +0,0 @@
-/.phpunit.cache
-/node_modules
-/public/build
-/public/hot
-/public/storage
-/vendor
-.env
-.env.backup
-.env.secrets
-.phpunit.result.cache
-Homestead.json
-Homestead.yaml
-auth.json
-npm-debug.log
-yarn-error.log
-/.fleet
-/.idea
-/.vscode
-/.npm
-/.bash_history
-/_data
-.rnd
-/.ssh
-.ignition.json
-.env.dusk.local
-docker/coolify-realtime/node_modules
-
-/storage/*.key
-/storage/app/backups
-/storage/app/ssh/keys
-/storage/app/ssh/mux
-/storage/app/tmp
-/storage/app/debugbar
-/storage/logs
-/storage/pail
-
-
-
diff --git a/.env.development.example b/.env.development.example
deleted file mode 100644
index d4daed4f74..0000000000
--- a/.env.development.example
+++ /dev/null
@@ -1,34 +0,0 @@
-# Coolify Configuration
-APP_ENV=local
-APP_NAME="Coolify Development"
-APP_ID=development
-APP_KEY=
-APP_URL=http://localhost
-APP_PORT=8000
-APP_DEBUG=true
-SSH_MUX_ENABLED=true
-
-# PostgreSQL Database Configuration
-DB_DATABASE=coolify
-DB_USERNAME=coolify
-DB_PASSWORD=password
-DB_HOST=host.docker.internal
-DB_PORT=5432
-
-# Ray Configuration
-# Set to true to enable Ray
-RAY_ENABLED=false
-# Set custom ray port
-# RAY_PORT=
-
-# Enable Laravel Telescope for debugging
-TELESCOPE_ENABLED=false
-
-# Selenium Driver URL for Dusk
-DUSK_DRIVER_URL=http://selenium:4444
-
-# Special Keys for Andras
-# For cache purging
-BUNNY_API_KEY=
-# For asset uploads
-BUNNY_STORAGE_API_KEY=
diff --git a/.env.dusk.ci b/.env.dusk.ci
deleted file mode 100644
index 9660de7b48..0000000000
--- a/.env.dusk.ci
+++ /dev/null
@@ -1,15 +0,0 @@
-APP_ENV=production
-APP_NAME="Coolify Staging"
-APP_ID=development
-APP_KEY=
-APP_URL=http://localhost
-APP_PORT=8000
-SSH_MUX_ENABLED=true
-
-# PostgreSQL Database Configuration
-DB_DATABASE=coolify
-DB_USERNAME=coolify
-DB_PASSWORD=password
-DB_HOST=localhost
-DB_PORT=5432
-
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000000..1696ab4873
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,65 @@
+APP_NAME=Laravel
+APP_ENV=local
+APP_KEY=
+APP_DEBUG=true
+APP_URL=http://localhost
+
+APP_LOCALE=en
+APP_FALLBACK_LOCALE=en
+APP_FAKER_LOCALE=en_US
+
+APP_MAINTENANCE_DRIVER=file
+# APP_MAINTENANCE_STORE=database
+
+PHP_CLI_SERVER_WORKERS=4
+
+BCRYPT_ROUNDS=12
+
+LOG_CHANNEL=stack
+LOG_STACK=single
+LOG_DEPRECATIONS_CHANNEL=null
+LOG_LEVEL=debug
+
+DB_CONNECTION=pgsql
+DB_HOST=127.0.0.1
+DB_PORT=5432
+DB_DATABASE=coolify
+DB_USERNAME=root
+DB_PASSWORD=
+
+SESSION_DRIVER=database
+SESSION_LIFETIME=120
+SESSION_ENCRYPT=false
+SESSION_PATH=/
+SESSION_DOMAIN=null
+
+BROADCAST_CONNECTION=log
+FILESYSTEM_DISK=local
+QUEUE_CONNECTION=database
+
+CACHE_STORE=database
+# CACHE_PREFIX=
+
+MEMCACHED_HOST=127.0.0.1
+
+REDIS_CLIENT=phpredis
+REDIS_HOST=127.0.0.1
+REDIS_PASSWORD=null
+REDIS_PORT=6379
+
+MAIL_MAILER=log
+MAIL_SCHEME=null
+MAIL_HOST=127.0.0.1
+MAIL_PORT=2525
+MAIL_USERNAME=null
+MAIL_PASSWORD=null
+MAIL_FROM_ADDRESS="hello@example.com"
+MAIL_FROM_NAME="${APP_NAME}"
+
+AWS_ACCESS_KEY_ID=
+AWS_SECRET_ACCESS_KEY=
+AWS_DEFAULT_REGION=us-east-1
+AWS_BUCKET=
+AWS_USE_PATH_STYLE_ENDPOINT=false
+
+VITE_APP_NAME="${APP_NAME}"
diff --git a/.env.production b/.env.production
deleted file mode 100644
index 96833c2533..0000000000
--- a/.env.production
+++ /dev/null
@@ -1,16 +0,0 @@
-APP_ID=
-APP_NAME=Coolify
-APP_KEY=
-
-DB_USERNAME=coolify
-DB_PASSWORD=
-
-REDIS_PASSWORD=
-
-PUSHER_APP_ID=
-PUSHER_APP_KEY=
-PUSHER_APP_SECRET=
-
-ROOT_USERNAME=
-ROOT_USER_EMAIL=
-ROOT_USER_PASSWORD=
diff --git a/.env.windows-docker-desktop.example b/.env.windows-docker-desktop.example
deleted file mode 100644
index b067b4c5c0..0000000000
--- a/.env.windows-docker-desktop.example
+++ /dev/null
@@ -1,13 +0,0 @@
-IS_WINDOWS_DOCKER_DESKTOP=true
-
-APP_ID=coolify-windows-docker-desktop
-APP_NAME=Coolify
-APP_KEY=base64:ssTlCmrIE/q7whnKMvT6DwURikg69COzGsAwFVROm80=
-
-DB_USERNAME=coolify
-DB_PASSWORD=coolify
-REDIS_PASSWORD=coolify
-
-PUSHER_APP_ID=coolify
-PUSHER_APP_KEY=coolify
-PUSHER_APP_SECRET=coolify
diff --git a/.gitattributes b/.gitattributes
index c48a5898bc..fcb21d396d 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -8,4 +8,4 @@
/.github export-ignore
CHANGELOG.md export-ignore
-.styleci.yml export-ignore
\ No newline at end of file
+.styleci.yml export-ignore
diff --git a/.github/FUNDING.yaml b/.github/FUNDING.yaml
deleted file mode 100644
index 632a4655d8..0000000000
--- a/.github/FUNDING.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-open_collective: coollabsio
-github: coollabsio
diff --git a/.github/ISSUE_TEMPLATE/01_BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/01_BUG_REPORT.yml
deleted file mode 100644
index 42df4785e6..0000000000
--- a/.github/ISSUE_TEMPLATE/01_BUG_REPORT.yml
+++ /dev/null
@@ -1,65 +0,0 @@
-name: 🐞 Bug Report
-description: "File a new bug report."
-title: "[Bug]: "
-labels: ["🐛 Bug", "🔍 Triage"]
-body:
- - type: markdown
- attributes:
- value: |
- > [!IMPORTANT]
- > **Please ensure you are using the latest version of Coolify before submitting an issue, as the bug may have already been fixed in a recent update.** (Of course, if you're experiencing an issue on the latest version that wasn't present in a previous version, please let us know.)
-
- # 💎 Bounty Program (with [algora.io](https://console.algora.io/org/coollabsio/bounties/new))
- - If you would like to prioritize the issue resolution, consider adding a bounty to this issue through our [Bounty Program](https://console.algora.io/org/coollabsio/bounties/new).
-
- - type: textarea
- attributes:
- label: Error Message and Logs
- description: Provide a detailed description of the error or exception you encountered, along with any relevant log output.
- validations:
- required: true
-
- - type: textarea
- attributes:
- label: Steps to Reproduce
- description: Please provide a step-by-step guide to reproduce the issue. Be as detailed as possible, otherwise we may not be able to assist you.
- value: |
- 1.
- 2.
- 3.
- 4.
- validations:
- required: true
-
- - type: input
- attributes:
- label: Example Repository URL
- description: If applicable, provide a URL to a repository demonstrating the issue.
-
- - type: input
- attributes:
- label: Coolify Version
- description: Please provide the Coolify version you are using. This can be found in the top left corner of your Coolify dashboard.
- placeholder: "v4.0.0-beta.335"
- validations:
- required: true
-
- - type: dropdown
- attributes:
- label: Are you using Coolify Cloud?
- options:
- - "No (self-hosted)"
- - "Yes (Coolify Cloud)"
- validations:
- required: true
-
- - type: input
- attributes:
- label: Operating System and Version (self-hosted)
- description: Run `cat /etc/os-release` or `lsb_release -a` in your terminal and provide the operating system and version.
- placeholder: "Ubuntu 22.04"
-
- - type: textarea
- attributes:
- label: Additional Information
- description: Any other relevant details about the issue.
diff --git a/.github/ISSUE_TEMPLATE/02_ENHANCEMENT_BOUNTY.yml b/.github/ISSUE_TEMPLATE/02_ENHANCEMENT_BOUNTY.yml
deleted file mode 100644
index ef26125e0b..0000000000
--- a/.github/ISSUE_TEMPLATE/02_ENHANCEMENT_BOUNTY.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-name: 💎 Enhancement Bounty
-description: "Propose a new feature, service, or improvement with an attached bounty."
-title: "[Enhancement]: "
-labels: ["✨ Enhancement", "🔍 Triage"]
-body:
- - type: markdown
- attributes:
- value: |
- > [!IMPORTANT]
- > **This issue template is exclusively for proposing new features, services, or improvements with an attached bounty.** Enhancements without a bounty can be discussed in the appropriate category of [Github Discussions](https://github.com/coollabsio/coolify/discussions).
-
- # 💎 Add a Bounty (with [algora.io](https://console.algora.io/org/coollabsio/bounties/new))
- - [Click here to add the required bounty](https://console.algora.io/org/coollabsio/bounties/new)
-
- - type: dropdown
- attributes:
- label: Request Type
- description: Select the type of request you are making.
- options:
- - New Feature
- - New Service
- - Improvement
- validations:
- required: true
-
- - type: textarea
- attributes:
- label: Description
- description: Provide a detailed description of the feature, improvement, or service you are proposing.
- validations:
- required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
deleted file mode 100644
index 92c48e2d62..0000000000
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-blank_issues_enabled: false
-
-contact_links:
- - name: 🤔 Questions and Community Support
- url: https://coollabs.io/discord
- about: If you have any questions, reach out to us on Discord inside the "#support" channel.
-
- - name: 💡 Feature Request
- url: https://github.com/coollabsio/coolify/discussions/categories/feature-requests
- about: Suggest a new feature for Coolify.
-
- - name: ⚙️ Service Request
- url: https://github.com/coollabsio/coolify/discussions/categories/service-requests
- about: Request a new service integration for Coolify.
-
- - name: 🔧 Improvements
- url: https://github.com/coollabsio/coolify/discussions/categories/improvements
- about: Suggest improvements to existing features for Coolify.
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
deleted file mode 100644
index 5afe00a301..0000000000
--- a/.github/pull_request_template.md
+++ /dev/null
@@ -1,13 +0,0 @@
-## Submit Checklist (REMOVE THIS SECTION BEFORE SUBMITTING)
-- [ ] I have selected the `next` branch as the destination for my PR, not `main`.
-- [ ] I have listed all changes in the `Changes` section.
-- [ ] I have filled out the `Issues` section with the issue/discussion link(s) (if applicable).
-- [ ] I have tested my changes.
-- [ ] I have considered backwards compatibility.
-- [ ] I have removed this checklist and any unused sections.
-
-## Changes
--
-
-## Issues
-- fix #
diff --git a/.github/workflows/browser-tests.yml b/.github/workflows/browser-tests.yml
deleted file mode 100644
index b06c9e97cf..0000000000
--- a/.github/workflows/browser-tests.yml
+++ /dev/null
@@ -1,65 +0,0 @@
-name: Dusk
-on:
- push:
- branches: [ "not-existing" ]
-jobs:
- dusk:
- runs-on: ubuntu-latest
-
- services:
- redis:
- image: redis
- env:
- REDIS_HOST: localhost
- REDIS_PORT: 6379
- ports:
- - 6379:6379
- options: >-
- --health-cmd "redis-cli ping"
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- steps:
- - uses: actions/checkout@v4
- - name: Set up PostgreSQL
- run: |
- sudo systemctl start postgresql
- sudo -u postgres psql -c "CREATE DATABASE coolify;"
- sudo -u postgres psql -c "CREATE USER coolify WITH PASSWORD 'password';"
- sudo -u postgres psql -c "ALTER ROLE coolify SET client_encoding TO 'utf8';"
- sudo -u postgres psql -c "ALTER ROLE coolify SET default_transaction_isolation TO 'read committed';"
- sudo -u postgres psql -c "ALTER ROLE coolify SET timezone TO 'UTC';"
- sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE coolify TO coolify;"
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: '8.2'
- - name: Copy .env
- run: cp .env.dusk.ci .env
- - name: Install Dependencies
- run: composer install --no-progress --prefer-dist --optimize-autoloader
- - name: Generate key
- run: php artisan key:generate
- - name: Install Chrome binaries
- run: php artisan dusk:chrome-driver --detect
- - name: Start Chrome Driver
- run: ./vendor/laravel/dusk/bin/chromedriver-linux --port=4444 &
- - name: Build assets
- run: npm install && npm run build
- - name: Run Laravel Server
- run: php artisan serve --no-reload &
- - name: Execute tests
- run: php artisan dusk
- - name: Upload Screenshots
- if: failure()
- uses: actions/upload-artifact@v4
- with:
- name: screenshots
- path: tests/Browser/screenshots
- - name: Upload Console Logs
- if: failure()
- uses: actions/upload-artifact@v4
- with:
- name: console
- path: tests/Browser/console
diff --git a/.github/workflows/chore-lock-closed-issues-discussions-and-prs.yml b/.github/workflows/chore-lock-closed-issues-discussions-and-prs.yml
deleted file mode 100644
index d008539647..0000000000
--- a/.github/workflows/chore-lock-closed-issues-discussions-and-prs.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-name: Lock closed Issues, Discussions, and PRs
-
-on:
- schedule:
- - cron: '0 1 * * *'
-
-jobs:
- lock-threads:
- runs-on: ubuntu-latest
- steps:
- - name: Lock threads after 30 days of inactivity
- uses: dessant/lock-threads@v5
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- issue-inactive-days: '30'
- pr-inactive-days: '30'
- discussion-inactive-days: '30'
diff --git a/.github/workflows/chore-manage-stale-issues-and-prs.yml b/.github/workflows/chore-manage-stale-issues-and-prs.yml
deleted file mode 100644
index 58a2b7d7e6..0000000000
--- a/.github/workflows/chore-manage-stale-issues-and-prs.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-name: Manage Stale Issues and PRs
-
-on:
- schedule:
- - cron: '0 2 * * *'
-
-jobs:
- manage-stale:
- runs-on: ubuntu-latest
- steps:
- - name: Manage stale issues and PRs
- uses: actions/stale@v9
- id: stale
- with:
- stale-issue-message: 'This issue will be automatically closed in a few days if no response is received. Please provide an update with the requested information.'
- stale-pr-message: 'This pull request requires attention. If no changes or response is received within the next few days, it will be automatically closed. Please update your PR or leave a comment with the requested information.'
- close-issue-message: 'This issue has been automatically closed due to inactivity.'
- close-pr-message: 'Thank you for your contribution. Due to inactivity, this PR was automatically closed. If you would like to continue working on this change in the future, feel free to reopen this PR or submit a new one.'
- days-before-stale: 14
- days-before-close: 7
- stale-issue-label: '⏱︎ Stale'
- stale-pr-label: '⏱︎ Stale'
- only-labels: '💤 Waiting for feedback, 💤 Waiting for changes'
- remove-stale-when-updated: true
- operations-per-run: 100
- labels-to-remove-when-unstale: '⏱︎ Stale, 💤 Waiting for feedback, 💤 Waiting for changes'
- close-issue-reason: 'not_planned'
- exempt-all-milestones: false
diff --git a/.github/workflows/chore-remove-labels-and-assignees-on-close.yml b/.github/workflows/chore-remove-labels-and-assignees-on-close.yml
deleted file mode 100644
index a3c299b5ea..0000000000
--- a/.github/workflows/chore-remove-labels-and-assignees-on-close.yml
+++ /dev/null
@@ -1,82 +0,0 @@
-name: Remove Labels and Assignees on Issue Close
-
-on:
- issues:
- types: [closed]
- pull_request:
- types: [closed]
- pull_request_target:
- types: [closed]
-
-jobs:
- remove-labels-and-assignees:
- runs-on: ubuntu-latest
- steps:
- - name: Remove labels and assignees
- uses: actions/github-script@v7
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const { owner, repo } = context.repo;
-
- async function processIssue(issueNumber, isFromPR = false, prBaseBranch = null) {
- try {
- if (isFromPR && prBaseBranch !== 'main') {
- return;
- }
-
- const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
- owner,
- repo,
- issue_number: issueNumber
- });
-
- const labelsToKeep = currentLabels
- .filter(label => label.name === '⏱︎ Stale')
- .map(label => label.name);
-
- await github.rest.issues.setLabels({
- owner,
- repo,
- issue_number: issueNumber,
- labels: labelsToKeep
- });
-
- const { data: issue } = await github.rest.issues.get({
- owner,
- repo,
- issue_number: issueNumber
- });
-
- if (issue.assignees && issue.assignees.length > 0) {
- await github.rest.issues.removeAssignees({
- owner,
- repo,
- issue_number: issueNumber,
- assignees: issue.assignees.map(assignee => assignee.login)
- });
- }
- } catch (error) {
- if (error.status !== 404) {
- console.error(`Error processing issue ${issueNumber}:`, error);
- }
- }
- }
-
- if (context.eventName === 'issues') {
- await processIssue(context.payload.issue.number);
- }
-
- if (context.eventName === 'pull_request' || context.eventName === 'pull_request_target') {
- const pr = context.payload.pull_request;
- await processIssue(pr.number);
- if (pr.merged && pr.base.ref === 'main' && pr.body) {
- const issueReferences = pr.body.match(/#(\d+)/g);
- if (issueReferences) {
- for (const reference of issueReferences) {
- const issueNumber = parseInt(reference.substring(1));
- await processIssue(issueNumber, true, pr.base.ref);
- }
- }
- }
- }
diff --git a/.github/workflows/coolify-helper-next.yml b/.github/workflows/coolify-helper-next.yml
deleted file mode 100644
index a4a2a21f64..0000000000
--- a/.github/workflows/coolify-helper-next.yml
+++ /dev/null
@@ -1,142 +0,0 @@
-name: Coolify Helper Image Development
-
-on:
- push:
- branches: [ "next" ]
- paths:
- - .github/workflows/coolify-helper-next.yml
- - docker/coolify-helper/Dockerfile
-
-env:
- GITHUB_REGISTRY: ghcr.io
- DOCKER_REGISTRY: docker.io
- IMAGE_NAME: "coollabsio/coolify-helper"
-
-jobs:
- amd64:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/coolify-helper/Dockerfile
- platforms: linux/amd64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next
- labels: |
- coolify.managed=true
- aarch64:
- runs-on: [ self-hosted, arm64 ]
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/coolify-helper/Dockerfile
- platforms: linux/aarch64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64
- labels: |
- coolify.managed=true
-
- merge-manifest:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- needs: [ amd64, aarch64 ]
- steps:
- - uses: actions/checkout@v4
- - uses: docker/setup-buildx-action@v3
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:next
-
- - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:next
-
- - uses: sarisia/actions-status-discord@v1
- if: always()
- with:
- webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}
-
diff --git a/.github/workflows/coolify-helper.yml b/.github/workflows/coolify-helper.yml
deleted file mode 100644
index 78c888a018..0000000000
--- a/.github/workflows/coolify-helper.yml
+++ /dev/null
@@ -1,142 +0,0 @@
-name: Coolify Helper Image
-
-on:
- push:
- branches: [ "main" ]
- paths:
- - .github/workflows/coolify-helper.yml
- - docker/coolify-helper/Dockerfile
-
-env:
- GITHUB_REGISTRY: ghcr.io
- DOCKER_REGISTRY: docker.io
- IMAGE_NAME: "coollabsio/coolify-helper"
-
-jobs:
- amd64:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/coolify-helper/Dockerfile
- platforms: linux/amd64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
- labels: |
- coolify.managed=true
- aarch64:
- runs-on: [ self-hosted, arm64 ]
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/coolify-helper/Dockerfile
- platforms: linux/aarch64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
- labels: |
- coolify.managed=true
- merge-manifest:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- needs: [ amd64, aarch64 ]
- steps:
- - uses: actions/checkout@v4
-
- - uses: docker/setup-buildx-action@v3
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getHelperVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
-
- - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
-
- - uses: sarisia/actions-status-discord@v1
- if: always()
- with:
- webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }}
-
diff --git a/.github/workflows/coolify-production-build.yml b/.github/workflows/coolify-production-build.yml
deleted file mode 100644
index ad08782056..0000000000
--- a/.github/workflows/coolify-production-build.yml
+++ /dev/null
@@ -1,140 +0,0 @@
-name: Production Build (v4)
-
-on:
- push:
- branches: ["main"]
- paths-ignore:
- - .github/workflows/coolify-helper.yml
- - .github/workflows/coolify-helper-next.yml
- - .github/workflows/coolify-realtime.yml
- - .github/workflows/coolify-realtime-next.yml
- - docker/coolify-helper/Dockerfile
- - docker/coolify-realtime/Dockerfile
- - docker/testing-host/Dockerfile
- - templates/**
- - CHANGELOG.md
-
-env:
- GITHUB_REGISTRY: ghcr.io
- DOCKER_REGISTRY: docker.io
- IMAGE_NAME: "coollabsio/coolify"
-
-jobs:
- amd64:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/production/Dockerfile
- platforms: linux/amd64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
-
- aarch64:
- runs-on: [self-hosted, arm64]
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/production/Dockerfile
- platforms: linux/aarch64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
-
- merge-manifest:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- needs: [amd64, aarch64]
- steps:
- - uses: actions/checkout@v4
-
- - uses: docker/setup-buildx-action@v3
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
-
- - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
-
- - uses: sarisia/actions-status-discord@v1
- if: always()
- with:
- webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }}
diff --git a/.github/workflows/coolify-realtime-next.yml b/.github/workflows/coolify-realtime-next.yml
deleted file mode 100644
index ad590146be..0000000000
--- a/.github/workflows/coolify-realtime-next.yml
+++ /dev/null
@@ -1,147 +0,0 @@
-name: Coolify Realtime Development
-
-on:
- push:
- branches: [ "next" ]
- paths:
- - .github/workflows/coolify-realtime-next.yml
- - docker/coolify-realtime/Dockerfile
- - docker/coolify-realtime/terminal-server.js
- - docker/coolify-realtime/package.json
- - docker/coolify-realtime/package-lock.json
- - docker/coolify-realtime/soketi-entrypoint.sh
-
-env:
- GITHUB_REGISTRY: ghcr.io
- DOCKER_REGISTRY: docker.io
- IMAGE_NAME: "coollabsio/coolify-realtime"
-
-jobs:
- amd64:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/coolify-realtime/Dockerfile
- platforms: linux/amd64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next
- labels: |
- coolify.managed=true
-
- aarch64:
- runs-on: [ self-hosted, arm64 ]
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/coolify-realtime/Dockerfile
- platforms: linux/aarch64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64
- labels: |
- coolify.managed=true
-
- merge-manifest:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- needs: [ amd64, aarch64 ]
- steps:
- - uses: actions/checkout@v4
-
- - uses: docker/setup-buildx-action@v3
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:next
-
- - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:next
-
- - uses: sarisia/actions-status-discord@v1
- if: always()
- with:
- webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}
diff --git a/.github/workflows/coolify-realtime.yml b/.github/workflows/coolify-realtime.yml
deleted file mode 100644
index d3af141449..0000000000
--- a/.github/workflows/coolify-realtime.yml
+++ /dev/null
@@ -1,147 +0,0 @@
-name: Coolify Realtime
-
-on:
- push:
- branches: [ "main" ]
- paths:
- - .github/workflows/coolify-realtime.yml
- - docker/coolify-realtime/Dockerfile
- - docker/coolify-realtime/terminal-server.js
- - docker/coolify-realtime/package.json
- - docker/coolify-realtime/package-lock.json
- - docker/coolify-realtime/soketi-entrypoint.sh
-
-env:
- GITHUB_REGISTRY: ghcr.io
- DOCKER_REGISTRY: docker.io
- IMAGE_NAME: "coollabsio/coolify-realtime"
-
-jobs:
- amd64:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/coolify-realtime/Dockerfile
- platforms: linux/amd64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
- labels: |
- coolify.managed=true
-
- aarch64:
- runs-on: [ self-hosted, arm64 ]
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/coolify-realtime/Dockerfile
- platforms: linux/aarch64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
- labels: |
- coolify.managed=true
-
- merge-manifest:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- needs: [ amd64, aarch64 ]
- steps:
- - uses: actions/checkout@v4
-
- - uses: docker/setup-buildx-action@v3
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
-
- - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
-
- - uses: sarisia/actions-status-discord@v1
- if: always()
- with:
- webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }}
diff --git a/.github/workflows/coolify-staging-build.yml b/.github/workflows/coolify-staging-build.yml
deleted file mode 100644
index ff6b553dfd..0000000000
--- a/.github/workflows/coolify-staging-build.yml
+++ /dev/null
@@ -1,126 +0,0 @@
-name: Staging Build
-
-on:
- push:
- branches-ignore: ["main", "v3"]
- paths-ignore:
- - .github/workflows/coolify-helper.yml
- - .github/workflows/coolify-helper-next.yml
- - .github/workflows/coolify-realtime.yml
- - .github/workflows/coolify-realtime-next.yml
- - docker/coolify-helper/Dockerfile
- - docker/coolify-realtime/Dockerfile
- - docker/testing-host/Dockerfile
- - templates/**
- - CHANGELOG.md
-
-env:
- GITHUB_REGISTRY: ghcr.io
- DOCKER_REGISTRY: docker.io
- IMAGE_NAME: "coollabsio/coolify"
-
-jobs:
- amd64:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/production/Dockerfile
- platforms: linux/amd64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
-
- aarch64:
- runs-on: [self-hosted, arm64]
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/production/Dockerfile
- platforms: linux/aarch64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64
-
- merge-manifest:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- needs: [amd64, aarch64]
- steps:
- - uses: actions/checkout@v4
-
- - uses: docker/setup-buildx-action@v3
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
-
- - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64 \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
-
- - uses: sarisia/actions-status-discord@v1
- if: always()
- with:
- webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}
diff --git a/.github/workflows/coolify-testing-host.yml b/.github/workflows/coolify-testing-host.yml
deleted file mode 100644
index 95a228114a..0000000000
--- a/.github/workflows/coolify-testing-host.yml
+++ /dev/null
@@ -1,126 +0,0 @@
-name: Coolify Testing Host
-
-on:
- push:
- branches: [ "next" ]
- paths:
- - .github/workflows/coolify-testing-host.yml
- - docker/testing-host/Dockerfile
-
-env:
- GITHUB_REGISTRY: ghcr.io
- DOCKER_REGISTRY: docker.io
- IMAGE_NAME: "coollabsio/coolify-testing-host"
-
-jobs:
- amd64:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/testing-host/Dockerfile
- platforms: linux/amd64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- labels: |
- coolify.managed=true
-
- aarch64:
- runs-on: [ self-hosted, arm64 ]
- permissions:
- contents: read
- packages: write
- steps:
- - uses: actions/checkout@v4
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Build and Push Image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/testing-host/Dockerfile
- platforms: linux/aarch64
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64
- labels: |
- coolify.managed=true
-
- merge-manifest:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- packages: write
- needs: [ amd64, aarch64 ]
- steps:
- - uses: actions/checkout@v4
-
- - uses: docker/setup-buildx-action@v3
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64 \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
-
- - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }}
- run: |
- docker buildx imagetools create \
- --append ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest-aarch64 \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
-
- - uses: sarisia/actions-status-discord@v1
- if: always()
- with:
- webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}
diff --git a/.github/workflows/generate-changelog.yml b/.github/workflows/generate-changelog.yml
deleted file mode 100644
index ee5af6b3d2..0000000000
--- a/.github/workflows/generate-changelog.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-name: Generate Changelog
-
-on:
- push:
- branches: [ main ]
- workflow_dispatch:
-
-permissions:
- contents: write
-
-jobs:
- changelog:
- name: Generate changelog
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Generate changelog
- uses: orhun/git-cliff-action@v4
- with:
- config: cliff.toml
- args: --verbose
- env:
- OUTPUT: CHANGELOG.md
- GITHUB_REPO: ${{ github.repository }}
-
- - name: Commit
- run: |
- git config user.name 'github-actions[bot]'
- git config user.email 'github-actions[bot]@users.noreply.github.com'
- git add CHANGELOG.md
- git commit -m "docs: update changelog"
- git push https://${{ secrets.GITHUB_TOKEN }}@github.com/${GITHUB_REPOSITORY}.git main
diff --git a/.gitignore b/.gitignore
index 541c8e9203..5ac0f2a9cf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,36 +4,21 @@
/public/hot
/public/storage
/storage/*.key
+/storage/pail
/vendor
.env
.env.backup
-.env.secrets
+.env.production
+.phpactor.json
.phpunit.result.cache
Homestead.json
Homestead.yaml
-auth.json
npm-debug.log
yarn-error.log
+/auth.json
/.fleet
/.idea
+/.nova
/.vscode
-/.npm
-/.bash_history
-/_data
-_testing_hosts/
-_volumes/
-.lesshst
-psysh_history
-.psql_history
-_ide_helper.php
-.gitignore
-.phpstorm.meta.php
-_ide_helper_models.php
-.rnd
-/.ssh
-scripts/load-test/*
-.ignition.json
-.env.dusk.local
-docker/coolify-realtime/node_modules
+/.zed
.DS_Store
-Changelog.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index fa6a282642..0000000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,6844 +0,0 @@
-# Changelog
-
-All notable changes to this project will be documented in this file.
-
-## [unreleased]
-
-### 🚀 Features
-
-- *(billing)* Add Stripe past due subscription status tracking
-- *(ui)* Add past due subscription warning banner
-
-### 🐛 Bug Fixes
-
-- *(billing)* Restrict Stripe subscription status update to 'active' only
-
-### 💼 Other
-
-- Bump Coolify to 4.0.0-beta.398
-
-### 🚜 Refactor
-
-- *(billing)* Enhance Stripe subscription status handling and notifications
-
-## [4.0.0-beta.397] - 2025-02-28
-
-### 🐛 Bug Fixes
-
-- *(billing)* Handle 'past_due' subscription status in Stripe processing
-- *(revert)* Label parsing
-- *(helpers)* Initialize command variable in parseCommandFromMagicEnvVariable
-
-### 📚 Documentation
-
-- Update changelog
-
-## [4.0.0-beta.396] - 2025-02-28
-
-### 🚀 Features
-
-- *(ui)* Add wire:key to two-step confirmation settings
-- *(database)* Add index to scheduled task executions for improved query performance
-- *(database)* Add index to scheduled database backup executions
-
-### 🐛 Bug Fixes
-
-- *(core)* Production dockerfile
-- *(ui)* Update storage configuration guidance link
-- *(ui)* Set default SMTP encryption to starttls
-- *(notifications)* Correct environment URL path in application notifications
-- *(config)* Update default PostgreSQL host to coolify-db instead of postgres
-- *(docker)* Improve Docker compose file validation process
-- *(ui)* Restrict service retrieval to current team
-- *(core)* Only validate custom compose files
-- *(mail)* Set default mailer to array when not specified
-- *(ui)* Correct redirect routes after task deletion
-- *(core)* Adding a new server should not try to make the default docker network
-- *(core)* Clean up unnecessary files during application image build
-- *(core)* Improve label generation and merging for applications and services
-
-### 💼 Other
-
-- Bump all dependencies (#5216)
-
-### 🚜 Refactor
-
-- *(ui)* Simplify file storage modal confirmations
-- *(notifications)* Improve transactional email settings handling
-- *(scheduled-tasks)* Improve scheduled task creation and management
-
-### 📚 Documentation
-
-- Update changelog
-- Update changelog
-
-### ⚙️ Miscellaneous Tasks
-
-- Bump helper and realtime version
-
-## [4.0.0-beta.395] - 2025-02-22
-
-### 📚 Documentation
-
-- Update changelog
-
-## [4.0.0-beta.394] - 2025-02-17
-
-### 📚 Documentation
-
-- Update changelog
-
-## [4.0.0-beta.393] - 2025-02-15
-
-### 📚 Documentation
-
-- Update changelog
-
-## [4.0.0-beta.392] - 2025-02-13
-
-### 🚀 Features
-
-- *(ui)* Add top padding to pricing plans view
-- *(core)* Add error logging and cron parsing to docker/server schedules
-- *(core)* Prevent using servers with existing resources as build servers
-- *(ui)* Add textarea switching option in service compose editor
-
-### 🐛 Bug Fixes
-
-- Pull latest image from registry when using build server
-- *(deployment)* Improve server selection for deployment cancellation
-- *(deployment)* Improve log line rendering and formatting
-- *(s3-storage)* Optimize team admin notification query
-- *(core)* Improve connection testing with dynamic disk configuration for s3 backups
-- *(core)* Update service status refresh event handling
-- *(ui)* Adjust polling intervals for database and service status checks
-- *(service)* Update Fider service template healthcheck command
-- *(core)* Improve server selection error handling in Docker component
-- *(core)* Add server functionality check before dispatching container status
-- *(ui)* Disable sticky scroll in Monaco editor
-- *(ui)* Add literal and multiline env support to services.
-- *(services)* Owncloud docs link
-- *(template)* Remove db-migration step from `infisical.yaml` (#5209)
-- *(service)* Penpot (#5047)
-
-### 🚜 Refactor
-
-- Use pull flag on docker compose up
-
-### 📚 Documentation
-
-- Update changelog
-- Update changelog
-
-### ⚙️ Miscellaneous Tasks
-
-- Rollback Coolify version to 4.0.0-beta.392
-- Bump Coolify version to 4.0.0-beta.393
-- Bump Coolify version to 4.0.0-beta.394
-- Bump Coolify version to 4.0.0-beta.395
-- Bump Coolify version to 4.0.0-beta.396
-- *(services)* Update zipline to use new Database env var. (#5210)
-- *(service)* Upgrade authentik service
-- *(service)* Remove unused env from zipline
-
-## [4.0.0-beta.391] - 2025-02-04
-
-### 🚀 Features
-
-- Add application api route
-- Container logs
-- Remove ansi color from log
-- Add lines query parameter
-- *(changelog)* Add git cliff for automatic changelog generation
-- *(workflows)* Improve changelog generation and workflows
-- *(ui)* Add periodic status checking for services
-- *(deployment)* Ensure private key is stored in filesystem before deployment
-- *(slack)* Show message title in notification previews (#5063)
-- *(i18n)* Add Arabic translations (#4991)
-- *(i18n)* Add French translations (#4992)
-- *(services)* Update `service-templates.json`
-
-### 🐛 Bug Fixes
-
-- *(core)* Improve deployment failure Slack notification formatting
-- *(core)* Update Slack notification formatting to use bold correctly
-- *(core)* Enhance Slack deployment success notification formatting
-- *(ui)* Simplify service templates loading logic
-- *(ui)* Align title and add button vertically in various views
-- Handle pullrequest:updated for reliable preview deployments
-- *(ui)* Fix typo on team page (#5105)
-- Cal.com documentation link give 404 (#5070)
-- *(slack)* Notification settings URL in `HighDiskUsage` message (#5071)
-- *(ui)* Correct typo in Storage delete dialog (#5061)
-- *(lang)* Add missing italian translations (#5057)
-- *(service)* Improve duplicati.yaml (#4971)
-- *(service)* Links in homepage service (#5002)
-- *(service)* Added SMTP credentials to getoutline yaml template file (#5011)
-- *(service)* Added `KEY` Variable to Beszel Template (#5021)
-- *(cloudflare-tunnels)* Dead links to docs (#5104)
-- System-wide GitHub apps (#5114)
-
-### 🚜 Refactor
-
-- Simplify service start and restart workflows
-
-### 📚 Documentation
-
-- *(services)* Reword nitropage url and slogan
-- *(readme)* Add Convex to special sponsors section
-- Update changelog
-
-### ⚙️ Miscellaneous Tasks
-
-- *(config)* Increase default PHP memory limit to 256M
-- Add openapi response
-- *(workflows)* Make naming more clear and remove unused code
-- Bump Coolify version to 4.0.0-beta.392/393
-- *(ci)* Update changelog generation workflow to target 'next' branch
-- *(ci)* Update changelog generation workflow to target main branch
-
-## [4.0.0-beta.390] - 2025-01-28
-
-### 🚀 Features
-
-- *(template)* Add Open Web UI
-- *(templates)* Add Open Web UI service template
-- *(ui)* Update GitHub source creation advanced section label
-- *(core)* Add dynamic label reset for application settings
-- *(ui)* Conditionally enable advanced application settings based on label readonly status
-- *(env)* Added COOLIFY_RESOURCE_UUID environment variable
-- *(vite)* Add Cloudflare async script and style tag attributes
-- *(meta)* Add comprehensive SEO and social media meta tags
-- *(core)* Add name to default proxy configuration
-
-### 🐛 Bug Fixes
-
-- *(ui)* Update database control UI to check server functionality before displaying actions
-- *(ui)* Typo in upgrade message
-- *(ui)* Cloudflare tunnel configuration should be an info, not a warning
-- *(s3)* DigitalOcean storage buckets do not work
-- *(ui)* Correct typo in container label helper text
-- Disable certain parts if readonly label is turned off
-- Cleanup old scheduled_task_executions
-- Validate cron expression in Scheduled Task update
-- *(core)* Check cron expression on save
-- *(database)* Detect more postgres database image types
-- *(templates)* Update service templates
-- Remove quotes in COOLIFY_CONTAINER_NAME
-- *(templates)* Update Trigger.dev service templates with v3 configuration
-- *(database)* Adjust MongoDB restore command and import view styling
-- *(core)* Improve public repository URL parsing for branch and base directory
-- *(core)* Increase HTTP/2 max concurrent streams to 250 (default)
-- *(ui)* Update docker compose file helper text to clarify repository modification
-- *(ui)* Skip SERVICE_FQDN and SERVICE_URL variables during update
-- *(core)* Stopping database is not disabling db proxy
-- *(core)* Remove --remove-orphans flag from proxy startup command to prevent other proxy deletions (db)
-- *(api)* Domain check when updating domain
-- *(ui)* Always redirect to dashboard after team switch
-- *(backup)* Escape special characters in database backup commands
-
-### 💼 Other
-
-- Trigger.dev templates - wrong key length issue
-- Trigger.dev template - missing ports and wrong env usage
-- Trigger.dev template - fixed otel config
-- Trigger.dev template - fixed otel config
-- Trigger.dev template - fixed port config
-
-### 🚜 Refactor
-
-- *(s3)* Improve S3 bucket endpoint formatting
-- *(vite)* Improve environment variable handling in Vite configuration
-- *(ui)* Simplify GitHub App registration UI and layout
-
-### ⚙️ Miscellaneous Tasks
-
-- *(version)* Bump Coolify version to 4.0.0-beta.391
-
-### ◀️ Revert
-
-- Remove Cloudflare async tag attributes
-
-## [4.0.0-beta.389] - 2025-01-23
-
-### 🚀 Features
-
-- *(docs)* Update tech stack
-- *(terminal)* Show terminal unavailable if the container does not have a shell on the global terminal UI
-- *(ui)* Improve deployment UI
-
-### 🐛 Bug Fixes
-
-- *(service)* Infinite loading and lag with invoiceninja service (#4876)
-- *(service)* Invoiceninja service
-- *(workflows)* `Waiting for changes` label should also be considered and improved messages
-- *(workflows)* Remove tags only if the PR has been merged into the main branch
-- *(terminal)* Terminal shows that it is not available, even though it is
-- *(labels)* Docker labels do not generated correctly
-- *(helper)* Downgrade Nixpacks to v1.29.0
-- *(labels)* Generate labels when they are empty not when they are already generated
-- *(storage)* Hetzner storage buckets not working
-
-### 📚 Documentation
-
-- Add TECH_STACK.md (#4883)
-
-### ⚙️ Miscellaneous Tasks
-
-- *(versions)* Update coolify versions to v4.0.0-beta.389
-- *(core)* EnvironmentVariable Model now extends BaseModel to remove duplicated code
-- *(versions)* Update coolify versions to v4.0.0-beta.3909
-
-## [4.0.0-beta.388] - 2025-01-22
-
-### 🚀 Features
-
-- *(core)* Add SOURCE_COMMIT variable to build environment in ApplicationDeploymentJob
-- *(service)* Update affine.yaml with AI environment variables (#4918)
-- *(service)* Add new service Flipt (#4875)
-
-### 🐛 Bug Fixes
-
-- *(core)* Update environment variable generation logic in ApplicationDeploymentJob to handle different build packs
-- *(env)* Shared variables can not be updated
-- *(ui)* Metrics stuck in loading state
-- *(ui)* Use `wire:navigate` to navigate to the server settings page
-- *(service)* Plunk API & health check endpoint (#4925)
-
-## [4.0.0-beta.386] - 2025-01-22
-
-### 🐛 Bug Fixes
-
-- *(redis)* Update environment variable keys from standalone_redis_id to resourceable_id
-- *(routes)* Local API docs not available on domain or IP
-- *(routes)* Local API docs not available on domain or IP
-- *(core)* Update application_id references to resourable_id and resourable_type for Nixpacks configuration
-- *(core)* Correct spelling of 'resourable' to 'resourceable' in Nixpacks configuration for ApplicationDeploymentJob
-- *(ui)* Traefik dashboard url not working
-- *(ui)* Proxy status badge flashing during navigation
-
-### 🚜 Refactor
-
-- *(workflows)* Replace jq with PHP script for version retrieval in workflows
-
-### ⚙️ Miscellaneous Tasks
-
-- *(dep)* Bump helper version to 1.0.5
-- *(docker)* Add blank line for readability in Dockerfile
-- *(versions)* Update coolify versions to v4.0.0-beta.388
-- *(versions)* Update coolify versions to v4.0.0-beta.389 and add helper version retrieval script
-
-## [4.0.0-beta.385] - 2025-01-21
-
-### 🚀 Features
-
-- *(core)* Wip version of coolify.json
-
-### 🐛 Bug Fixes
-
-- *(email)* Transactional email sending
-- *(ui)* Add missing save button for new Docker Cleanup page
-- *(ui)* Show preview deployment environment variables
-- *(ui)* Show error on terminal if container has no shell (bash/sh)
-- *(parser)* Resource URL should only be parsed if there is one
-- *(core)* Compose parsing for apps
-
-### ⚙️ Miscellaneous Tasks
-
-- *(dep)* Bump nixpacks version
-- *(dep)* Version++
-
-## [4.0.0-beta.384] - 2025-01-21
-
-### 🐛 Bug Fixes
-
-- *(ui)* Backups link should not redirected to general
-- Envs with special chars during build
-- *(db)* `finished_at` timestamps are not set for existing deployments
-- Load service templates on cloud
-
-## [4.0.0-beta.383] - 2025-01-20
-
-### 🐛 Bug Fixes
-
-- *(service)* Add healthcheck to Cloudflared service (#4859)
-- Remove wire:navigate from import backups
-
-## [4.0.0-beta.382] - 2025-01-17
-
-### 🚀 Features
-
-- Add log file check message in upgrade script for better troubleshooting
-- Add root user details to install script
-
-### 🐛 Bug Fixes
-
-- Create the private key before the server in the prod seeder
-- Update ProductionSeeder to check for private key instead of server's private key
-- *(ui)* Missing underline for docs link in the Swarm section (#4860)
-- *(service)* Change chatwoot service postgres image from `postgres:12` to `pgvector/pgvector:pg12`
-- Docker image parser
-- Add public key attribute to privatekey model
-- Correct service update logic in Docker Compose parser
-- Update CDN URL in install script to point to nightly version
-
-### 🚜 Refactor
-
-- Comment out RootUserSeeder call in ProductionSeeder for clarity
-- Streamline ProductionSeeder by removing debug logs and unnecessary checks, while ensuring essential seeding operations remain intact
-- Remove debug echo statements from Init command to clean up output and improve readability
-
-## [4.0.0-beta.381] - 2025-01-17
-
-### 🚀 Features
-
-- Able to import full db backups for pg/mysql/mariadb
-- Restore backup from server file
-- Docker volume data cloning
-- Move volume data cloning to a Job
-- Volume cloning for ResourceOperations
-- Remote server volume cloning
-- Add horizon server details to queue
-- Enhance horizon:manage command with worker restart check
-- Add is_coolify_host to the server api responses
-- DB migration for Backup retention
-- UI for backup retention settings
-- New global s3 and local backup deletion function
-- Use new backup deletion functions
-- Add calibre-web service
-- Add actual-budget service
-- Add rallly service
-- Template for Gotenberg, a Docker-powered stateless API for PDF files
-- Enhance import command options with additional guidance and improved checkbox label
-- Purify for better sanitization
-- Move docker cleanup to its own tab
-- DB and Model for docker cleanup executions
-- DockerCleanupExecutions relationship
-- DockerCleanupDone event
-- Get command and output for logs from CleanupDocker
-- New sidebar menu and order
-- Docker cleanup executions UI
-- Add execution log to dockerCleanupJob
-- Improve deployment UI
-- Root user envs and seeding
-- Email, username and password validation when they are set via envs
-- Improved error handling and log output
-- Add root user configuration variables to production environment
-
-### 🐛 Bug Fixes
-
-- Compose envs
-- Scheduled tasks and backups are executed by server timezone.
-- Show backup timezone on the UI
-- Disappearing UI after livewire event received
-- Add default vector db for anythingllm
-- We need XSRF-TOKEN for terminal
-- Prevent default link behavior for resource and settings actions in dashboard
-- Increase default php memory limit
-- Show if only build servers are added to your team
-- Update Livewire button click method to use camelCase
-- Local dropzonejs
-- Import backups due to js stuff should not be navigated
-- Install inetutils on Arch Linux
-- Use ip in place of hostname from inetutils in arch
-- Update import command to append file redirection for database restoration
-- Ui bug on pw confirmation
-- Exclude system and computed fields from model replication
-- Service cloning on a separate server
-- Application cloning
-- `Undefined variable $fs_path` for databases
-- Service and database cloning and label generation
-- Labels and URL generation when cloning
-- Clone naming for different database data volumes
-- Implement all the cloneMe changes for ResourceOperations as well
-- Volume and fileStorages cloning
-- View text and helpers
-- Teable
-- Trigger with external db
-- Set `EXPERIMENTAL_FEATURES` to false for labelstudio
-- Monaco editor disabled state
-- Edge case where executions could be null
-- Create destination properly
-- Getcontainer status should timeout after 30s
-- Enable response for temporary unavailability in sentinel push endpoint
-- Use timeout in cleanup resources
-- Add timeout to sentinel process checks for improved reliability
-- Horizon job checker
-- Update response message for sentinel push route
-- Add own servers on cloud
-- Application deployment
-- Service update statsu
-- If $SERVICE found in the service specific configuration, then search for it in the db
-- Instance wide GitHub apps are not available on other teams then the source team
-- Function calls
-- UI
-- Deletion of single backup
-- Backup job deletion - delete all backups from s3 and local
-- Use new removeOldBackups function
-- Retention functions and folder deletion for local backups
-- Storage retention setting
-- Db without s3 should still backup
-- Wording
-- `Undefined variable $service` when creating a new service
-- Nodebb service
-- Calibre-web service
-- Rallly and actualbudget service
-- Removed container_name
-- Added healthcheck for gotenberg template
-- Gotenberg
-- *(template)* Gotenberg healthcheck, use /health instead of /version
-- Use wire:navigate on sidebar
-- Use wire:navigate on dashboard
-- Use wire:navigate on projects page
-- More wire:navigate
-- Even more wire:navigate
-- Service navigation
-- Logs icons everywhere + terminal
-- Redis DB should use the new resourceable columns
-- Joomla service
-- Add back letters to prod password requirement
-- Check System and GitHub time and throw and error if it is over 50s out of sync
-- Error message and server time getting
-- Error rendering
-- Render html correctly now
-- Indent
-- Potential fix for permissions update
-- Expiration time claim ('exp') must be a numeric value
-- Sanitize html error messages
-- Production password rule and cleanup code
-- Use json as it is just better than string for huge amount of logs
-- Use `wire:navigate` on server sidebar
-- Use finished_at for the end time instead of created_at
-- Cancelled deployments should not show end and duration time
-- Redirect to server index instead of show on error in Advanced and DockerCleanup components
-- Disable registration after creating the root user
-- RootUserSeeder
-- Regex username validation
-- Add spacing around echo outputs
-- Success message
-- Silent return if envs are empty or not set.
-
-### 💼 Other
-
-- Arrrrr
-- Dep
-- Docker dep
-
-### 🚜 Refactor
-
-- Rename parameter in DatabaseBackupJob for clarity
-- Improve checkbox component accessibility and styling
-- Remove unused tags method from ApplicationDeploymentJob
-- Improve deployment status check in isAnyDeploymentInprogress function
-- Extend HorizonServiceProvider from HorizonApplicationServiceProvider
-- Streamline job status retrieval and clean up repository interface
-- Enhance ApplicationDeploymentJob and HorizonServiceProvider for improved job handling
-- Remove commented-out unsubscribe route from API
-- Update redirect calls to use a consistent navigation method in deployment functions
-- AppServiceProvider
-- Github.php
-- Improve data formatting and UI
-
-### ⚙️ Miscellaneous Tasks
-
-- Improve Penpot healthchecks
-- Switch up readonly lables to make more sense
-- Remove unused computed fields
-- Use the new job dispatch
-- Disable volume data cloning for now
-- Improve code
-- Lowcoder service naming
-- Use new functions
-- Improve error styling
-- Css
-- More css as it still looks like shit
-- Final css touches
-- Ajust time to 50s (tests done)
-- Remove debug log, finally found it
-- Remove more logging
-- Remove limit on commit message
-- Remove dayjs
-- Remove unused code and fix import
-
-## [4.0.0-beta.380] - 2024-12-27
-
-### 🚀 Features
-
-- New ServerReachabilityChanged event
-- Use new ServerReachabilityChanged event instead of isDirty
-- Add infomaniak oauth
-- Add server disk usage check frequency
-- Add environment_uuid support and update API documentation
-- Add service/resource/project labels
-- Add coolify.environment label
-- Add database subtype
-- Migrate to new encryption options
-- New encryption options
-
-### 🐛 Bug Fixes
-
-- Render html on error page correctly
-- Invalid API response on missing project
-- Applications API response code + schema
-- Applications API writing to unavailable models
-- If an init script is renamed the old version is still on the server
-- Oauthseeder
-- Compose loading seq
-- Resource clone name + volume name generation
-- Update Dockerfile entrypoint path to /etc/entrypoint.d
-- Debug mode
-- Unreachable notifications
-- Remove duplicated ServerCheckJob call
-- Few fixes and use new ServerReachabilityChanged event
-- Use serverStatus not just status
-- Oauth seeder
-- Service ui structure
-- Check port 8080 and fallback to 80
-- Refactor database view
-- Always use docker cleanup frequency
-- Advanced server UI
-- Html css
-- Fix domain being override when update application
-- Use nixpacks predefined build variables, but still could update the default values from Coolify
-- Use local monaco-editor instead of Cloudflare
-- N8n timezone
-- Smtp encryption
-- Bind() to 0.0.0.0:80 failed
-- Oauth seeder
-- Unreachable notifications
-- Instance settings migration
-- Only encrypt instance email settings if there are any
-- Error message
-- Update healthcheck and port configurations to use port 8080
-
-### 🚜 Refactor
-
-- Rename `coolify.environment` to `coolify.environmentName`
-
-### ⚙️ Miscellaneous Tasks
-
-- Regenerate API spec, removing notification fields
-- Remove ray debugging
-- Version ++
-
-## [4.0.0-beta.378] - 2024-12-13
-
-### 🐛 Bug Fixes
-
-- Monaco editor light and dark mode switching
-- Service status indicator + oauth saving
-- Socialite for azure and authentik
-- Saving oauth
-- Fallback for copy button
-- Copy the right text
-- Maybe fallback is now working
-- Only show copy button on secure context
-
-## [4.0.0-beta.377] - 2024-12-13
-
-### 🚀 Features
-
-- Add deploy-only token permission
-- Able to deploy without cache on every commit
-- Update private key nam with new slug as well
-- Allow disabling default redirect, set status to 503
-- Add TLS configuration for default redirect in Server model
-- Slack notifications
-- Introduce root permission
-- Able to download schedule task logs
-- Migrate old email notification settings from the teams table
-- Migrate old discord notification settings from the teams table
-- Migrate old telegram notification settings from the teams table
-- Add slack notifications to a new table
-- Enable success messages again
-- Use new notification stuff inside team model
-- Some more notification settings and better defaults
-- New email notification settings
-- New shared function name `is_transactional_emails_enabled()`
-- New shared notifications functions
-- Email Notification Settings Model
-- Telegram notification settings Model
-- Discord notification settings Model
-- Slack notification settings Model
-- New Discord notification UI
-- New Slack notification UI
-- New telegram UI
-- Use new notification event names
-- Always sent notifications
-- Scheduled task success notification
-- Notification trait
-- Get discord Webhook form new table
-- Get Slack Webhook form new table
-- Use new table or instance settings for email
-- Use new place for settings and topic IDs for telegram
-- Encrypt instance email settings
-- Use encryption in instance settings model
-- Scheduled task success and failure notifications
-- Add docker cleanup success and failure notification settings columns
-- UI for docker cleanup success and failure notification
-- Docker cleanup email views
-- Docker cleanup success and failure notification files
-- Scheduled task success email
-- Send new docker cleanup notifications
-- :passport_control: integrate Authentik authentication with Coolify
-- *(notification)* Add Pushover
-- Add seeder command and configuration for database seeding
-- Add new password magic env with symbols
-- Add documenso service
-
-### 🐛 Bug Fixes
-
-- Resolve undefined searchInput reference in Alpine.js component
-- URL and sync new app name
-- Typos and naming
-- Client and webhook secret disappear after sync
-- Missing `mysql_password` API property
-- Incorrect MongoDB init API property
-- Old git versions does not have --cone implemented properly
-- Don't allow editing traefik config
-- Restart proxy
-- Dev mode
-- Ui
-- Display actual values for disk space checks in installer script
-- Proxy change behaviour
-- Add warning color
-- Import NotificationSlack correctly
-- Add middleware to new abilities, better ux for selecting permissions, etc.
-- Root + read:sensive could read senstive data with a middlewarew
-- Always have download logs button on scheduled tasks
-- Missing css
-- Development image
-- Dockerignore
-- DB migration error
-- Drop all unused smtp columns
-- Backward compatibility
-- Email notification channel enabled function
-- Instance email settins
-- Make sure resend is false if SMTP is true and vice versa
-- Email Notification saving
-- Slack and discord url now uses text filed because encryption makes the url very long
-- Notification trait
-- Encryption fixes
-- Docker cleanup email template
-- Add missing deployment notifications to telegram
-- New docker cleanup settings are now saved to the DB correctly
-- Ui + migrations
-- Docker cleanup email notifications
-- General notifications does not go through email channel
-- Test notifications to only send it to the right channel
-- Remove resale_license from db as well
-- Nexus service
-- Fileflows volume names
-- --cone
-- Provider error
-- Database migration
-- Seeder
-- Migration call
-- Slack helper
-- Telegram helper
-- Discord helper
-- Telegram topic IDs
-- Make pushover settings more clear
-- Typo in pushover user key
-- Use Livewire refresh method and lock properties
-- Create pushover settings for existing teams
-- Update token permission check from 'write' to 'root'
-- Pushover
-- Oauth seeder
-- Correct heading display for OAuth settings in settings-oauth.blade.php
-- Adjust spacing in login form for improved layout
-- Services env values should be sensitive
-- Documenso
-- Dolibarr
-- Typo
-- Update OauthSettingSeeder to handle new provider definitions and ensure authentik is recreated if missing
-- Improve OauthSettingSeeder to correctly delete non-existent providers and ensure proper handling of provider definitions
-- Encrypt resend API key in instance settings
-- Resend api key is already a text column
-
-### 💼 Other
-
-- Test rename GitHub app
-- Checkmate service and fix prowlar slogan (too long)
-
-### 🚜 Refactor
-
-- Update Traefik configuration for improved security and logging
-- Improve proxy configuration and code consistency in Server model
-- Rename name method to sanitizedName in BaseModel for clarity
-- Improve migration command and enhance application model with global scope and status checks
-- Unify notification icon
-- Remove unused Azure and Authentik service configurations from services.php
-- Change email column types in instance_settings migration from string to text
-- Change OauthSetting creation to updateOrCreate for better handling of existing records
-
-### ⚙️ Miscellaneous Tasks
-
-- Regenerate openapi spec
-- Composer dep bump
-- Dep bump
-- Upgrade cloudflared and minio
-- Remove comments and improve DB column naming
-- Remove unused seeder
-- Remove unused waitlist stuff
-- Remove wired.php (not used anymore)
-- Remove unused resale license job
-- Remove commented out internal notification
-- Remove more waitlist stuff
-- Remove commented out notification
-- Remove more waitlist stuff
-- Remove unused code
-- Fix typo
-- Remove comment out code
-- Some reordering
-- Remove resale license reference
-- Remove functions from shared.php
-- Public settings for email notification
-- Remove waitlist redirect
-- Remove log
-- Use new notification trait
-- Remove unused route
-- Remove unused email component
-- Comment status changes as it is disabled for now
-- Bump dep
-- Reorder navbar
-- Rename topicID to threadId like in the telegram API response
-- Update PHP configuration to set memory limit using environment variable
-
-## [4.0.0-beta.376] - 2024-12-07
-
-### 🐛 Bug Fixes
-
-- Api endpoint
-
-## [4.0.0-beta.374] - 2024-12-03
-
-### 🐛 Bug Fixes
-
-- Application view loading
-- Postiz service
-- Only able to select the right keys
-- Test email should not be required
-- A few inputs
-
-### 🧪 Testing
-
-- Setup database for upcoming tests
-
-## [4.0.0-beta.372] - 2024-11-26
-
-### 🚀 Features
-
-- Add MacOS template
-- Add Windows template
-- *(service)* :sparkles: add mealie
-- Add hex magic env var
-
-### 🐛 Bug Fixes
-
-- Service generate includes yml files as well (haha)
-- ServercheckJob should run every 5 minutes on cloud
-- New resource icons
-- Search should be more visible on scroll on new resource
-- Logdrain settings
-- Ui
-- Email should be retried with backoff
-- Alpine in body layout
-
-### 💼 Other
-
-- Caddy docker labels do not honor "strip prefix" option
-
-## [4.0.0-beta.371] - 2024-11-22
-
-### 🐛 Bug Fixes
-
-- Improve helper text for metrics input fields
-- Refine helper text for metrics input fields
-- If mux conn fails, still use it without mux + save priv key with better logic
-- Migration
-- Always validate ssh key
-- Make sure important jobs/actions are running on high prio queue
-- Do not send internal notification for backups and status jobs
-- Validateconnection
-- View issue
-- Heading
-- Remove mux cleanup
-- Db backup for services
-- Version should come from constants + fix stripe webhook error reporting
-- Undefined variable
-- Remove version.php as everything is coming from constants.php
-- Sentry error
-- Websocket connections autoreconnect
-- Sentry error
-- Sentry
-- Empty server API response
-- Incorrect server API patch response
-- Missing `uuid` parameter on server API patch
-- Missing `settings` property on servers API
-- Move servers API `delete_unused_*` properties
-- Servers API returning `port` as a string -> integer
-- Only return server uuid on server update
-
-## [4.0.0-beta.370] - 2024-11-15
-
-### 🐛 Bug Fixes
-
-- Modal (+ add) on dynamic config was not opening, removed x-cloak
-- AUTOUPDATE + checkbox opacity
-
-## [4.0.0-beta.369] - 2024-11-15
-
-### 🐛 Bug Fixes
-
-- Modal-input
-
-## [4.0.0-beta.368] - 2024-11-15
-
-### 🚀 Features
-
-- Check local horizon scheduler deployments
-- Add internal api docs to /docs/api with auth
-- Add proxy type change to create/update apis
-
-### 🐛 Bug Fixes
-
-- Show proper error message on invalid Git source
-- Convert HTTP to SSH source when using deploy key on GitHub
-- Cloud + stripe related
-- Terminal view loading in async
-- Cool 500 error (thanks hugodos)
-- Update schema in code decorator
-- Openapi docs
-- Add tests for git url converts
-- Minio / logto url generation
-- Admin view
-- Min docker version 26
-- Pull latest service-templates.json on init
-- Workflow files for coolify build
-- Autocompletes
-- Timezone settings validation
-- Invalid tz should not prevent other jobs to be executed
-- Testing-host should be built locally
-- Poll with modal issue
-- Terminal opening issue
-- If service img not found, use github as a source
-- Fallback to local coolify.png
-- Gather private ips
-- Cf tunnel menu should be visible when server is not validated
-- Deployment optimizations
-- Init script + optimize laravel
-- Default docker engine version + fix install script
-- Pull helper image on init
-- SPA static site default nginx conf
-
-### 💼 Other
-
-- Https://github.com/coollabsio/coolify/issues/4186
-- Separate resources by type in projects view
-- Improve s3 add view
-
-### ⚙️ Miscellaneous Tasks
-
-- Update dep
-
-## [4.0.0-beta.365] - 2024-11-11
-
-### 🚀 Features
-
-- Custom nginx configuration for static deployments + fix 404 redirects in nginx conf
-
-### 🐛 Bug Fixes
-
-- Trigger.dev db host & sslmode=disable
-- Manual update should be executed only once + better UX
-- Upgrade.sh
-- Missing privateKey
-
-## [4.0.0-beta.364] - 2024-11-08
-
-### 🐛 Bug Fixes
-
-- Define separate volumes for mattermost service template
-- Github app name is too long
-- ServerTimezone update
-
-### ⚙️ Miscellaneous Tasks
-
-- Edit www helper
-
-## [4.0.0-beta.363] - 2024-11-08
-
-### 🚀 Features
-
-- Add Firefox template
-- Add template for Wiki.js
-- Add upgrade logs to /data/coolify/source
-
-### 🐛 Bug Fixes
-
-- Saving resend api key
-- Wildcard domain save
-- Disable cloudflare tunnel on "localhost"
-
-## [4.0.0-beta.362] - 2024-11-08
-
-### 🐛 Bug Fixes
-
-- Notifications ui
-- Disable wire:navigate
-- Confirmation Settings css for light mode
-- Server wildcard
-
-## [4.0.0-beta.361] - 2024-11-08
-
-### 🚀 Features
-
-- Add Transmission template
-- Add transmission healhcheck
-- Add zipline template
-- Dify template
-- Required envs
-- Add EdgeDB
-- Show warning if people would like to use sslip with https
-- Add is shared to env variables
-- Variabel sync and support shared vars
-- Add notification settings to server_disk_usage
-- Add coder service tamplate and logo
-- Debug mode for sentinel
-- Add jitsi template
-- Add --gpu support for custom docker command
-
-### 🐛 Bug Fixes
-
-- Make sure caddy is not removed by cleanup
-- Libretranslate
-- Do not allow to change number of lines when streaming logs
-- Plunk
-- No manual timezones
-- Helper push
-- Format
-- Add port metadata and Coolify magic to generate the domain
-- Sentinel
-- Metrics
-- Generate sentinel url
-- Only enable Sentinel for new servers
-- Is_static through API
-- Allow setting standalone redis variables via ENVs (team variables...)
-- Check for username separately form password
-- Encrypt all existing redis passwords
-- Pull helper image on helper_version change
-- Redis database user and password
-- Able to update ipv4 / ipv6 instance settings
-- Metrics for dbs
-- Sentinel start fixed
-- Validate sentinel custom URL when enabling sentinel
-- Should be able to reset labels in read-only mode with manual click
-- No sentinel for swarm yet
-- Charts ui
-- Volume
-- Sentinel config changes restarts sentinel
-- Disable sentinel for now
-- Disable Sentinel temporarily
-- Disable Sentinel temporarily for non-dev environments
-- Access team's github apps only
-- Admins should now invite owner
-- Add experimental flag
-- GenerateSentinelUrl method
-- NumberOfLines could be null
-- Login / register view
-- Restart sentinel once a day
-- Changing private key manually won't trigger a notification
-- Grammar for helper
-- Fix my own grammar
-- Add telescope only in dev mode
-- New way to update container statuses
-- Only run server storage every 10 mins if sentinel is not active
-- Cloud admin view
-- Queries in kernel.php
-- Lower case emails only
-- Change emails to lowercase on init
-- Do not error on update email
-- Always authenticate with lowercase emails
-- Dashboard refactor
-- Add min/max length to input/texarea
-- Remove livewire legacy from help view
-- Remove unnecessary endpoints (magic)
-- Transactional email livewire
-- Destinations livewire refactor
-- Refactor destination/docker view
-- Logdrains validation
-- Reworded
-- Use Auth(), add new db proxy stop event refactor clickhouse view
-- Add user/pw to db view
-- Sort servers by name
-- Keydb view
-- Refactor tags view / remove obsolete one
-- Send discord/telegram notifications on high job queue
-- Server view refresh on validation
-- ShowBoarding
-- Show docker installation logs & ubuntu 24.10 notification
-- Do not overlap servercheckjob
-- Server limit check
-- Server validation
-- Clear route / view
-- Only skip docker installation on 24.10 if its not installed
-- For --gpus device support
-- Db/service start should be on high queue
-- Do not stop sentinel on Coolify restart
-- Run resourceCheck after new serviceCheckJob
-- Mongodb in dev
-- Better invitation errors
-- Loading indicator for db proxies
-- Do not execute gh workflow on template changes
-- Only use sentry in cloud
-- Update packagejson of coolify-realtime + add lock file
-- Update last online with old function
-- Seeder should not start sentinel
-- Start sentinel on seeder
-
-### 💼 Other
-
-- Add peppermint
-- Loggy
-- Add UI for redis password and username
-- Wireguard-easy template
-
-### 📚 Documentation
-
-- Update link to deploy api docs
-
-### ⚙️ Miscellaneous Tasks
-
-- Add transmission template desc
-- Update transmission docs link
-- Update version numbers to 4.0.0-beta.360 in configuration files
-- Update AWS environment variable names in unsend.yaml
-- Update AWS environment variable names in unsend.yaml
-- Update livewire/livewire dependency to version 3.4.9
-- Update version to 4.0.0-beta.361
-- Update Docker build and push actions to v6
-- Update Docker build and push actions to v6
-- Update Docker build and push actions to v6
-- Sync coolify-helper to dockerhub as well
-- Push realtime to dockerhub
-- Sync coolify-realtime to dockerhub
-- Rename workflows
-- Rename development to staging build
-- Sync coolify-testing-host to dockerhbu
-- Sync coolify prod image to dockerhub as well
-- Update Docker version to 26.0
-- Update project resource index page
-- Update project service configuration view
-
-## [4.0.0-beta.360] - 2024-10-11
-
-### ⚙️ Miscellaneous Tasks
-
-- Update livewire/livewire dependency to version 3.4.9
-
-## [4.0.0-beta.359] - 2024-10-11
-
-### 🐛 Bug Fixes
-
-- Use correct env variable for invoice ninja password
-
-### ⚙️ Miscellaneous Tasks
-
-- Update laravel/horizon dependency to version 5.29.1
-- Update service extra fields to use dynamic keys
-
-## [4.0.0-beta.358] - 2024-10-10
-
-### 🚀 Features
-
-- Add customHelper to stack-form
-- Add cloudbeaver template
-- Add ntfy template
-- Add qbittorrent template
-- Add Homebox template
-- Add owncloud service and logo
-- Add immich service
-- Auto generate url
-- Refactored to work with coolify auto env vars
-- Affine service template and logo
-- Add LibreTranslate template
-- Open version in a new tab
-
-### 🐛 Bug Fixes
-
-- Signup
-- Application domains should be http and https only
-- Validate and sanitize application domains
-- Sanitize and validate application domains
-
-### 💼 Other
-
-- Other DB options for freshrss
-- Nextcloud MariaDB and MySQL versions
-
-### ⚙️ Miscellaneous Tasks
-
-- Fix form submission and keydown event handling in modal-confirmation.blade.php
-- Update version numbers to 4.0.0-beta.359 in configuration files
-- Disable adding default environment variables in shared.php
-
-## [4.0.0-beta.357] - 2024-10-08
-
-### 🚀 Features
-
-- Add Mautic 4 and 5 to service templates
-- Add keycloak template
-- Add onedev template
-- Improve search functionality in project selection
-
-### 🐛 Bug Fixes
-
-- Update mattermost image tag and add default port
-- Remove env, change timezone
-- Postgres healthcheck
-- Azimutt template - still not working haha
-- New parser with SERVICE_URL_ envs
-- Improve service template readability
-- Update password variables in Service model
-- Scheduled database server
-- Select server view
-
-### 💼 Other
-
-- Keycloak
-
-### ⚙️ Miscellaneous Tasks
-
-- Add mattermost logo as svg
-- Add mattermost svg to compose
-- Update version to 4.0.0-beta.357
-
-## [4.0.0-beta.356] - 2024-10-07
-
-### 🚀 Features
-
-- Add Argilla service configuration to Service model
-- Add Invoice Ninja service configuration to Service model
-- Project search on frontend
-- Add ollama service with open webui and logo
-- Update setType method to use slug value for type
-- Refactor setType method to use slug value for type
-- Refactor setType method to use slug value for type
-- Add Supertokens template
-- Add easyappointments service template
-- Add dozzle template
-- Adds forgejo service with runners
-
-### 🐛 Bug Fixes
-
-- Reset description and subject fields after submitting feedback
-- Tag mass redeployments
-- Service env orders, application env orders
-- Proxy conf in dev
-- One-click services
-- Use local service-templates in dev
-- New services
-- Remove not used extra host
-- Chatwoot service
-- Directus
-- Database descriptions
-- Update services
-- Soketi
-- Select server view
-
-### 💼 Other
-
-- Update helper version
-- Outline
-- Directus
-- Supertokens
-- Supertokens json
-- Rabbitmq
-- Easyappointments
-- Soketi
-- Dozzle
-- Windmill
-- Coolify.json
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.356
-- Remove commented code for shared variable type validation
-- Update MariaDB image to version 11 and fix service environment variable orders
-- Update anythingllm.yaml volumes configuration
-- Update proxy configuration paths for Caddy and Nginx in dev
-- Update password form submission in modal-confirmation component
-- Update project query to order by name in uppercase
-- Update project query to order by name in lowercase
-- Update select.blade.php with improved search functionality
-- Add Nitropage service template and logo
-- Bump coolify-helper version to 1.0.2
-- Refactor loadServices2 method and remove unused code
-- Update version to 4.0.0-beta.357
-- Update service names and volumes in windmill.yaml
-- Update version to 4.0.0-beta.358
-- Ignore .ignition.json files in Docker and Git
-
-## [4.0.0-beta.355] - 2024-10-03
-
-### 🐛 Bug Fixes
-
-- Scheduled backup for services view
-- Parser, espacing container labels
-
-### ⚙️ Miscellaneous Tasks
-
-- Update homarr service template and remove unnecessary code
-- Update version to 4.0.0-beta.355
-
-## [4.0.0-beta.354] - 2024-10-03
-
-### 🚀 Features
-
-- Add it-tools service template and logo
-- Add homarr service tamplate and logo
-
-### 🐛 Bug Fixes
-
-- Parse proxy config and check the set ports usage
-- Update FQDN
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.354
-- Remove debug statement in Service model
-- Remove commented code in Server model
-- Fix application deployment queue filter logic
-- Refactor modal-confirmation component
-- Update it-tools service template and port configuration
-- Update homarr service template and remove unnecessary code
-
-## [4.0.0-beta.353] - 2024-10-03
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.353
-- Update service application view
-
-## [4.0.0-beta.352] - 2024-10-03
-
-### 🐛 Bug Fixes
-
-- Service application view
-- Add new supported database images
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.352
-- Refactor DatabaseBackupJob to handle missing team
-
-## [4.0.0-beta.351] - 2024-10-03
-
-### 🚀 Features
-
-- Add strapi template
-
-### 🐛 Bug Fixes
-
-- Able to support more database dynamically from Coolify's UI
-- Strapi template
-- Bitcoin core template
-- Api useBuildServer
-
-## [4.0.0-beta.349] - 2024-10-01
-
-### 🚀 Features
-
-- Add command to check application deployment queue
-- Support Hetzner S3
-- Handle HTTPS domain in ConfigureCloudflareTunnels
-- Backup all databases for mysql,mariadb,postgresql
-- Restart service without pulling the latest image
-
-### 🐛 Bug Fixes
-
-- Remove autofocuses
-- Ipv6 scp should use -6 flag
-- Cleanup stucked applicationdeploymentqueue
-- Realtime watch in development mode
-- Able to select root permission easier
-
-### 💼 Other
-
-- Show backup button on supported db service stacks
-
-### 🚜 Refactor
-
-- Remove deployment queue when deleting an application
-- Improve SSH command generation in Terminal.php and terminal-server.js
-- Fix indentation in modal-confirmation.blade.php
-- Improve parsing of commands for sudo in parseCommandsByLineForSudo
-- Improve popup component styling and button behavior
-- Encode delimiter in SshMultiplexingHelper
-- Remove inactivity timer in terminal-server.js
-- Improve socket reconnection interval in terminal.js
-- Remove unnecessary watch command from soketi service entrypoint
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version numbers to 4.0.0-beta.350 in configuration files
-- Update command signature and description for cleanup application deployment queue
-- Add missing import for Attribute class in ApplicationDeploymentQueue model
-- Update modal input in server form to prevent closing on outside click
-- Remove unnecessary command from SshMultiplexingHelper
-- Remove commented out code for uploading to S3 in DatabaseBackupJob
-- Update soketi service image to version 1.0.3
-
-## [4.0.0-beta.348] - 2024-10-01
-
-### 🚀 Features
-
-- Update resource deletion job to allow configurable options through API
-- Add query parameters for deleting configurations, volumes, docker cleanup, and connected networks
-
-### 🐛 Bug Fixes
-
-- In dev mode do not ask confirmation on delete
-- Mixpost
-- Handle deletion of 'hello' in confirmation modal for dev environment
-
-### 💼 Other
-
-- Server storage check
-
-### 🚜 Refactor
-
-- Update search input placeholder in resource index view
-
-### ⚙️ Miscellaneous Tasks
-
-- Fix docs link in running state
-- Update Coolify Realtime workflow to only trigger on the main branch
-- Refactor instanceSettings() function to improve code readability
-- Update Coolify Realtime image to version 1.0.2
-- Remove unnecessary code in DatabaseBackupJob.php
-- Add "Not Usable" indicator for storage items
-- Refactor instanceSettings() function and improve code readability
-- Update version numbers to 4.0.0-beta.349 and 4.0.0-beta.350
-
-## [4.0.0-beta.347] - 2024-09-28
-
-### 🚀 Features
-
-- Allow specify use_build_server when creating/updating an application
-- Add support for `use_build_server` in API endpoints for creating/updating applications
-- Add Mixpost template
-
-### 🐛 Bug Fixes
-
-- Filebrowser template
-- Edit is_build_server_enabled upon creating application on other application type
-- Save settings after assigning value
-
-### 💼 Other
-
-- Remove memlock as it caused problems for some users
-
-### ⚙️ Miscellaneous Tasks
-
-- Update Mailpit logo to use SVG format
-
-## [4.0.0-beta.346] - 2024-09-27
-
-### 🚀 Features
-
-- Add ContainerStatusTypes enum for managing container status
-
-### 🐛 Bug Fixes
-
-- Proxy fixes
-- Proxy
-- *(templates)* Filebrowser FQDN env variable
-- Handle edge case when build variables and env variables are in different format
-- Compose based terminal
-
-### 💼 Other
-
-- Manual cleanup button and unused volumes and network deletion
-- Force helper image removal
-- Use the new confirmation flow
-- Typo
-- Typo in install script
-- If API is disabeled do not show API token creation stuff
-- Disable API by default
-- Add debug bar
-
-### 🚜 Refactor
-
-- Update environment variable name for uptime-kuma service
-- Improve start proxy script to handle existing containers gracefully
-- Update delete server confirmation modal buttons
-- Remove unnecessary code
-
-### ⚙️ Miscellaneous Tasks
-
-- Add autocomplete attribute to input fields
-- Refactor API Tokens component to use isApiEnabled flag
-- Update versions.json file
-- Remove unused .env.development.example file
-- Update API Tokens view to include link to Settings menu
-- Update web.php to cast server port as integer
-- Update backup deletion labels to use language files
-- Update database startup heading title
-- Update database startup heading title
-- Custom vite envs
-- Update version numbers to 4.0.0-beta.348
-- Refactor code to improve SSH key handling and storage
-
-## [4.0.0-beta.343] - 2024-09-25
-
-### 🐛 Bug Fixes
-
-- Parser
-- Exited services statuses
-- Make sure to reload window if app status changes
-- Deploy key based deployments
-
-### 🚜 Refactor
-
-- Remove commented out code and improve environment variable handling in newParser function
-- Improve label positioning in input and checkbox components
-- Group and sort fields in StackForm by service name and password status
-- Improve layout and add checkbox for task enablement in scheduled task form
-- Update checkbox component to support full width option
-- Update confirmation label in danger.blade.php template
-- Fix typo in execute-container-command.blade.php
-- Update OS_TYPE for Asahi Linux in install.sh script
-- Add localhost as Server if it doesn't exist and not in cloud environment
-- Add localhost as Server if it doesn't exist and not in cloud environment
-- Update ProductionSeeder to fix issue with coolify_key assignment
-- Improve modal confirmation titles and button labels
-- Update install.sh script to remove redirection of upgrade output to /dev/null
-- Fix modal input closeOutside prop in configuration.blade.php
-- Add support for IPv6 addresses in sslip function
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version numbers to 4.0.0-beta.343
-- Update version numbers to 4.0.0-beta.344
-- Update version numbers to 4.0.0-beta.345
-- Update version numbers to 4.0.0-beta.346
-
-## [4.0.0-beta.342] - 2024-09-24
-
-### 🚀 Features
-
-- Add nullable constraint to 'fingerprint' column in private_keys table
-- *(api)* Add an endpoint to execute a command
-- *(api)* Add endpoint to execute a command
-
-### 🐛 Bug Fixes
-
-- Proxy status
-- Coolify-db should not be in the managed resources
-- Store original root key in the original location
-- Logto service
-- Cloudflared service
-- Migrations
-- Cloudflare tunnel configuration, ui, etc
-
-### 💼 Other
-
-- Volumes on development environment
-- Clean new volume name for dev volumes
-- Persist DBs, services and so on stored in data/coolify
-- Add SSH Key fingerprint to DB
-- Add a fingerprint to every private key on save, create...
-- Make sure invalid private keys can not be added
-- Encrypt private SSH keys in the DB
-- Add is_sftp and is_server_ssh_key coloums
-- New ssh key file name on disk
-- Store all keys on disk by default
-- Populate SSH key folder
-- Populate SSH keys in dev
-- Use new function names and logic everywhere
-- Create a Multiplexing Helper
-- SSH multiplexing
-- Remove unused code form multiplexing
-- SSH Key cleanup job
-- Private key with ID 2 on dev
-- Move more functions to the PrivateKey Model
-- Add ssh key fingerprint and generate one for existing keys
-- ID issues on dev seeders
-- Server ID 0
-- Make sure in use private keys are not deleted
-- Do not delete SSH Key from disk during server validation error
-- UI bug, do not write ssh key to disk in server dialog
-- SSH Multiplexing for Jobs
-- SSH algorhytm text
-- Few multiplexing things
-- Clear mux directory
-- Multiplexing do not write file manually
-- Integrate tow step process in the modal component WIP
-- Ability to hide labels
-- DB start, stop confirm
-- Del init script
-- General confirm
-- Preview deployments and typos
-- Service confirmation
-- Confirm file storage
-- Stop service confirm
-- DB image cleanup
-- Confirm ressource operation
-- Environment variabel deletion
-- Confirm scheduled tasks
-- Confirm API token
-- Confirm private key
-- Confirm server deletion
-- Confirm server settings
-- Proxy stop and restart confirmation
-- GH app deletion confirmation
-- Redeploy all confirmation
-- User deletion confirmation
-- Team deletion confirmation
-- Backup job confirmation
-- Delete volume confirmation
-- More conformations and fixes
-- Delete unused private keys button
-- Ray error because port is not uncommented
-- #3322 deploy DB alterations before updating
-- Css issue with advanced settings and remove cf tunnel in onboarding
-- New cf tunnel install flow
-- Made help text more clear
-- Cloudflare tunnel
-- Make helper text more clean to use a FQDN and not an URL
-
-### 🚜 Refactor
-
-- Update Docker cleanup label in Heading.php and Navbar.php
-- Remove commented out code in Navbar.php
-- Remove CleanupSshKeysJob from schedule in Kernel.php
-- Update getAJoke function to exclude offensive jokes
-- Update getAJoke function to use HTTPS for API request
-- Update CleanupHelperContainersJob to use more efficient Docker command
-- Update PrivateKey model to improve code readability and maintainability
-- Remove unnecessary code in PrivateKey model
-- Update PrivateKey model to use ownedByCurrentTeam() scope for cleanupUnusedKeys()
-- Update install.sh script to check if coolify-db volume exists before generating SSH key
-- Update ServerSeeder and PopulateSshKeysDirectorySeeder
-- Improve attribute sanitization in Server model
-- Update confirmation button text for deletion actions
-- Remove unnecessary code in shared.php file
-- Update environment variables for services in compose files
-- Update select.blade.php to improve trademarks policy display
-- Update select.blade.php to improve trademarks policy display
-- Fix typo in subscription URLs
-- Add Postiz service to compose file (disabled for now)
-- Update shared.php to include predefined ports for services
-- Simplify SSH key synchronization logic
-- Remove unused code in DatabaseBackupStatusJob and PopulateSshKeysDirectorySeeder
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version numbers to 4.0.0-beta.342
-- Update remove-labels-and-assignees-on-close.yml
-- Add SSH key for localhost in ProductionSeeder
-- Update SSH key generation in install.sh script
-- Update ProductionSeeder to call OauthSettingSeeder and PopulateSshKeysDirectorySeeder
-- Update install.sh to support Asahi Linux
-- Update install.sh version to 1.6
-- Remove unused middleware and uniqueId method in DockerCleanupJob
-- Refactor DockerCleanupJob to remove unused middleware and uniqueId method
-- Remove unused migration file for populating SSH keys and clearing mux directory
-- Add modified files to the commit
-- Refactor pre-commit hook to improve performance and readability
-- Update CONTRIBUTING.md with troubleshooting note about database migrations
-- Refactor pre-commit hook to improve performance and readability
-- Update cleanup command to use Redis instead of queue
-- Update Docker commands to start proxy
-
-## [4.0.0-beta.341] - 2024-09-18
-
-### 🚀 Features
-
-- Add buddy logo
-
-## [4.0.0-beta.336] - 2024-09-16
-
-### 🚀 Features
-
-- Make coolify full width by default
-- Fully functional terminal for command center
-- Custom terminal host
-
-### 🐛 Bug Fixes
-
-- Keep-alive ws connections
-- Add build.sh to debug logs
-- Update Coolify installer
-- Terminal
-- Generate https for minio
-- Install script
-- Handle WebSocket connection close in terminal.blade.php
-- Able to open terminal to any containers
-- Refactor run-command
-- If you exit a container manually, it should close the underlying tty as well
-- Move terminal to separate view on services
-- Only update helper image in DB
-- Generated fqdn for SERVICE_FQDN_APP_3000 magic envs
-
-### 💼 Other
-
-- Remove labels and assignees on issue close
-- Make sure this action is also triggered on PR issue close
-
-### 🚜 Refactor
-
-- Remove unnecessary code in ExecuteContainerCommand.php
-- Improve Docker network connection command in StartService.php
-- Terminal / run command
-- Add authorization check in ExecuteContainerCommand mount method
-- Remove unnecessary code in Terminal.php
-- Remove unnecessary code in Terminal.blade.php
-- Update WebSocket connection initialization in terminal.blade.php
-- Remove unnecessary console.log statements in terminal.blade.php
-
-### ⚙️ Miscellaneous Tasks
-
-- Update release version to 4.0.0-beta.336
-- Update coolify environment variable assignment with double quotes
-- Update shared.php to fix issues with source and network variables
-- Update terminal styling for better readability
-- Update button text for container connection form
-- Update Dockerfile and workflow for Coolify Realtime (v4)
-- Remove unused entrypoint script and update volume mapping
-- Update .env file and docker-compose configuration
-- Update APP_NAME environment variable in docker-compose.prod.yml
-- Update WebSocket URL in terminal.blade.php
-- Update Dockerfile and workflow for Coolify Realtime (v4)
-- Update Dockerfile and workflow for Coolify Realtime (v4)
-- Update Dockerfile and workflow for Coolify Realtime (v4)
-- Rename Command Center to Terminal in code and views
-- Update branch restriction for push event in coolify-helper.yml
-- Update terminal button text and layout in application heading view
-- Refactor terminal component and select form layout
-- Update coolify nightly version to 4.0.0-beta.335
-- Update helper version to 1.0.1
-- Fix syntax error in versions.json
-- Update version numbers to 4.0.0-beta.337
-- Update Coolify installer and scripts to include a function for fetching programming jokes
-- Update docker network connection command in ApplicationDeploymentJob.php
-- Add validation to prevent selecting 'default' server or container in RunCommand.php
-- Update versions.json to reflect latest version of realtime container
-- Update soketi image to version 1.0.1
-- Nightly - Update soketi image to version 1.0.1 and versions.json to reflect latest version of realtime container
-- Update version numbers to 4.0.0-beta.339
-- Update version numbers to 4.0.0-beta.340
-- Update version numbers to 4.0.0-beta.341
-
-### ◀️ Revert
-
-- Databasebackup
-
-## [4.0.0-beta.335] - 2024-09-12
-
-### 🐛 Bug Fixes
-
-- Cloudflare tunnel with new multiplexing feature
-
-### 💼 Other
-
-- SSH Multiplexing on docker desktop on Windows
-
-### ⚙️ Miscellaneous Tasks
-
-- Update release version to 4.0.0-beta.335
-- Update constants.ssh.mux_enabled in remoteProcess.php
-- Update listeners and proxy settings in server form and new server components
-- Remove unnecessary null check for proxy_type in generate_default_proxy_configuration
-- Remove unnecessary SSH command execution time logging
-
-## [4.0.0-beta.334] - 2024-09-12
-
-### ⚙️ Miscellaneous Tasks
-
-- Remove itsgoingd/clockwork from require-dev in composer.json
-- Update 'key' value of gitlab in Service.php to use environment variable
-
-## [4.0.0-beta.333] - 2024-09-11
-
-### 🐛 Bug Fixes
-
-- Disable mux_enabled during server validation
-- Move mc command to coolify image from helper
-- Keydb. add `:` delimiter for connection string
-
-### 💼 Other
-
-- Remote servers with port and user
-- Do not change localhost server name on revalidation
-- Release.md file
-
-### 🚜 Refactor
-
-- Improve handling of environment variable merging in upgrade script
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version numbers to 4.0.0-beta.333
-- Copy .env file to .env-{DATE} if it exists
-- Update .env file with new values
-- Update server check job middleware to use server ID instead of UUID
-- Add reminder to backup .env file before running install script again
-- Copy .env file to backup location during installation script
-- Add reminder to backup .env file during installation script
-- Update permissions in pr-build.yml and version numbers
-- Add minio/mc command to Dockerfile
-
-## [4.0.0-beta.332] - 2024-09-10
-
-### 🚀 Features
-
-- Expose project description in API response
-- Add elixir finetunes to the deployment job
-
-### 🐛 Bug Fixes
-
-- Reenable overlapping servercheckjob
-- Appwrite template + parser
-- Don't add `networks` key if `network_mode` is used
-- Remove debug statement in shared.php
-- Scp through cloudflare
-- Delete older versions of the helper image other than the latest one
-- Update remoteProcess.php to handle null values in logItem properties
-
-### 💼 Other
-
-- Set a default server timezone
-- Implement SSH Multiplexing
-- Enabel mux
-- Cleanup stale multiplexing connections
-
-### 🚜 Refactor
-
-- Improve environment variable handling in shared.php
-
-### ⚙️ Miscellaneous Tasks
-
-- Set timeout for ServerCheckJob to 60 seconds
-- Update appwrite.yaml to include OpenSSL key variable assignment
-
-## [4.0.0-beta.330] - 2024-09-06
-
-### 🐛 Bug Fixes
-
-- Parser
-- Plunk NEXT_PUBLIC_API_URI
-
-### 💼 Other
-
-- Pull helper image if not available otherwise s3 backup upload fails
-
-### 🚜 Refactor
-
-- Improve handling of server timezones in scheduled backups and tasks
-- Improve handling of server timezones in scheduled backups and tasks
-- Improve handling of server timezones in scheduled backups and tasks
-- Update cleanup schedule to run daily at midnight
-- Skip returning volume if driver type is cifs or nfs
-
-### ⚙️ Miscellaneous Tasks
-
-- Update coolify-helper.yml to get version from versions.json
-- Disable Ray by default
-- Enable Ray by default and update Dockerfile with latest versions of PACK and NIXPACKS
-- Update Ray configuration and Dockerfile
-- Add middleware for updating environment variables by UUID in `api.php` routes
-- Expose port 3000 in browserless.yaml template
-- Update Ray configuration and Dockerfile
-- Update coolify version to 4.0.0-beta.331
-- Update versions.json and sentry.php to 4.0.0-beta.332
-- Update version to 4.0.0-beta.332
-- Update DATABASE_URL in plunk.yaml to use plunk database
-- Add coolify.managed=true label to Docker image builds
-- Update docker image pruning command to exclude managed images
-- Update docker cleanup schedule to run daily at midnight
-- Update versions.json to version 1.0.1
-- Update coolify-helper.yml to include "next" branch in push trigger
-
-## [4.0.0-beta.326] - 2024-09-03
-
-### 🚀 Features
-
-- Update server_settings table to force docker cleanup
-- Update Docker Compose file with DB_URL environment variable
-- Refactor shared.php to improve environment variable handling
-
-### 🐛 Bug Fixes
-
-- Wrong executions order
-- Handle project not found error in environment_details API endpoint
-- Deployment running for - without "ago"
-- Update helper image pulling logic to only pull if the version is newer
-
-### 💼 Other
-
-- Plunk svg
-
-### 📚 Documentation
-
-- Update Plunk documentation link in compose/plunk.yaml
-
-### ⚙️ Miscellaneous Tasks
-
-- Update UI for displaying no executions found in scheduled task list
-- Update UI for displaying deployment status in deployment list
-- Update UI for displaying deployment status in deployment list
-- Ignore unnecessary files in production build workflow
-- Update server form layout and settings
-- Update Dockerfile with latest versions of PACK and NIXPACKS
-
-## [4.0.0-beta.324] - 2024-09-02
-
-### 🚀 Features
-
-- Preserve git repository with advanced file storages
-- Added Windmill template
-- Added Budibase template
-- Add shm-size for custom docker commands
-- Add custom docker container options to all databases
-- Able to select different postgres database
-- Add new logos for jobscollider and hostinger
-- Order scheduled task executions
-- Add Code Server environment variables to Service model
-- Add coolify build env variables to building phase
-- Add new logos for GlueOps, Ubicloud, Juxtdigital, Saasykit, and Massivegrid
-- Add new logos for GlueOps, Ubicloud, Juxtdigital, Saasykit, and Massivegrid
-
-### 🐛 Bug Fixes
-
-- Timezone not updated when systemd is missing
-- If volumes + file mounts are defined, should merge them together in the compose file
-- All mongo v4 backups should use the different backup command
-- Database custom environment variables
-- Connect compose apps to the right predefined network
-- Docker compose destination network
-- Server status when there are multiple servers
-- Sync fqdn change on the UI
-- Pr build names in case custom name is used
-- Application patch request instant_deploy
-- Canceling deployment on build server
-- Backup of password protected postgresql database
-- Docker cleanup job
-- Storages with preserved git repository
-- Parser parser parser
-- New parser only in dev
-- Parser parser
-- Numberoflines should be number
-- Docker cleanup job
-- Fix directory and file mount headings in file-storage.blade.php
-- Preview fqdn generation
-- Revert a few lines
-- Service ui sync bug
-- Setup script doesn't work on rhel based images with some curl variant already installed
-- Let's wait for healthy container during installation and wait an extra 20 seconds (for migrations)
-- Infra files
-- Log drain only for Applications
-- Copy large compose files through scp (not ssh)
-- Check if array is associative or not
-- Openapi endpoint urls
-- Convert environment variables to one format in shared.php
-- Logical volumes could be overwritten with new path
-- Env variable in value parsed
-- Pull coolify image only when the app needs to be updated
-
-### 💼 Other
-
-- Actually update timezone on the server
-- Cron jobs are executed based on the server timezone
-- Server timezone seeder
-- Recent backups UI
-- Use apt-get instead of apt
-- Typo
-- Only pull helper image if the version is newer than the one
-
-### 🚜 Refactor
-
-- Update event listeners in Show components
-- Refresh application to get latest database changes
-- Update RabbitMQ configuration to use environment variable for port
-- Remove debug statement in parseDockerComposeFile function
-- ParseServiceVolumes
-- Update OpenApi command to generate documentation
-- Remove unnecessary server status check in destination view
-- Remove unnecessary admin user email and password in budibase.yaml
-- Improve saving of custom internal name in Advanced.php
-- Add conditional check for volumes in generate_compose_file()
-- Improve storage mount forms in add.blade.php
-- Load environment variables based on resource type in sortEnvironmentVariables()
-- Remove unnecessary network cleanup in Init.php
-- Remove unnecessary environment variable checks in parseDockerComposeFile()
-- Add null check for docker_compose_raw in parseCompose()
-- Update dockerComposeParser to use YAML data from $yaml instead of $compose
-- Convert service variables to key-value pairs in parseDockerComposeFile function
-- Update database service name from mariadb to mysql
-- Remove unnecessary code in DatabaseBackupJob and BackupExecutions
-- Update Docker Compose parsing function to convert service variables to key-value pairs
-- Update Docker Compose parsing function to convert service variables to key-value pairs
-- Remove unused server timezone seeder and related code
-- Remove unused server timezone seeder and related code
-- Remove unused PullCoolifyImageJob from schedule
-- Update parse method in Advanced, All, ApplicationPreview, General, and ApplicationDeploymentJob classes
-- Remove commented out code for getIptables() in Dashboard.php
-- Update .env file path in install.sh script
-- Update SELF_HOSTED environment variable in docker-compose.prod.yml
-- Remove unnecessary code for creating coolify network in upgrade.sh
-- Update environment variable handling in StartClickhouse.php and ApplicationDeploymentJob.php
-- Improve handling of COOLIFY_URL in shared.php
-- Update build_args property type in ApplicationDeploymentJob
-- Update background color of sponsor section in README.md
-- Update Docker Compose location handling in PublicGitRepository
-- Upgrade process of Coolify
-
-### 🧪 Testing
-
-- More tests
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.324
-- New compose parser with tests
-- Update version to 1.3.4 in install.sh and 1.0.6 in upgrade.sh
-- Update memory limit to 64MB in horizon configuration
-- Update php packages
-- Update axios npm dependency to version 1.7.5
-- Update Coolify version to 4.0.0-beta.324 and fix file paths in upgrade script
-- Update Coolify version to 4.0.0-beta.324
-- Update Coolify version to 4.0.0-beta.325
-- Update Coolify version to 4.0.0-beta.326
-- Add cd command to change directory before removing .env file
-- Update Coolify version to 4.0.0-beta.327
-- Update Coolify version to 4.0.0-beta.328
-- Update sponsor links in README.md
-- Update version.json to versions.json in GitHub workflow
-- Cleanup stucked resources and scheduled backups
-- Update GitHub workflow to use versions.json instead of version.json
-- Update GitHub workflow to use versions.json instead of version.json
-- Update GitHub workflow to use versions.json instead of version.json
-- Update GitHub workflow to use jq container for version extraction
-- Update GitHub workflow to use jq container for version extraction
-
-## [4.0.0-beta.323] - 2024-08-08
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.323
-
-## [4.0.0-beta.322] - 2024-08-08
-
-### 🐛 Bug Fixes
-
-- Manual update process
-
-### 🚜 Refactor
-
-- Update Server model getContainers method to use collect() for containers and containerReplicates
-- Import ProxyTypes enum and use TRAEFIK instead of TRAEFIK_V2
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.322
-
-## [4.0.0-beta.321] - 2024-08-08
-
-### 🐛 Bug Fixes
-
-- Scheduledbackup not found
-
-### 🚜 Refactor
-
-- Update StandalonePostgresql database initialization and backup handling
-- Update cron expressions and add helper text for scheduled tasks
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.321
-
-## [4.0.0-beta.320] - 2024-08-08
-
-### 🚀 Features
-
-- Delete team in cloud without subscription
-- Coolify init should cleanup stuck networks in proxy
-- Add manual update check functionality to settings page
-- Update auto update and update check frequencies in settings
-- Update Upgrade component to check for latest version of Coolify
-- Improve homepage service template
-- Support map fields in Directus
-- Labels by proxy type
-- Able to generate only the required labels for resources
-
-### 🐛 Bug Fixes
-
-- Only append docker network if service/app is running
-- Remove lazy load from scheduled tasks
-- Plausible template
-- Service_url should not have a trailing slash
-- If usagebefore cannot be determined, cleanup docker with force
-- Async remote command
-- Only run logdrain if necessary
-- Remove network if it is only connected to coolify proxy itself
-- Dir mounts should have proper dirs
-- File storages (dir/file mount) handled properly
-- Do not use port exposes on docker compose buildpacks
-- Minecraft server template fixed
-- Graceful shutdown
-- Stop resources gracefully
-- Handle null and empty disk usage in DockerCleanupJob
-- Show latest version on manual update view
-- Empty string content should be saved as a file
-- Update Traefik labels on init
-- Add missing middleware for server check job
-
-### 🚜 Refactor
-
-- Update CleanupDatabase.php to adjust keep_days based on environment
-- Adjust keep_days in CleanupDatabase.php based on environment
-- Remove commented out code for cleaning up networks in CleanupDocker.php
-- Update livewire polling interval in heading.blade.php
-- Remove unused code for checking server status in Heading.php
-- Simplify log drain installation in ServerCheckJob
-- Remove unnecessary debug statement in ServerCheckJob
-- Simplify log drain installation and stop log drain if necessary
-- Cleanup unnecessary dynamic proxy configuration in Init command
-- Remove unnecessary debug statement in ApplicationDeploymentJob
-- Update timeout for graceful_shutdown_container in ApplicationDeploymentJob
-- Remove unused code and optimize CheckForUpdatesJob
-- Update ProxyTypes enum values to use TRAEFIK instead of TRAEFIK_V2
-- Update Traefik labels on init and cleanup unnecessary dynamic proxy configuration
-
-### 🎨 Styling
-
-- Linting
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.320
-- Add pull_request image builds to GH actions
-- Add comment explaining the purpose of disconnecting the network in cleanup_unused_network_from_coolify_proxy()
-- Update formbricks template
-- Update registration view to display a notice for first user that it will be an admin
-- Update server form to use password input for IP Address/Domain field
-- Update navbar to include service status check
-- Update navbar and configuration to improve service status check functionality
-- Update workflows to include PR build and merge manifest steps
-- Update UpdateCoolifyJob timeout to 10 minutes
-- Update UpdateCoolifyJob to dispatch CheckForUpdatesJob synchronously
-
-## [4.0.0-beta.319] - 2024-07-26
-
-### 🐛 Bug Fixes
-
-- Parse docker composer
-- Service env parsing
-- Service env variables
-- Activity type invalid
-- Update env on ui
-
-### 💼 Other
-
-- Service env parsing
-
-### ⚙️ Miscellaneous Tasks
-
-- Collect/create/update volumes in parseDockerComposeFile function
-
-## [4.0.0-beta.318] - 2024-07-24
-
-### 🚀 Features
-
-- Create/delete project endpoints
-- Add patch request to projects
-- Add server api endpoints
-- Add branddev logo to README.md
-- Update API endpoint summaries
-- Update Caddy button label in proxy.blade.php
-- Check custom internal name through server's applications.
-- New server check job
-
-### 🐛 Bug Fixes
-
-- Preview deployments should be stopped properly via gh webhook
-- Deleting application should delete preview deployments
-- Plane service images
-- Fix issue with deployment start command in ApplicationDeploymentJob
-- Directory will be created by default for compose host mounts
-- Restart proxy does not work + status indicator on the UI
-- Uuid in api docs type
-- Raw compose deployment .env not found
-- Api -> application patch endpoint
-- Remove pull always when uploading backup to s3
-- Handle array env vars
-- Link in task failed job notifications
-- Random generated uuid will be full length (not 7 characters)
-- Gitlab service
-- Gitlab logo
-- Bitbucket repository url
-- By default volumes that we cannot determine if they are directories or files are treated as directories
-- Domain update on services on the UI
-- Update SERVICE_FQDN/URL env variables when you change the domain
-- Several shared environment variables in one value, parsed correctly
-- Members of root team should not see instance admin stuff
-
-### 💼 Other
-
-- Formbricks template add required CRON_SECRET
-- Add required CRON_SECRET to Formbricks template
-
-### ⚙️ Miscellaneous Tasks
-
-- Update APP_BASE_URL to use SERVICE_FQDN_PLANE
-- Update resource-limits.blade.php with improved input field helpers
-- Update version numbers to 4.0.0-beta.319
-- Remove commented out code for docker image pruning
-
-## [4.0.0-beta.314] - 2024-07-15
-
-### 🚀 Features
-
-- Improve error handling in loadComposeFile method
-- Add readonly labels
-- Preserve git repository
-- Force cleanup server
-
-### 🐛 Bug Fixes
-
-- Typo in is_literal helper
-- Env is_literal helper text typo
-- Update docker compose pull command with --policy always
-- Plane service template
-- Vikunja
-- Docmost template
-- Drupal
-- Improve github source creation
-- Tag deployments
-- New docker compose parsing
-- Handle / in preselecting branches
-- Handle custom_internal_name check in ApplicationDeploymentJob.php
-- If git limit reached, ignore it and continue with a default selection
-- Backup downloads
-- Missing input for api endpoint
-- Volume detection (dir or file) is fixed
-- Supabase
-- Create file storage even if content is empty
-
-### 💼 Other
-
-- Add basedir + compose file in new compose based apps
-
-### 🚜 Refactor
-
-- Remove unused code and fix storage form layout
-- Update Docker Compose build command to include --pull flag
-- Update DockerCleanupJob to handle nullable usageBefore property
-- Server status job and docker cleanup job
-- Update DockerCleanupJob to use server settings for force cleanup
-- Update DockerCleanupJob to use server settings for force cleanup
-- Disable health check for Rust applications during deployment
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.315
-- Update version to 4.0.0-beta.316
-- Update bug report template
-- Update repository form with simplified URL input field
-- Update width of container in general.blade.php
-- Update checkbox labels in general.blade.php
-- Update general page of apps
-- Handle JSON parsing errors in format_docker_command_output_to_json
-- Update Traefik image version to v2.11
-- Update version to 4.0.0-beta.317
-- Update version to 4.0.0-beta.318
-- Update helper message with link to documentation
-- Disable health check by default
-- Remove commented out code for sending internal notification
-
-### ◀️ Revert
-
-- Pull policy
-- Advanced dropdown
-
-## [4.0.0-beta.308] - 2024-07-11
-
-### 🚀 Features
-
-- Cleanup unused docker networks from proxy
-- Compose parser v2
-- Display time interval for rollback images
-- Add security and storage access key env to twenty template
-- Add new logo for Latitude
-- Enable legacy model binding in Livewire configuration
-
-### 🐛 Bug Fixes
-
-- Do not overwrite hardcoded variables if they rely on another variable
-- Remove networks when deleting a docker compose based app
-- Api
-- Always set project name during app deployments
-- Remove volumes as well
-- Gitea pr previews
-- Prevent instance fqdn persisting to other servers dynamic proxy configs
-- Better volume cleanups
-- Cleanup parameter
-- Update redirect URL in unauthenticated exception handler
-- Respect top-level configs and secrets
-- Service status changed event
-- Disable sentinel until a few bugs are fixed
-- Service domains and envs are properly updated
-- *(reactive-resume)* New healthcheck command for MinIO
-- *(MinIO)* New command healthcheck
-- Update minio hc in services
-- Add validation for missing docker compose file
-
-### 🚜 Refactor
-
-- Add force parameter to StartProxy handle method
-- Comment out unused code for network cleanup
-- Reset default labels when docker_compose_domains is modified
-- Webhooks view
-- Tags view
-- Only get instanceSettings once from db
-- Update Dockerfile to set CI environment variable to true
-- Remove unnecessary code in AppServiceProvider.php
-- Update Livewire configuration views
-- Update Webhooks.php to use nullable type for webhook URLs
-- Add lazy loading to tags in Livewire configuration view
-- Update metrics.blade.php to improve alert message clarity
-- Update version numbers to 4.0.0-beta.312
-- Update version numbers to 4.0.0-beta.314
-
-### ⚙️ Miscellaneous Tasks
-
-- Update Plausible docker compose template to Plausible 2.1.0
-- Update Plausible docker compose template to Plausible 2.1.0
-- Update livewire/livewire dependency to version 3.4.9
-- Refactor checkIfDomainIsAlreadyUsed function
-- Update storage.blade.php view for livewire project service
-- Update version to 4.0.0-beta.310
-- Update composer dependencies
-- Add new logo for Latitude
-- Bump version to 4.0.0-beta.311
-
-### ◀️ Revert
-
-- Instancesettings
-
-## [4.0.0-beta.301] - 2024-06-24
-
-### 🚀 Features
-
-- Local fonts
-- More API endpoints
-- Bulk env update api endpoint
-- Update server settings metrics history days to 7
-- New app API endpoint
-- Private gh deployments through api
-- Lots of api endpoints
-- Api api api api api api
-- Rename CloudCleanupSubs to CloudCleanupSubscriptions
-- Early fraud warning webhook
-- Improve internal notification message for early fraud warning webhook
-- Add schema for uuid property in app update response
-
-### 🐛 Bug Fixes
-
-- Run user commands on high prio queue
-- Load js locally
-- Remove lemon + paddle things
-- Run container commands on high priority
-- Image logo
-- Remove both option for api endpoints. it just makes things complicated
-- Cleanup subs in cloud
-- Show keydbs/dragonflies/clickhouses
-- Only run cloud clean on cloud + remove root team
-- Force cleanup on busy servers
-- Check domain on new app via api
-- Custom container name will be the container name, not just internal network name
-- Api updates
-- Yaml everywhere
-- Add newline character to private key before saving
-- Add validation for webhook endpoint selection
-- Database input validators
-- Remove own app from domain checks
-- Return data of app update
-
-### 💼 Other
-
-- Update process
-- Glances service
-- Glances
-- Able to update application
-
-### 🚜 Refactor
-
-- Update Service model's saveComposeConfigs method
-- Add default environment to Service model's saveComposeConfigs method
-- Improve handling of default environment in Service model's saveComposeConfigs method
-- Remove commented out code in Service model's saveComposeConfigs method
-- Update stack-form.blade.php to include wire:target attribute for submit button
-- Update code to use str() instead of Str::of() for string manipulation
-- Improve formatting and readability of source.blade.php
-- Add is_build_time property to nixpacks_php_fallback_path and nixpacks_php_root_dir
-- Simplify code for retrieving subscription in Stripe webhook
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.302
-- Update version to 4.0.0-beta.303
-- Update version to 4.0.0-beta.305
-- Update version to 4.0.0-beta.306
-- Add log1x/laravel-webfonts package
-- Update version to 4.0.0-beta.307
-- Refactor ServerStatusJob constructor formatting
-- Update Monaco Editor for Docker Compose and Proxy Configuration
-- More details
-- Refactor shared.php helper functions
-
-## [4.0.0-beta.298] - 2024-06-24
-
-### 🚀 Features
-
-- Spanish translation
-- Cancelling a deployment will check if new could be started.
-- Add supaguide logo to donations section
-- Nixpacks now could reach local dbs internally
-- Add Tigris logo to other/logos directory
-- COOLIFY_CONTAINER_NAME predefined variable
-- Charts
-- Sentinel + charts
-- Container metrics
-- Add high priority queue
-- Add metrics warning for servers without Sentinel enabled
-- Add blacksmith logo to donations section
-- Preselect server and destination if only one found
-- More api endpoints
-- Add API endpoint to update application by UUID
-- Update statusnook logo filename in compose template
-
-### 🐛 Bug Fixes
-
-- Stripprefix middleware correctly labeled to http
-- Bitbucket link
-- Compose generator
-- Do no truncate repositories wtih domain (git) in it
-- In services should edit compose file for volumes and envs
-- Handle laravel deployment better
-- Db proxy status shown better in the UI
-- Show commit message on webhooks + prs
-- Metrics parsing
-- Charts
-- Application custom labels reset after saving
-- Static build with new nixpacks build process
-- Make server charts one livewire component with one interval selector
-- You can now add env variable from ui to services
-- Update compose environment with UI defined variables
-- Refresh deployable compose without reload
-- Remove cloud stripe notifications
-- App deployment should be in high queue
-- Remove zoom from modals
-- Get envs before sortby
-- MB is % lol
-- Projects with 0 envs
-
-### 💼 Other
-
-- Unnecessary notification
-
-### 🚜 Refactor
-
-- Update text color for stderr output in deployment show view
-- Update text color for stderr output in deployment show view
-- Remove debug code for saving environment variables
-- Update Docker build commands for better performance and flexibility
-- Update image sizes and add new logos to README.md
-- Update README.md with new logos and fix styling
-- Update shared.php to use correct key for retrieving sentinel version
-- Update container name assignment in Application model
-- Remove commented code for docker container removal
-- Update Application model to include getDomainsByUuid method
-- Update Project/Show component to sort environments by created_at
-- Update profile index view to display 2FA QR code in a centered container
-- Update dashboard.blade.php to use project's default environment for redirection
-- Update gitCommitLink method to handle null values in source.html_url
-- Update docker-compose generation to use multi-line literal block
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version numbers to 4.0.0-beta.298
-- Switch to database sessions from redis
-- Update dependencies and remove unused code
-- Update tailwindcss and vue versions in package.json
-- Update service template URL in constants.php
-- Update sentinel version to 0.0.8
-- Update chart styling and loading text
-- Update sentinel version to 0.0.9
-- Update Spanish translation for failed authentication messages
-- Add portuguese traslation
-- Add Turkish translations
-- Add Vietnamese translate
-- Add Treive logo to donations section
-- Update README.md with latest release version badge
-- Update latest release version badge in README.md
-- Update version to 4.0.0-beta.299
-- Move server delete component to the bottom of the page
-- Update version to 4.0.0-beta.301
-
-## [4.0.0-beta.297] - 2024-06-11
-
-### 🚀 Features
-
-- Easily redirect between www-and-non-www domains
-- Add logos for new sponsors
-- Add homepage template
-- Update homepage.yaml with environment variables and volumes
-
-### 🐛 Bug Fixes
-
-- Multiline build args
-- Setup script doesnt link to the correct source code file
-- Install.sh do not reinstall packages on arch
-- Just restart
-
-### 🚜 Refactor
-
-- Replaces duplications in code with a single function
-
-### ⚙️ Miscellaneous Tasks
-
-- Update page title in resource index view
-- Update logo file path in logto.yaml
-- Update logo file path in logto.yaml
-- Remove commented out code for docker container removal
-- Add isAnyDeploymentInprogress function to check if any deployments are in progress
-- Add ApplicationDeploymentJob and pint.json
-
-## [4.0.0-beta.295] - 2024-06-10
-
-### 🚀 Features
-
-- Able to change database passwords on the UI. It won't sync to the database.
-- Able to add several domains to compose based previews
-- Add bounty program link to bug report template
-- Add titles
-- Db proxy logs
-
-### 🐛 Bug Fixes
-
-- Custom docker compose commands, add project dir if needed
-- Autoupdate process
-- Backup executions view
-- Handle previously defined compose previews
-- Sort backup executions
-- Supabase service, newest versions
-- Set default name for Docker volumes if it is null
-- Multiline variable should be literal + should be multiline in bash with \
-- Gitlab merge request should close PR
-
-### 💼 Other
-
-- Rocketchat
-- New services based git apps
-
-### 🚜 Refactor
-
-- Append utm_source parameter to documentation URL
-- Update save_environment_variables method to use application's environment_variables instead of environment_variables_preview
-- Update deployment previews heading to "Deployments"
-- Remove unused variables and improve code readability
-- Initialize null properties in Github Change component
-- Improve pre and post deployment command inputs
-- Improve handling of Docker volumes in parseDockerComposeFile function
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version numbers to 4.0.0-beta.295
-- Update supported OS list with almalinux
-- Update install.sh to support PopOS
-- Update install.sh script to version 1.3.2 and handle Linux Mint as Ubuntu
-
-## [4.0.0-beta.294] - 2024-06-04
-
-### ⚙️ Miscellaneous Tasks
-
-- Update Dockerfile with latest versions of Docker, Docker Compose, Docker Buildx, Pack, and Nixpacks
-
-## [4.0.0-beta.289] - 2024-05-29
-
-### 🚀 Features
-
-- Add PHP memory limit environment variable to docker-compose.prod.yml
-- Add manual update option to UpdateCoolify handle method
-- Add port configuration for Vaultwarden service
-
-### 🐛 Bug Fixes
-
-- Sync upgrade process
-- Publish horizon
-- Add missing team model
-- Test new upgrade process?
-- Throw exception
-- Build server dirs not created on main server
-- Compose load with non-root user
-- Able to redeploy dockerfile based apps without cache
-- Compose previews does have env variables
-- Fine-tune cdn pulls
-- Spamming :D
-- Parse docker version better
-- Compose issues
-- SERVICE_FQDN has source port in it
-- Logto service
-- Allow invitations via email
-- Sort by defined order + fixed typo
-- Only ignore volumes with driver_opts
-- Check env in args for compose based apps
-
-### 🚜 Refactor
-
-- Update destination.blade.php to add group class for better styling
-- Applicationdeploymentjob
-- Improve code structure in ApplicationDeploymentJob.php
-- Remove unnecessary debug statement in ApplicationDeploymentJob.php
-- Remove unnecessary debug statements and improve code structure in RunRemoteProcess.php and ApplicationDeploymentJob.php
-- Remove unnecessary logging statements from UpdateCoolify
-- Update storage form inputs in show.blade.php
-- Improve Docker Compose parsing for services
-- Remove unnecessary port appending in updateCompose function
-- Remove unnecessary form class in profile index.blade.php
-- Update form layout in invite-link.blade.php
-- Add log entry when starting new application deployment
-- Improve Docker Compose parsing for services
-- Update Docker Compose parsing for services
-- Update slogan in shlink.yaml
-- Improve display of deployment time in index.blade.php
-- Remove commented out code for clearing Ray logs
-- Update save_environment_variables method to use application's environment_variables instead of environment_variables_preview
-
-### ⚙️ Miscellaneous Tasks
-
-- Update for version 289
-- Fix formatting issue in deployment index.blade.php file
-- Remove unnecessary wire:navigate attribute in breadcrumbs.blade.php
-- Rename docker dirs
-- Update laravel/socialite to version v5.14.0 and livewire/livewire to version 3.4.9
-- Update modal styles for better user experience
-- Update deployment index.blade.php script for better performance
-- Update version numbers to 4.0.0-beta.290
-- Update version numbers to 4.0.0-beta.291
-- Update version numbers to 4.0.0-beta.292
-- Update version numbers to 4.0.0-beta.293
-- Add upgrade guide link to upgrade.blade.php
-- Improve upgrade.blade.php with clearer instructions and formatting
-- Update version numbers to 4.0.0-beta.294
-- Add Lightspeed.run as a sponsor
-- Update Dockerfile to install vim
-
-## [4.0.0-beta.288] - 2024-05-28
-
-### 🐛 Bug Fixes
-
-- Do not allow service storage mount point modifications
-- Volume adding
-
-### ⚙️ Miscellaneous Tasks
-
-- Update Sentry release version to 4.0.0-beta.288
-
-## [4.0.0-beta.287] - 2024-05-27
-
-### 🚀 Features
-
-- Handle incomplete expired subscriptions in Stripe webhook
-- Add more persistent storage types
-
-### 🐛 Bug Fixes
-
-- Force load services from cdn on reload list
-
-### ⚙️ Miscellaneous Tasks
-
-- Update Sentry release version to 4.0.0-beta.287
-- Add Thompson Edolo as a sponsor
-- Add null checks for team in Stripe webhook
-
-## [4.0.0-beta.286] - 2024-05-27
-
-### 🚀 Features
-
-- If the time seems too long it remains at 0s
-- Improve Docker Engine start logic in ServerStatusJob
-- If proxy stopped manually, it won't start back again
-- Exclude_from_hc magic
-- Gitea manual webhooks
-- Add container logs in case the container does not start healthy
-
-### 🐛 Bug Fixes
-
-- Wrong time during a failed deployment
-- Removal of the failed deployment condition, addition of since started instead of finished time
-- Use local versions + service templates and query them every 10 minutes
-- Check proxy functionality before removing unnecessary coolify.yaml file and checking Docker Engine
-- Show first 20 users only in admin view
-- Add subpath for services
-- Ghost subdir
-- Do not pull templates in dev
-- Templates
-- Update error message for invalid token to mention invalid signature
-- Disable containerStopped job for now
-- Disable unreachable/revived notifications for now
-- JSON_UNESCAPED_UNICODE
-- Add wget to nixpacks builds
-- Pre and post deployment commands
-- Bitbucket commits link
-- Better way to add curl/wget to nixpacks
-- Root team able to download backups
-- Build server should not have a proxy
-- Improve build server functionalities
-- Sentry issue
-- Sentry
-- Sentry error + livewire downgrade
-- Sentry
-- Sentry
-- Sentry error
-- Sentry
-
-### 🚜 Refactor
-
-- Update edit-domain form in project service view
-- Add Huly services to compose file
-- Remove redundant heading in backup settings page
-- Add isBuildServer method to Server model
-- Update docker network creation in ApplicationDeploymentJob
-
-### ⚙️ Miscellaneous Tasks
-
-- Change pre and post deployment command length in applications table
-- Refactor container name logic in GetContainersStatus.php and ForcePasswordReset.php
-- Remove unnecessary content from Docker Compose file
-
-## [4.0.0-beta.285] - 2024-05-21
-
-### 🚀 Features
-
-- Add SerpAPI as a Github Sponsor
-- Admin view for deleting users
-- Scheduled task failed notification
-
-### 🐛 Bug Fixes
-
-- Optimize new resource creation
-- Show it docker compose has syntax errors
-
-### 💼 Other
-
-- Responsive here and there
-
-## [4.0.0-beta.284] - 2024-05-19
-
-### 🚀 Features
-
-- Add hc logs to healthchecks
-
-### ◀️ Revert
-
-- Hc return code check
-
-## [4.0.0-beta.283] - 2024-05-17
-
-### 🚀 Features
-
-- Update healthcheck test in StartMongodb action
-- Add pull_request_id filter to get_last_successful_deployment method in Application model
-
-### 🐛 Bug Fixes
-
-- PR deployments have good predefined envs
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.283
-
-## [4.0.0-beta.281] - 2024-05-17
-
-### 🚀 Features
-
-- Shows the latest deployment commit + message on status
-- New manual update process + remove next_channel
-- Add lastDeploymentInfo and lastDeploymentLink props to breadcrumbs and status components
-- Sort envs alphabetically and creation date
-- Improve sorting of environment variables in the All component
-
-### 🐛 Bug Fixes
-
-- Hc from localhost to 127.0.0.1
-- Use rc in hc
-- Telegram group chat notifications
-
-## [4.0.0-beta.280] - 2024-05-16
-
-### 🐛 Bug Fixes
-
-- Commit message length
-
-## [4.0.0-beta.279] - 2024-05-16
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version numbers to 4.0.0-beta.279
-- Limit commit message length to 50 characters in ApplicationDeploymentJob
-
-## [4.0.0-beta.278] - 2024-05-16
-
-### 🚀 Features
-
-- Adding new COOLIFY_ variables
-- Save commit message and better view on deployments
-- Toggle label escaping mechanism
-
-### 🐛 Bug Fixes
-
-- Use commit hash on webhooks
-
-### ⚙️ Miscellaneous Tasks
-
-- Refactor Service.php to handle missing admin user in extraFields() method
-- Update twenty CRM template with environment variables and dependencies
-- Refactor applications.php to remove unused imports and improve code readability
-- Refactor deployment index.blade.php for improved readability and rollback handling
-- Refactor GitHub app selection UI in project creation form
-- Update ServerLimitCheckJob.php to handle missing serverLimit value
-- Remove unnecessary code for saving commit message
-- Update DOCKER_VERSION to 26.0 in install.sh script
-- Update Docker and Docker Compose versions in Dockerfiles
-
-## [4.0.0-beta.277] - 2024-05-10
-
-### 🚀 Features
-
-- Add AdminRemoveUser command to remove users from the database
-
-### 🐛 Bug Fixes
-
-- Color for resource operation server and project name
-- Only show realtime error on non-cloud instances
-- Only allow push and mr gitlab events
-- Improve scheduled task adding/removing
-- Docker compose dependencies for pr previews
-- Properly populating dependencies
-
-### 💼 Other
-
-- Fix a few boxes here and there
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version numbers to 4.0.0-beta.278
-- Update hover behavior and cursor style in scheduled task executions view
-- Refactor scheduled task view to improve code readability and maintainability
-- Skip scheduled tasks if application or service is not running
-- Remove debug logging statements in Kernel.php
-- Handle invalid cron strings in Kernel.php
-
-## [4.0.0-beta.275] - 2024-05-06
-
-### 🚀 Features
-
-- Add container name to network aliases in ApplicationDeploymentJob
-- Add lazy loading for images in General.php and improve Docker Compose file handling in Application.php
-- Experimental sentinel
-- Start Sentinel on servers.
-- Pull new sentinel image and restart container
-- Init metrics
-
-### 🐛 Bug Fixes
-
-- Typo in tags.blade.php
-- Install.sh error
-- Env file
-- Comment out internal notification in email_verify method
-- Confirmation for custom labels
-- Change permissions on newly created dirs
-
-### 💼 Other
-
-- Fix tag view
-
-### 🚜 Refactor
-
-- Add SCHEDULER environment variable to StartSentinel.php
-
-### ⚙️ Miscellaneous Tasks
-
-- Dark mode should be the default
-- Improve menu item styling and spacing in service configuration and index views
-- Improve menu item styling and spacing in service configuration and index views
-- Improve menu item styling and spacing in project index and show views
-- Remove docker compose versions
-- Add Listmonk service template and logo
-- Refactor GetContainersStatus.php for improved readability and maintainability
-- Refactor ApplicationDeploymentJob.php for improved readability and maintainability
-- Add metrics and logs directories to installation script
-- Update sentinel version to 0.0.2 in versions.json
-- Update permissions on metrics and logs directories
-- Comment out server sentinel check in ServerStatusJob
-
-## [4.0.0-beta.273] - 2024-05-03
-
-### 🐛 Bug Fixes
-
-- Formbricks image origin
-- Add port even if traefik is used
-
-### ⚙️ Miscellaneous Tasks
-
-- Update version to 4.0.0-beta.275
-- Update DNS server validation helper text
-
-## [4.0.0-beta.267] - 2024-04-26
-
-### 🚀 Features
-
-- Initial datalist
-- Update service contribution docs URL
-- The final pricing plan, pay-as-you-go
-
-### 🐛 Bug Fixes
-
-- Move s3 storages to separate view
-- Mongo db backup
-- Backups
-- Autoupdate
-- Respect start period and chekc interval for hc
-- Parse HEALTHCHECK from dockerfile
-- Make s3 name and endpoint required
-- Able to update source path for predefined volumes
-- Get logs with non-root user
-- Mongo 4.0 db backup
-
-### 💼 Other
-
-- Update resource operations view
-
-### ◀️ Revert
-
-- Variable parsing
-
-## [4.0.0-beta.266] - 2024-04-24
-
-### 🐛 Bug Fixes
-
-- Refresh public ips on start
-
-## [4.0.0-beta.259] - 2024-04-17
-
-### 🚀 Features
-
-- Literal env variables
-- Lazy load stuffs + tell user if compose based deployments have missing envs
-- Can edit file/dir volumes from ui in compose based apps
-- Upgrade Appwrite service template to 1.5
-- Upgrade Appwrite service template to 1.5
-- Add db name to backup notifications
-
-### 🐛 Bug Fixes
-
-- Helper image only pulled if required, not every 10 mins
-- Make sure that confs when checking if it is changed sorted
-- Respect .env file (for default values)
-- Remove temporary cloudflared config
-- Remove lazy loading until bug figured out
-- Rollback feature
-- Base64 encode .env
-- $ in labels escaped
-- .env saved to deployment server, not to build server
-- Do no able to delete gh app without deleting resources
-- 500 error on edge case
-- Able to select server when creating new destination
-- N8n template
-
-### 💼 Other
-
-- Non-root user for remote servers
-- Non-root
-
-## [4.0.0-beta.258] - 2024-04-12
-
-### 🚀 Features
-
-- Dynamic mux time
-
-### 🐛 Bug Fixes
-
-- Check each required binaries one-by-one
-
-## [4.0.0-beta.256] - 2024-04-12
-
-### 🚀 Features
-
-- Upload large backups
-- Edit domains easier for compose
-- Able to delete configuration from server
-- Configuration checker for all resources
-- Allow tab in textarea
-
-### 🐛 Bug Fixes
-
-- Service config hash update
-- Redeploy if image not found in restart only mode
-
-### 💼 Other
-
-- New pricing
-- Fix allowTab logic
-- Use 2 space instead of tab
-
-## [4.0.0-beta.252] - 2024-04-09
-
-### 🚀 Features
-
-- Add amazon linux 2023
-
-### 🐛 Bug Fixes
-
-- Git submodule update
-- Unintended left padding on sidebar
-- Hashed random delimeter in ssh commands + make sure to remove the delimeter from the command
-
-## [4.0.0-beta.250] - 2024-04-05
-
-### 🚀 Features
-
-- *(application)* Update submodules after git checkout
-
-## [4.0.0-beta.249] - 2024-04-03
-
-### 🚀 Features
-
-- Able to make rsa/ed ssh keys
-
-### 🐛 Bug Fixes
-
-- Warning if you use multiple domains for a service
-- New github app creation
-- Always rebuild Dockerfile / dockerimage buildpacks
-- Do not rebuild dockerfile based apps twice
-- Make sure if envs are changed, rebuild is needed
-- Members cannot manage subscriptions
-- IsMember
-- Storage layout
-- How to update docker-compose, environment variables and fqdns
-
-### 💼 Other
-
-- Light buttons
-- Multiple server view
-
-## [4.0.0-beta.242] - 2024-03-25
-
-### 🚀 Features
-
-- Change page width
-- Watch paths
-
-### 🐛 Bug Fixes
-
-- Compose env has SERVICE, but not defined for Coolify
-- Public service database
-- Make sure service db proxy restarted
-- Restart service db proxies
-- Two factor
-- Ui for tags
-- Update resources view
-- Realtime connection check
-- Multline env in dev mode
-- Scheduled backup for other service databases (supabase)
-- PR deployments should not be distributed to 2 servers
-- Name/from address required for resend
-- Autoupdater
-- Async service loads
-- Disabled inputs are not trucated
-- Duplicated generated fqdns are now working
-- Uis
-- Ui for cftunnels
-- Search services
-- Trial users subscription page
-- Async public key loading
-- Unfunctional server should see resources
-
-### 💼 Other
-
-- Run cleanup every day
-- Fix
-- Fix log outputs
-- Automatic cloudflare tunnels
-- Backup executions
-
-## [4.0.0-beta.241] - 2024-03-20
-
-### 🚀 Features
-
-- Able to run scheduler/horizon programatically
-
-### 🐛 Bug Fixes
-
-- Volumes for prs
-- Shared env variable parsing
-
-### 💼 Other
-
-- Redesign
-- Redesign
-
-## [4.0.0-beta.240] - 2024-03-18
-
-### 🐛 Bug Fixes
-
-- Empty get logs number of lines
-- Only escape envs after v239+
-- 0 in env value
-- Consistent container name
-- Custom ip address should turn off rolling update
-- Multiline input
-- Raw compose deployment
-- Dashboard view if no project found
-
-## [4.0.0-beta.239] - 2024-03-14
-
-### 🐛 Bug Fixes
-
-- Duplicate dockerfile
-- Multiline env variables
-- Server stopped, service page not reachable
-
-## [4.0.0-beta.237] - 2024-03-14
-
-### 🚀 Features
-
-- Domains api endpoint
-- Resources api endpoint
-- Team api endpoint
-- Add deployment details to deploy endpoint
-- Add deployments api
-- Experimental caddy support
-- Dynamic configuration for caddy
-- Reset password
-- Show resources on source page
-
-### 🐛 Bug Fixes
-
-- Deploy api messages
-- Fqdn null in case docker compose bp
-- Reload caddy issue
-- /realtime endpoint
-- Proxy switch
-- Service ports for services + caddy
-- Failed deployments should send failed email/notification
-- Consider custom healthchecks in dockerfile
-- Create initial files async
-- Docker compose validation
-
-## [4.0.0-beta.235] - 2024-03-05
-
-### 🐛 Bug Fixes
-
-- Should note delete personal teams
-- Make sure to show some buttons
-- Sort repositories by name
-
-## [4.0.0-beta.224] - 2024-02-23
-
-### 🚀 Features
-
-- Custom server limit
-- Delay container/server jobs
-- Add static ipv4 ipv6 support
-- Server disabled by overflow
-- Preview deployment logs
-- Collect webhooks during maintenance
-- Logs and execute commands with several servers
-
-### 🐛 Bug Fixes
-
-- Subscription / plan switch, etc
-- Firefly service
-- Force enable/disable server in case ultimate package quantity decreases
-- Server disabled
-- Custom dockerfile location always checked
-- Import to mysql and mariadb
-- Resource tab not loading if server is not reachable
-- Load unmanaged async
-- Do not show n/a networsk
-- Service container status updates
-- Public prs should not be commented
-- Pull request deployments + build servers
-- Env value generation
-- Sentry error
-- Service status updated
-
-### 💼 Other
-
-- Change + icon to hamburger.
-
-## [4.0.0-beta.222] - 2024-02-22
-
-### 🚀 Features
-
-- Able to add dynamic configurations from proxy dashboard
-
-### 🐛 Bug Fixes
-
-- Connections being stuck and not processed until proxy restarts
-- Use latest image if nothing is specified
-- No coolify.yaml found
-- Server validation
-- Statuses
-- Unknown image of service until it is uploaded
-
-## [4.0.0-beta.220] - 2024-02-19
-
-### 🚀 Features
-
-- Save github app permission locally
-- Minversion for services
-
-### 🐛 Bug Fixes
-
-- Add openbsd ssh server check
-- Resources
-- Empty build variables
-- *(server)* Revalidate server button not showing in server's page
-- Fluent bit ident level
-- Submodule cloning
-- Database status
-- Permission change updates from webhook
-- Server validation
-
-### 💼 Other
-
-- Updates
-
-## [4.0.0-beta.213] - 2024-02-12
-
-### 🚀 Features
-
-- Magic for traefik redirectregex in services
-- Revalidate server
-- Disable gzip compression on service applications
-
-### 🐛 Bug Fixes
-
-- Cleanup scheduled tasks
-- Padding left on input boxes
-- Use ls / command instead ls
-- Do not add the same server twice
-- Only show redeployment required if status is not exited
-
-## [4.0.0-beta.212] - 2024-02-08
-
-### 🚀 Features
-
-- Cleanup queue
-
-### 🐛 Bug Fixes
-
-- New menu on navbar
-- Make sure resources are deleted in async mode
-- Go to prod env from dashboard if there is no other envs defined
-- User proper image_tag, if set
-- New menu ui
-- Lock logdrain configuration when one of them are enabled
-- Add docker compose check during server validation
-- Get service stack as uuid, not name
-- Menu
-- Flex wrap deployment previews
-- Boolean docker options
-- Only add 'networks' key if 'network_mode' is absent
-
-## [4.0.0-beta.206] - 2024-02-05
-
-### 🚀 Features
-
-- Clone to env
-- Multi deployments
-
-### 🐛 Bug Fixes
-
-- Wrap tags and avoid horizontal overflow
-- Stripe webhooks
-- Feedback from self-hosted envs to discord
-
-### 💼 Other
-
-- Specific about newrelic logdrains
-
-## [4.0.0-beta.201] - 2024-01-29
-
-### 🚀 Features
-
-- Added manual webhook support for bitbucket
-- Add initial support for custom docker run commands
-- Cleanup unreachable servers
-- Tags and tag deploy webhooks
-
-### 🐛 Bug Fixes
-
-- Bitbucket manual deployments
-- Webhooks for multiple apps
-- Unhealthy deployments should be failed
-- Add env variables for wordpress template without database
-- Service deletion function
-- Service deletion fix
-- Dns validation + duplicated fqdns
-- Validate server navbar upated
-- Regenerate labels on application clone
-- Service deletion
-- Not able to use other shared envs
-- Sentry fix
-- Sentry
-- Sentry error
-- Sentry
-- Sentry error
-- Create dynamic directory
-- Migrate to new modal
-- Duplicate domain check
-- Tags
-
-### 💼 Other
-
-- New modal component
-
-## [4.0.0-beta.188] - 2024-01-11
-
-### 🚀 Features
-
-- Search between resources
-- Move resources between projects / environments
-- Clone any resource
-- Shared environments
-- Concurrent builds / server
-- Able to deploy multiple resources with webhook
-- Add PR comments
-- Dashboard live deployment view
-
-### 🐛 Bug Fixes
-
-- Preview deployments with nixpacks
-- Cleanup docker stuffs before upgrading
-- Service deletion command
-- Cpuset limits was determined in a way that apps only used 1 CPU max, ehh, sorry.
-- Service stack view
-- Change proxy view
-- Checkbox click
-- Git pull command for deploy key based previews
-- Server status job
-- Service deletion bug!
-- Links
-- Redis custom conf
-- Sentry error
-- Restrict concurrent deployments per server
-- Queue
-- Change env variable length
-
-### 💼 Other
-
-- Send notification email if payment
-
-### 🚜 Refactor
-
-- Compose file and install script
-
-## [4.0.0-beta.186] - 2024-01-11
-
-### 🚀 Features
-
-- Import backups
-
-### 🐛 Bug Fixes
-
-- Do not include thegameplan.json into build image
-- Submit error on postgresql
-- Email verification / forgot password
-- Escape build envs properly for nixpacks + docker build
-- Undead endpoint
-- Upload limit on ui
-- Save cmd output propely (merge)
-- Load profile on remote commands
-- Load profile and set envs on remote cmd
-- Restart should not update config hash
-
-## [4.0.0-beta.184] - 2024-01-09
-
-### 🐛 Bug Fixes
-
-- Healthy status
-- Show framework based notification in build logs
-- Traefik labels
-- Use ip for sslip in dev if remote server is used
-- Service labels without ports (unknown ports)
-- Sort and rename (unique part) of labels
-- Settings menu
-- Remove traefik debug in dev mode
-- Php pgsql to 8.2
-- Static buildpack should set port 80
-- Update navbar on build_pack change
-
-## [4.0.0-beta.183] - 2024-01-06
-
-### 🚀 Features
-
-- Add www-non-www redirects to traefik
-
-### 🐛 Bug Fixes
-
-- Database env variables
-
-## [4.0.0-beta.182] - 2024-01-04
-
-### 🐛 Bug Fixes
-
-- File storage save
-
-## [4.0.0-beta.181] - 2024-01-03
-
-### 🐛 Bug Fixes
-
-- Nixpacks buildpack
-
-## [4.0.0-beta.180] - 2024-01-03
-
-### 🐛 Bug Fixes
-
-- Nixpacks cache
-- Only add restart policy if its empty (compose)
-
-## [4.0.0-beta.179] - 2024-01-02
-
-### 🐛 Bug Fixes
-
-- Set deployment failed if new container is not healthy
-
-## [4.0.0-beta.177] - 2024-01-02
-
-### 🚀 Features
-
-- Raw docker compose deployments
-
-### 🐛 Bug Fixes
-
-- Duplicate compose variable
-
-## [4.0.0-beta.176] - 2023-12-31
-
-### 🐛 Bug Fixes
-
-- Horizon
-
-## [4.0.0-beta.175] - 2023-12-30
-
-### 🚀 Features
-
-- Add environment description + able to change name
-
-### 🐛 Bug Fixes
-
-- Sub
-- Wrong env variable parsing
-- Deploy key + docker compose
-
-## [4.0.0-beta.174] - 2023-12-27
-
-### 🐛 Bug Fixes
-
-- Restore falsely deleted coolify-db-backup
-
-## [4.0.0-beta.173] - 2023-12-27
-
-### 🐛 Bug Fixes
-
-- Cpu limit to float from int
-- Add source commit to final envs
-- Routing, switch back to old one
-- Deploy instead of restart in case swarm is used
-- Button title
-
-## [4.0.0-beta.163] - 2023-12-15
-
-### 🚀 Features
-
-- Custom docker compose commands
-
-### 🐛 Bug Fixes
-
-- Domains for compose bp
-- No action in webhooks
-- Add debug output to gitlab webhooks
-- Do not push dockerimage
-- Add alpha to swarm
-- Server not found
-- Do not autovalidate server on mount
-- Server update schedule
-- Swarm support ui
-- Server ready
-- Get swarm service logs
-- Docker compose apps env rewritten
-- Storage error on dbs
-- Why?!
-- Stay tuned
-
-### 💼 Other
-
-- Swarm
-- Swarm
-
-## [4.0.0-beta.155] - 2023-12-11
-
-### 🚀 Features
-
-- Autoupdate env during seed
-- Disable autoupdate
-- Randomly sleep between executions
-- Pull latest images for services
-
-### 🐛 Bug Fixes
-
-- Do not send telegram noti on intent payment failed
-- Database ui is realtime based
-- Live mode for github webhooks
-- Ui
-- Realtime connection popup could be disabled
-- Realtime check
-- Add new destination
-- Proxy logs
-- Db status check
-- Pusher host
-- Add ipv6
-- Realtime connection?!
-- Websocket
-- Better handling of errors with install script
-- Install script parse version
-- Only allow to modify in .env file if AUTOUPDATE is set
-- Is autoupdate not null
-- Run init command after production seeder
-- Init
-- Comma in traefik custom labels
-- Ignore if dynamic config could not be set
-- Service env variable ovewritten if it has a default value
-- Labelling
-- Non-ascii chars in labels
-- Labels
-- Init script echos
-- Update Coolify script
-- Null notify
-- Check queued deployments as well
-- Copy invitation
-- Password reset / invitation link requests
-- Add catch all route
-- Revert random container job delay
-- Backup executions view
-- Only check server status in container status job
-- Improve server status check times
-- Handle other types of generated values
-- Server checking status
-- Ui for adding new destination
-- Reset domains on compose file change
-
-### 💼 Other
-
-- Fix for comma in labels
-- Add image name to service stack + better options visibility
-
-### 🚜 Refactor
-
-- Service logs are now on one page
-- Application status changed realtime
-- Custom labels
-- Clone project
-
-## [4.0.0-beta.154] - 2023-12-07
-
-### 🚀 Features
-
-- Execute command in container
-
-### 🐛 Bug Fixes
-
-- Container selection
-- Service navbar using new realtime events
-- Do not create duplicated networks
-- Live event
-- Service start + event
-- Service deletion job
-- Double ws connection
-- Boarding view
-
-### 💼 Other
-
-- Env vars
-- Migrate to livewire 3
-
-## [4.0.0-beta.124] - 2023-11-13
-
-### 🚀 Features
-
-- Log drain (wip)
-- Enable/disable log drain by service
-- Log drainer container check
-- Add docker engine support install script to rhel based systems
-- Save timestamp configuration for logs
-- Custom log drain endpoints
-- Auto-restart tcp proxies for databases
-
-### 🐛 Bug Fixes
-
-- *(fider template)* Use the correct docs url
-- Fqdn for minio
-- Generate service fields
-- Mariadb backups
-- When to pull image
-- Do not allow to enter local ip addresses
-- Reset password
-- Only report nonruntime errors
-- Handle different label formats in services
-- Server adding process
-- Show defined resources in server tab, so you will know what you need to delete before you can delete the server.
-- Lots of regarding git + docker compose deployments
-- Pull request build variables
-- Double default password length
-- Do not remove deployment in case compose based failed
-- No container servers
-- Sentry issue
-- Dockercompose save ./ volumes under /data/coolify
-- Server view for link()
-- Default value do not overwrite existing env value
-- Use official install script with rancher (one will work for sure)
-- Add cf tunnel to boarding server view
-- Prevent autorefresh of proxy status
-- Missing docker image thing
-- Add hc for soketi
-- Deploy the right compose file
-- Bind volumes for compose bp
-- Use hc port 80 in case of static build
-- Switching to static build
-
-### 💼 Other
-
-- New deployment jobs
-- Compose based apps
-- Swarm
-- Swarm
-- Swarm
-- Swarm
-- Disable trial
-- Meilisearch
-- Broadcast
-- 🌮
-
-### 🚜 Refactor
-
-- Env variable generator
-
-### ◀️ Revert
-
-- Wip
-
-## [4.0.0-beta.109] - 2023-11-06
-
-### 🚀 Features
-
-- Deployment logs fullscreen
-- Service database backups
-- Make service databases public
-
-### 🐛 Bug Fixes
-
-- Missing environment variables prevewi on service
-- Invoice.paid should sleep for 5 seconds
-- Local dev repo
-- Deployments ui
-- Dockerfile build pack fix
-- Set labels on generate domain
-- Network service parse
-- Notification url in containerstatusjob
-- Gh webhook response 200 to installation_repositories
-- Delete destination
-- No id found
-- Missing $mailMessage
-- Set default from/sender names
-- No environments
-- Telegram text
-- Private key not found error
-- UI
-- Resourcesdelete command
-- Port number should be int
-- Separate delete with validation of server
-- Add nixpacks info
-- Remove filter
-- Container logs are now followable in full-screen and sorted by timestamp
-- Ui for labels
-- Ui
-- Deletions
-- Build_image not found
-- Github source view
-- Github source view
-- Dockercleanupjob should be released back
-- Ui
-- Local ip address
-- Revert workdir to basedir
-- Container status jobs for old pr deployments
-- Service updates
-
-## [4.0.0-beta.99] - 2023-10-24
-
-### 🚀 Features
-
-- Improve deployment time by a lot
-
-### 🐛 Bug Fixes
-
-- Space in build args
-- Lock SERVICE_FQDN envs
-- If user is invited, that means its email is verified
-- Force password reset on invited accounts
-- Add ssh options to git ls-remote
-- Git ls-remote
-- Remove coolify labels from ui
-
-### 💼 Other
-
-- Fix subs
-
-## [4.0.0-beta.97] - 2023-10-20
-
-### 🚀 Features
-
-- Standalone mongodb
-- Cloning project
-- Api tokens + deploy webhook
-- Start all kinds of things
-- Simple search functionality
-- Mysql, mariadb
-- Lock environment variables
-- Download local backups
-
-### 🐛 Bug Fixes
-
-- Service docs links
-- Add PGUSER to prevent HC warning
-- Preselect s3 storage if available
-- Port exposes change, shoud regenerate label
-- Boarding
-- Clone to with the same environment name
-- Cleanup stucked resources on start
-- Do not allow to delete env if a resource is defined
-- Service template generator + appwrite
-- Mongodb backup
-- Make sure coolfiy network exists on install
-- Syncbunny command
-- Encrypt mongodb password
-- Mongodb healtcheck command
-- Rate limit for api + add mariadb + mysql
-- Server settings guarded
-
-### 💼 Other
-
-- Generate services
-- Mongodb backup
-- Mongodb backup
-- Updates
-
-## [4.0.0-beta.93] - 2023-10-18
-
-### 🚀 Features
-
-- Able to customize docker labels on applications
-- Show if config is not applied
-
-### 🐛 Bug Fixes
-
-- Setup:dev script & contribution guide
-- Do not show configuration changed if config_hash is null
-- Add config_hash if its null (old deployments)
-- Label generation
-- Labels
-- Email channel no recepients
-- Limit horizon processes to 2 by default
-- Add custom port as ssh option to deploy_key based commands
-- Remove custom port from git repo url
-- ContainerStatus job
-
-### 💼 Other
-
-- PAT by team
-
-## [4.0.0-beta.92] - 2023-10-17
-
-### 🐛 Bug Fixes
-
-- Proxy start process
-
-## [4.0.0-beta.91] - 2023-10-17
-
-### 🐛 Bug Fixes
-
-- Always start proxy if not NONE is selected
-
-### 💼 Other
-
-- Add helper to service domains
-
-## [4.0.0-beta.90] - 2023-10-17
-
-### 🐛 Bug Fixes
-
-- Only include config.json if its exists and a file
-
-### 💼 Other
-
-- Wordpress
-
-## [4.0.0-beta.89] - 2023-10-17
-
-### 🐛 Bug Fixes
-
-- Noindex meta tag
-- Show docker build logs
-
-## [4.0.0-beta.88] - 2023-10-17
-
-### 🚀 Features
-
-- Use docker login credentials from server
-
-## [4.0.0-beta.87] - 2023-10-17
-
-### 🐛 Bug Fixes
-
-- Service status check is a bit better
-- Generate fqdn if you deleted a service app, but it requires fqdn
-- Cancel any deployments + queue next
-- Add internal domain names during build process
-
-## [4.0.0-beta.86] - 2023-10-15
-
-### 🐛 Bug Fixes
-
-- Build image before starting dockerfile buildpacks
-
-## [4.0.0-beta.85] - 2023-10-14
-
-### 🐛 Bug Fixes
-
-- Redis URL generated
-
-## [4.0.0-beta.83] - 2023-10-13
-
-### 🐛 Bug Fixes
-
-- Docker hub URL
-
-## [4.0.0-beta.70] - 2023-10-09
-
-### 🚀 Features
-
-- Add email verification for cloud
-- Able to deploy docker images
-- Add dockerfile location
-- Proxy logs on the ui
-- Add custom redis conf
-
-### 🐛 Bug Fixes
-
-- Server validation process
-- Fqdn could be null
-- Small
-- Server unreachable count
-- Do not reset unreachable count
-- Contact docs
-- Check connection
-- Server saving
-- No env goto envs from dashboard
-- Goto
-- Tcp proxy for dbs
-- Database backups
-- Only send email if transactional email set
-- Backupfailed notification is forced
-- Use port exposed for reverse proxy
-- Contact link
-- Use only ip addresses for servers
-- Deleted team and it is the current one
-- Add new team button
-- Transactional email link
-- Dashboard goto link
-- Only require registry image in case of dockerimage bp
-- Instant save build pack change
-- Public git
-- Cannot remove localhost
-- Check localhost connection
-- Send unreachable/revived notifications
-- Boarding + verification
-- Make sure proxy wont start in NONE mode
-- Service check status 10 sec
-- IsCloud in production seeder
-- Make sure to use IP address
-- Dockerfile location feature
-- Server ip could be hostname in self-hosted
-- Urls should be password fields
-- No backup for redis
-- Show database logs in case of its not healthy and running
-- Proxy check for ports, do not kill anything listening on port 80/443
-- Traefik dashboard ip
-- Db labels
-- Docker cleanup jobs
-- Timeout for instant remote processes
-- Dev containerjobs
-- Backup database one-by-one.
-- Turn off static deployment if you switch buildpacks
-
-### 💼 Other
-
-- Dockerimage
-- Updated dashboard
-- Fix
-- Fix
-- Coolify proxy access logs exposed in dev
-- Able to select environment on new resource
-- Delete server
-- Redis
-
-## [4.0.0-beta.58] - 2023-10-02
-
-### 🚀 Features
-
-- Reset root password
-- Attach Coolify defined networks to services
-- Delete resource command
-- Multiselect removable resources
-- Disable service, required version
-- Basedir / monorepo initial support
-- Init version of any git deployment
-- Deploy private repo with ssh key
-
-### 🐛 Bug Fixes
-
-- If waitlist is disabled, redirect to register
-- Add destination to new services
-- Predefined content for files
-- Move /data to ./_data in dev
-- UI
-- Show all storages in one place for services
-- Ui
-- Add _data to vite ignore
-- Only use _ in volume names for services
-- Volume names in services
-- Volume names
-- Service logs visible if the whole service stack is not running
-- Ui
-- Compose magic
-- Compose parser updated
-- Dev compose files
-- Traefik labels for multiport deployments
-- Visible version number
-- Remove SERVICE_ from deployable compose
-- Delete event to deleting
-- Move dev data to volumes to prevent permission issues
-- Traefik labelling in case of several http and https domain added
-- PR deployments use the first fqdn as base
-- Email notifications subscription fixed
-- Services - do not remove unnecessary things for now
-- Decrease max horizon processes to get lower memory usage
-- Test emails only available for user owned smtp/resend
-- Ui for self-hosted email settings
-- Set smtp notifications on by default
-- Select branch on other git
-- Private repository
-- Contribution guide
-- Public repository names
-- *(create)* Flex wrap on server & network selection
-- Better unreachable/revived server statuses
-- Able to set base dir for Dockerfile build pack
-
-### 💼 Other
-
-- Uptime kume hc updated
-- Switch back to /data (volume errors)
-- Notifications
-- Add shared email option to everyone
-
-## [4.0.0-beta.57] - 2023-10-02
-
-### 🚀 Features
-
-- Container logs
-
-### 🐛 Bug Fixes
-
-- Always pull helper image in dev
-- Only show last 1000 lines
-- Service status
-
-## [4.0.0-beta.47] - 2023-09-28
-
-### 🐛 Bug Fixes
-
-- Next helper image
-- Service templates
-- Sync:bunny
-- Update process if server has been renamed
-- Reporting handler
-- Localhost privatekey update
-- Remove private key in case you removed a github app
-- Only show manually added private keys on server view
-- Show source on all type of applications
-- Docker cleanup should be a job by server
-- File/dir based volumes are now read from the server
-- Respect server fqdn
-- If public repository does not have a main branch
-- Preselect branc on private repos
-- Deploykey branch
-- Backups are now working again
-- Not found base_branch in git webhooks
-- Coolify db backup
-- Preview deployments name, status etc
-- Services should have destination as well
-- Dockerfile expose is not overwritten
-- If app settings is not saved to db
-- Do not show subscription cancelled noti
-- Show real volume names
-- Only parse expose in dockerfiles if ports_exposes is empty
-- Add uuid to volume names
-- New volumes for services should have - instead of _
-
-### 💼 Other
-
-- Fix previews to preview
-
-## [4.0.0-beta.46] - 2023-09-28
-
-### 🐛 Bug Fixes
-
-- Containerstatusjob
-- Aaaaaaaaaaaaaaaaa
-- Services view
-- Services
-- Manually create network for services
-- Disable early updates
-- Sslip for localhost
-- ContainerStatusJob
-- Cannot delete env with available services
-- Sync command
-- Install script drops an error
-- Prevent sync version (it needs an option)
-- Instance fqdn setting
-- Sentry 4510197209
-- Sentry 4504136641
-- Sentry 4502634789
-
-## [4.0.0-beta.45] - 2023-09-24
-
-### 🚀 Features
-
-- Services
-- Image tag for services
-
-### 🐛 Bug Fixes
-
-- Applications with port mappins do a normal update (not rolling update)
-- Put back build pack chooser
-- Proxy configuration + starter
-- Show real storage name on services
-- New service template layout
-
-### 💼 Other
-
-- Fixed z-index for version link.
-- Add source button
-- Fixed z-index for magicbar
-- A bit better error
-- More visible feedback button
-- Update help modal
-- Help
-- Marketing emails
-
-## [4.0.0-beta.28] - 2023-09-08
-
-### 🚀 Features
-
-- Telegram topics separation
-- Developer view for env variables
-- Cache team settings
-- Generate public key from private keys
-- Able to invite more people at once
-- Trial
-- Dynamic trial period
-- Ssh-agent instead of filesystem based ssh keys
-- New container status checks
-- Generate ssh key
-- Sentry add email for better support
-- Healthcheck for apps
-- Add cloudflare tunnel support
-
-### 🐛 Bug Fixes
-
-- Db backup job
-- Sentry 4459819517
-- Sentry 4451028626
-- Ui
-- Retry notifications
-- Instance email settings
-- Ui
-- Test email on for admins or custom smtp
-- Coolify already exists should not throw error
-- Delete database related things when delete database
-- Remove -q from docker compose
-- Errors in views
-- Only send internal notifcations to enabled channels
-- Recovery code
-- Email sending error
-- Sentry 4469575117
-- Old docker version error
-- Errors
-- Proxy check, reduce jobs, etc
-- Queue after commit
-- Remove nixpkgarchive
-- Remove nixpkgarchive from ui
-- Webhooks should not run if server is not functional
-- Server is functional check
-- Confirm email before sending
-- Help should send cc on email
-- Sub type
-- Show help modal everywhere
-- Forgot password
-- Disable dockerfile based healtcheck for now
-- Add timeout for ssh commands
-- Prevent weird ui bug for validateServer
-- Lowercase email in forgot password
-- Lower case email on waitlist
-- Encrypt jobs
-- ProcessWithEnv()->run
-- Plus boarding step about Coolify
-- SaveConfigurationSync
-- Help uri
-- Sub for root
-- Redirect on server not found
-- Ip check
-- Uniqueips
-- Simply reply to help messages
-- Help
-- Rate limit
-- Collect billing address
-- Invitation
-- Smtp view
-- Ssh-agent revert
-- Restarting container state on ui
-- Generate new key
-- Missing upgrade js
-- Team error
-- 4.0.0-beta.37
-- Localhost
-- Proxy start (if not proxy defined, use Traefik)
-- Do not remove localhost in boarding
-- Allow non ip address (DNS)
-- InstallDocker id not found
-- Boarding
-- Errors
-- Proxy container status
-- Proxy configuration saving
-- Convert startProxy to action
-- Stop/start UI on apps and dbs
-- Improve localhost boarding process
-- Try to use old docker-compose
-- Boarding again
-- Send internal notifications of email errors
-- Add github app change on new app view
-- Delete environment variables on app/db delete
-- Save proxy configuration
-- Add proxy to network with periodic check
-- Proxy connections
-- Delete persistent storages on resource deletion
-- Prevent overwrite already existing env variables in services
-- Mappings
-- Sentry issue 4478125289
-- Make sure proxy path created
-- StartProxy
-- Server validation with cf tunnels
-- Only show traefik dashboard if its available
-- Services
-- Database schema
-- Report livewire errors
-- Links with path
-- Add traefik labels no matter if traefik is selected or not
-- Add expose port for containers
-- Also check docker socks permission on validation
-
-### 💼 Other
-
-- User should know that the public key
-- Services are not availble yet
-- Show registered users on waitlist page
-- Nixpacksarchive
-- Add Plausible analytics
-- Global env variables
-- Fix
-- Trial emails
-- Server check instead of app check
-- Show trial instead of sub
-- Server lost connection
-- Services
-- Services
-- Services
-- Ui for services
-- Services
-- Services
-- Services
-- Fixes
-- Fix typo
-
-## [4.0.0-beta.27] - 2023-09-08
-
-### 🐛 Bug Fixes
-
-- Bug
-
-## [4.0.0-beta.26] - 2023-09-08
-
-### 🚀 Features
-
-- Public database
-
-## [4.0.0-beta.25] - 2023-09-07
-
-### 🐛 Bug Fixes
-
-- SaveModel email settings
-
-## [4.0.0-beta.24] - 2023-09-06
-
-### 🚀 Features
-
-- Send request in cloud
-- Add discord notifications
-
-### 🐛 Bug Fixes
-
-- Form address
-- Show hosted email service, just disable for non pro subs
-- Add navbar for source + keys
-- Add docker network to build process
-- Overlapping apps
-- Do not show system wide git on cloud
-- Lowercase image names
-- Typo
-
-### 💼 Other
-
-- Backup existing database
-
-## [4.0.0-beta.23] - 2023-09-01
-
-### 🐛 Bug Fixes
-
-- Sentry bug
-- Button loading animation
-
-## [4.0.0-beta.22] - 2023-09-01
-
-### 🚀 Features
-
-- Add resend as transactional emails
-
-### 🐛 Bug Fixes
-
-- DockerCleanupjob
-- Validation
-- Webhook endpoint in cloud and no system wide gh app
-- Subscriptions
-- Password confirmation
-- Proxy start job
-- Dockerimage jobs are not overlapping
-
-## [4.0.0-beta.21] - 2023-08-27
-
-### 🚀 Features
-
-- Invite by email from waitlist
-- Rolling update
-
-### 🐛 Bug Fixes
-
-- Limits & server creation page
-- Fqdn on apps
-
-### 💼 Other
-
-- Boarding
-
-## [4.0.0-beta.20] - 2023-08-17
-
-### 🚀 Features
-
-- Send internal notification to discord
-- Monitor server connection
-
-### 🐛 Bug Fixes
-
-- Make coolify-db backups unique dir
-
-## [4.0.0-beta.19] - 2023-08-15
-
-### 🚀 Features
-
-- Pricing plans ans subs
-- Add s3 storages
-- Init postgresql database
-- Add backup notifications
-- Dockerfile build pack
-- Cloud
-- Force password reset + waitlist
-
-### 🐛 Bug Fixes
-
-- Remove buggregator from dev
-- Able to change localhost's private key
-- Readonly input box
-- Notifications
-- Licensing
-- Subscription link
-- Migrate db schema for smtp + discord
-- Text field
-- Null fqdn notifications
-- Remove old modal
-- Proxy stop/start ui
-- Proxy UI
-- Empty description
-- Input and textarea
-- Postgres_username name to not name, lol
-- DatabaseBackupJob.php
-- No storage
-- Backup now button
-- Ui + subscription
-- Self-hosted
-
-### 💼 Other
-
-- Scheduled backups
-
-## [4.0.0-beta.18] - 2023-07-14
-
-### 🚀 Features
-
-- Able to control multiplexing
-- Add runRemoteCommandSync
-- Github repo with deployment key
-- Add persistent volumes
-- Debuggable executeNow commands
-- Add private gh repos
-- Delete gh app
-- Installation/update github apps
-- Auto-deploy
-- Deploy key based deployments
-- Resource limits
-- Long running queue with 1 hour of timeout
-- Add arm build to dev
-- Disk cleanup threshold by server
-- Notify user of disk cleanup init
-
-### 🐛 Bug Fixes
-
-- Logo of CCCareers
-- Typo
-- Ssh
-- Nullable name on deploy_keys
-- Enviroments
-- Remove dd - oops
-- Add inprogress activity
-- Application view
-- Only set status in case the last command block is finished
-- Poll activity
-- Small typo
-- Show activity on load
-- Deployment should fail on error
-- Tests
-- Version
-- Status not needed
-- No project redirect
-- Gh actions
-- Set status
-- Seeders
-- Do not modify localhost
-- Deployment_uuid -> type_uuid
-- Read env from config, bc of cache
-- Private key change view
-- New destination
-- Do not update next channel all the time
-- Cancel deployment button
-- Public repo limit shown + branch should be preselected.
-- Better status on ui for apps
-- Arm coolify version
-- Formatting
-- Gh actions
-- Show github app secrets
-- Do not force next version updates
-- Debug log button
-- Deployment key based works
-- Deployment cancel/debug buttons
-- Upgrade button
-- Changing static build changes port
-- Overwrite default nginx configuration
-- Do not overlap docker image names
-- Oops
-- Found image name
-- Name length
-- Semicolons encoding by traefik
-- Base_dir wip & outputs
-- Cleanup docker images
-- Nginx try_files
-- Master is the default, not main
-- No ms in rate limit resets
-- Loading after button text
-- Default value
-- Localhost is usable
-- Update docker-compose prod
-- Cloud/checkoutid/lms
-- Type of license code
-- More verbose error
-- Version lol
-- Update prod compose
-- Version
-
-### 💼 Other
-
-- Extract process handling from async job.
-- Extract process handling from async job.
-- Extract process handling from async job.
-- Extract process handling from async job.
-- Extract process handling from async job.
-- Extract process handling from async job.
-- Extract process handling from async job.
-- Persisting data
-
-## [3.12.28] - 2023-03-16
-
-### 🐛 Bug Fixes
-
-- Revert from dockerhub if ghcr.io does not exists
-
-## [3.12.27] - 2023-03-07
-
-### 🐛 Bug Fixes
-
-- Show ip address as host in public dbs
-
-## [3.12.24] - 2023-03-04
-
-### 🐛 Bug Fixes
-
-- Nestjs buildpack
-
-## [3.12.22] - 2023-03-03
-
-### 🚀 Features
-
-- Add host path to any container
-
-### 🐛 Bug Fixes
-
-- Set PACK_VERSION to 0.27.0
-- PublishDirectory
-- Host volumes
-- Replace . & .. & $PWD with ~
-- Handle log format volumes
-
-## [3.12.19] - 2023-02-20
-
-### 🚀 Features
-
-- Github raw icon url
-- Remove svg support
-
-### 🐛 Bug Fixes
-
-- Typos in docs
-- Url
-- Network in compose files
-- Escape new line chars in wp custom configs
-- Applications cannot be deleted
-- Arm servics
-- Base directory not found
-- Cannot delete resource when you are not on root team
-- Empty port in docker compose
-
-## [3.12.18] - 2023-01-24
-
-### 🐛 Bug Fixes
-
-- CleanupStuckedContainers
-- CleanupStuckedContainers
-
-## [3.12.16] - 2023-01-20
-
-### 🐛 Bug Fixes
-
-- Stucked containers
-
-## [3.12.15] - 2023-01-20
-
-### 🐛 Bug Fixes
-
-- Cleanup function
-- Cleanup stucked containers
-- Deletion + cleanupStuckedContainers
-
-## [3.12.14] - 2023-01-19
-
-### 🐛 Bug Fixes
-
-- Www redirect
-
-## [3.12.13] - 2023-01-18
-
-### 🐛 Bug Fixes
-
-- Secrets
-
-## [3.12.12] - 2023-01-17
-
-### 🚀 Features
-
-- Init h2c (http2/grpc) support
-- Http + h2c paralel
-
-### 🐛 Bug Fixes
-
-- Build args docker compose
-- Grpc
-
-## [3.12.11] - 2023-01-16
-
-### 🐛 Bug Fixes
-
-- Compose file location
-- Docker log sequence
-- Delete apps with previews
-- Do not cleanup compose applications as unconfigured
-- Build env variables with docker compose
-- Public gh repo reload compose
-
-### 💼 Other
-
-- Trpc
-- Trpc
-- Trpc
-- Trpc
-- Trpc
-- Trpc
-- Trpc
-
-## [3.12.10] - 2023-01-11
-
-### 💼 Other
-
-- Add missing variables
-
-## [3.12.9] - 2023-01-11
-
-### 🚀 Features
-
-- Add Openblocks icon
-- Adding icon for whoogle
-- *(ui)* Add libretranslate service icon
-- Handle invite_only plausible analytics
-
-### 🐛 Bug Fixes
-
-- Custom gitlab git user
-- Add documentation link again
-- Remove prefetches
-- Doc link
-- Temporary disable dns check with dns servers
-- Local images for reverting
-- Secrets
-
-## [3.12.8] - 2022-12-27
-
-### 🐛 Bug Fixes
-
-- Parsing secrets
-- Read-only permission
-- Read-only iam
-- $ sign in secrets
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.12.5] - 2022-12-26
-
-### 🐛 Bug Fixes
-
-- Remove unused imports
-
-### 💼 Other
-
-- Conditional on environment
-
-## [3.12.2] - 2022-12-19
-
-### 🐛 Bug Fixes
-
-- Appwrite tmp volume
-- Do not replace secret
-- Root user for dbs on arm
-- Escape secrets
-- Escape env vars
-- Envs
-- Docker buildpack env
-- Secrets with newline
-- Secrets
-- Add default node_env variable
-- Add default node_env variable
-- Secrets
-- Secrets
-- Gh actions
-- Duplicate env variables
-- Cleanupstorage
-
-### 💼 Other
-
-- Trpc
-- Trpc
-- Trpc
-- Trpc
-- Trpc
-- Trpc
-- Trpc
-- Trpc
-- Trpc
-- Trpc
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.12.1] - 2022-12-13
-
-### 🐛 Bug Fixes
-
-- Build commands
-- Migration file
-- Adding missing appwrite volume
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.12.0] - 2022-12-09
-
-### 🚀 Features
-
-- Use registry for building
-- Docker registries working
-- Custom docker compose file location in repo
-- Save doNotTrackData to db
-- Add default sentry
-- Do not track in settings
-- System wide git out of beta
-- Custom previewseparator
-- Sentry frontend
-- Able to host static/php sites on arm
-- Save application data before deploying
-- SimpleDockerfile deployment
-- Able to push image to docker registry
-- Revert to remote image
-- *(api)* Name label
-
-### 🐛 Bug Fixes
-
-- 0 destinations redirect after creation
-- Seed
-- Sentry dsn update
-- Dnt
-- Ui
-- Only visible with publicrepo
-- Migrations
-- Prevent webhook errors to be logged
-- Login error
-- Remove beta from systemwide git
-- Git checkout
-- Remove sentry before migration
-- Webhook previewseparator
-- Apache on arm
-- Update PR/MRs with new previewSeparator
-- Static for arm
-- Failed builds should not push images
-- Turn off autodeploy for simpledockerfiles
-- Security hole
-- Rde
-- Delete resource on dashboard
-- Wrong port in case of docker compose
-- Public db icon on dashboard
-- Cleanup
-
-### 💼 Other
-
-- Pocketbase release
-
-## [3.11.10] - 2022-11-16
-
-### 🚀 Features
-
-- Only show expose if no proxy conf defined in template
-- Custom/private docker registries
-
-### 🐛 Bug Fixes
-
-- Local dev api/ws urls
-- Wrong template/type
-- Gitea icon is svg
-- Gh actions
-- Gh actions
-- Replace $$generate vars
-- Webhook traefik
-- Exposed ports
-- Wrong icons on dashboard
-- Escape % in secrets
-- Move debug log settings to build logs
-- Storage for compose bp + debug on
-- Hasura admin secret
-- Logs
-- Mounts
-- Load logs after build failed
-- Accept logged and not logged user in /base
-- Remote haproxy password/etc
-- Remove hardcoded sentry dsn
-- Nope in database strings
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version++
-- Version++
-- Version++
-
-## [3.11.9] - 2022-11-15
-
-### 🐛 Bug Fixes
-
-- IsBot issue
-
-## [3.11.8] - 2022-11-14
-
-### 🐛 Bug Fixes
-
-- Default icon for new services
-
-## [3.11.1] - 2022-11-08
-
-### 🚀 Features
-
-- Rollback coolify
-
-### 🐛 Bug Fixes
-
-- Remove contribution docs
-- Umami template
-- Compose webhooks fixed
-- Variable replacements
-- Doc links
-- For rollback
-- N8n and weblate icon
-- Expose ports for services
-- Wp + mysql on arm
-- Show rollback button loading
-- No tags error
-- Update on mobile
-- Dashboard error
-- GetTemplates
-- Docker compose persistent volumes
-- Application persistent storage things
-- Volume names for undefined volume names in compose
-- Empty secrets on UI
-- Ports for services
-
-### 💼 Other
-
-- Secrets on apps
-- Fix
-- Fixes
-- Reload compose loading
-
-### 🚜 Refactor
-
-- Code
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Add jda icon for lavalink service
-- Version++
-
-### ◀️ Revert
-
-- Revert: revert
-
-## [3.11.0] - 2022-11-07
-
-### 🚀 Features
-
-- Initial support for specific git commit
-- Add default to latest commit and support for gitlab
-- Redirect catch-all rule
-
-### 🐛 Bug Fixes
-
-- Secret errors
-- Service logs
-- Heroku bp
-- Expose port is readonly on the wrong condition
-- Toast
-- Traefik proxy q 10s
-- App logs view
-- Tooltip
-- Toast, rde, webhooks
-- Pathprefix
-- Load public repos
-- Webhook simplified
-- Remote webhooks
-- Previews wbh
-- Webhooks
-- Websecure redirect
-- Wb for previews
-- Pr stopps main deployment
-- Preview wbh
-- Wh catchall for all
-- Remove old minio proxies
-- Template files
-- Compose icon
-- Templates
-- Confirm restart service
-- Template
-- Templates
-- Templates
-- Plausible analytics things
-- Appwrite webhook
-- Coolify instance proxy
-- Migrate template
-- Preview webhooks
-- Simplify webhooks
-- Remove ghost-mariadb from the list
-- More simplified webhooks
-- Umami + ghost issues
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.10.16] - 2022-10-12
-
-### 🐛 Bug Fixes
-
-- Single container logs and usage with compose
-
-### 💼 Other
-
-- New resource label
-
-## [3.10.15] - 2022-10-12
-
-### 🚀 Features
-
-- Monitoring by container
-
-### 🐛 Bug Fixes
-
-- Do not show nope as ip address for dbs
-- Add git sha to build args
-- Smart search for new services
-- Logs for not running containers
-- Update docker binaries
-- Gh release
-- Dev container
-- Gitlab auth and compose reload
-- Check compose domains in general
-- Port required if fqdn is set
-- Appwrite v1 missing containers
-- Dockerfile
-- Pull does not work remotely on huge compose file
-
-### ⚙️ Miscellaneous Tasks
-
-- Update staging release
-
-## [3.10.14] - 2022-10-05
-
-### 🚀 Features
-
-- Docker compose support
-- Docker compose
-- Docker compose
-
-### 🐛 Bug Fixes
-
-- Do not use npx
-- Pure docker based development
-
-### 💼 Other
-
-- Docker-compose support
-- Docker compose
-- Remove worker jobs
-- One less worker thread
-
-### 🧪 Testing
-
-- Remove prisma
-
-## [3.10.5] - 2022-09-26
-
-### 🚀 Features
-
-- Add migration button to appwrite
-- Custom certificate
-- Ssl cert on traefik config
-- Refresh resource status on dashboard
-- Ssl certificate sets custom ssl for applications
-- System-wide github apps
-- Cleanup unconfigured applications
-- Cleanup unconfigured services and databases
-
-### 🐛 Bug Fixes
-
-- Ui
-- Tooltip
-- Dropdown
-- Ssl certificate distribution
-- Db migration
-- Multiplex ssh connections
-- Able to search with id
-- Not found redirect
-- Settings db requests
-- Error during saving logs
-- Consider base directory in heroku bp
-- Basedirectory should be empty if null
-- Allow basedirectory for heroku
-- Stream logs for heroku bp
-- Debug log for bp
-- Scp without host verification & cert copy
-- Base directory & docker bp
-- Laravel php chooser
-- Multiplex ssh and ssl copy
-- Seed new preview secret types
-- Error notification
-- Empty preview value
-- Error notification
-- Seed
-- Service logs
-- Appwrite function network is not the default
-- Logs in docker bp
-- Able to delete apps in unconfigured state
-- Disable development low disk space
-- Only log things to console in dev mode
-- Do not get status of more than 10 resources defined by category
-- BaseDirectory
-- Dashboard statuses
-- Default buildImage and baseBuildImage
-- Initial deploy status
-- Show logs better
-- Do not start tcp proxy without main container
-- Cleanup stucked tcp proxies
-- Default 0 pending invitations
-- Handle forked repositories
-- Typo
-- Pr branches
-- Fork pr previews
-- Remove unnecessary things
-- Meilisearch data dir
-- Verify and configure remote docker engines
-- Add buildkit features
-- Nope if you are not logged in
-
-### 💼 Other
-
-- Responsive!
-- Fixes
-- Fix git icon
-- Dropdown as infobox
-- Small logs on mobile
-- Improvements
-- Fix destination view
-- Settings view
-- More UI improvements
-- Fixes
-- Fixes
-- Fix
-- Fixes
-- Beta features
-- Fix button
-- Service fixes
-- Fix basedirectory meaning
-- Resource button fix
-- Main resource search
-- Dev logs
-- Loading button
-- Fix gitlab importer view
-- Small fix
-- Beta flag
-- Hasura console notification
-- Fix
-- Fix
-- Fixes
-- Inprogress version of iam
-- Fix indicato
-- Iam & settings update
-- Send 200 for ping and installation wh
-- Settings icon
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version++
-- Version++
-- Version++
-- Version++
-- Version++
-- Version++
-
-### ◀️ Revert
-
-- Show usage everytime
-
-## [3.10.2] - 2022-09-11
-
-### 🚀 Features
-
-- Add queue reset button
-- Previewapplications init
-- PreviewApplications finalized
-- Fluentbit
-- Show remote servers
-- *(layout)* Added drawer when user is in mobile
-- Re-apply ui improves
-- *(ui)* Improve header of pages
-- *(styles)* Make header css component
-- *(routes)* Improve ui for apps, databases and services logs
-
-### 🐛 Bug Fixes
-
-- Changing umami image URL to get latest version
-- Gitlab importer for public repos
-- Show error logs
-- Umami init sql
-- Plausible analytics actions
-- Login
-- Dev url
-- UpdateMany build logs
-- Fallback to db logs
-- Fluentbit configuration
-- Coolify update
-- Fluentbit and logs
-- Canceling build
-- Logging
-- Load more
-- Build logs
-- Versions of appwrite
-- Appwrite?!
-- Get building status
-- Await
-- Await #2
-- Update PR building status
-- Appwrite default version 1.0
-- Undead endpoint does not require JWT
-- *(routes)* Improve design of application page
-- *(routes)* Improve design of git sources page
-- *(routes)* Ui from destinations page
-- *(routes)* Ui from databases page
-- *(routes)* Ui from databases page
-- *(routes)* Ui from databases page
-- *(routes)* Ui from services page
-- *(routes)* More ui tweaks
-- *(routes)* More ui tweaks
-- *(routes)* More ui tweaks
-- *(routes)* More ui tweaks
-- *(routes)* Ui from settings page
-- *(routes)* Duplicates classes in services page
-- *(routes)* Searchbar ui
-- Github conflicts
-- *(routes)* More ui tweaks
-- *(routes)* More ui tweaks
-- *(routes)* More ui tweaks
-- *(routes)* More ui tweaks
-- Ui with headers
-- *(routes)* Header of settings page in databases
-- *(routes)* Ui from secrets table
-
-### 💼 Other
-
-- Fix plausible
-- Fix cleanup button
-- Fix buttons
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Minor changes
-- Minor changes
-- Minor changes
-- Whoops
-
-## [3.10.1] - 2022-09-10
-
-### 🐛 Bug Fixes
-
-- Show restarting apps
-- Show restarting application & logs
-- Remove unnecessary gitlab group name
-- Secrets for PR
-- Volumes for services
-- Build secrets for apps
-- Delete resource use window location
-
-### 💼 Other
-
-- Fix button
-- Fix follow button
-- Arm should be on next all the time
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.10.0] - 2022-09-08
-
-### 🚀 Features
-
-- New servers view
-
-### 🐛 Bug Fixes
-
-- Change to execa from utils
-- Save search input
-- Ispublic status on databases
-- Port checkers
-- Ui variables
-- Glitchtip env to pyhton boolean
-- Autoupdater
-
-### 💼 Other
-
-- Dashboard updates
-- Fix tooltip
-
-## [3.9.4] - 2022-09-07
-
-### 🐛 Bug Fixes
-
-- DnsServer formatting
-- Settings for service
-
-## [3.9.3] - 2022-09-07
-
-### 🐛 Bug Fixes
-
-- Pr previews
-
-## [3.9.2] - 2022-09-07
-
-### 🚀 Features
-
-- Add traefik acme json to coolify container
-- Database secrets
-
-### 🐛 Bug Fixes
-
-- Gitlab webhook
-- Use ip address instead of window location
-- Use ip instead of window location host
-- Service state update
-- Add initial DNS servers
-- Revert last change with domain check
-- Service volume generation
-- Minio default env variables
-- Add php 8.1/8.2
-- Edgedb ui
-- Edgedb stuff
-- Edgedb
-
-### 💼 Other
-
-- Fix login/register page
-- Update devcontainer
-- Add debug log
-- Fix initial loading icon bg
-- Fix loading start/stop db/services
-- Dashboard updates and a lot more
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version++
-
-## [3.9.0] - 2022-09-06
-
-### 🐛 Bug Fixes
-
-- Debug api logging + gh actions
-- Workdir
-- Move restart button to settings
-
-## [3.9.1-rc.1] - 2022-09-06
-
-### 🚀 Features
-
-- *(routes)* Rework ui from login and register page
-
-### 🐛 Bug Fixes
-
-- Ssh pid agent name
-- Repository link trim
-- Fqdn or expose port required
-- Service deploymentEnabled
-- Expose port is not required
-- Remote verification
-- Dockerfile
-
-### 💼 Other
-
-- Database_branches
-- Login page
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version++
-
-## [3.9.0-rc.1] - 2022-09-02
-
-### 🚀 Features
-
-- New service - weblate
-- Restart application
-- Show elapsed time on running builds
-- Github allow fual branches
-- Gitlab dual branch
-- Taiga
-
-### 🐛 Bug Fixes
-
-- Glitchtip things
-- Loading state on start
-- Ui
-- Submodule
-- Gitlab webhooks
-- UI + refactor
-- Exposedport on save
-- Appwrite letsencrypt
-- Traefik appwrite
-- Traefik
-- Finally works! :)
-- Rename components + remove PR/MR deployment from public repos
-- Settings missing id
-- Explainer component
-- Database name on logs view
-- Taiga
-
-### 💼 Other
-
-- Fixes
-- Change tooltips and info boxes
-- Added rc release
-
-### 🧪 Testing
-
-- Native binary target
-- Dockerfile
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.8.9] - 2022-08-30
-
-### 🐛 Bug Fixes
-
-- Oh god Prisma
-
-## [3.8.8] - 2022-08-30
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.8.6] - 2022-08-30
-
-### 🐛 Bug Fixes
-
-- Pr deployment
-- CompareVersions
-- Include
-- Include
-- Gitlab apps
-
-### 💼 Other
-
-- Fixes
-- Route to the correct path when creating destination from db config
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.8.5] - 2022-08-27
-
-### 🐛 Bug Fixes
-
-- Copy all files during install process
-- Typo
-- Process
-- White labeled icon on navbar
-- Whitelabeled icon
-- Next/nuxt deployment type
-- Again
-
-## [3.8.4] - 2022-08-27
-
-### 🐛 Bug Fixes
-
-- UI thinkgs
-- Delete team while it is active
-- Team switching
-- Queue cleanup
-- Decrypt secrets
-- Cleanup build cache as well
-- Pr deployments + remove public gits
-
-### 💼 Other
-
-- Dashbord fixes
-- Fixes
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.8.3] - 2022-08-26
-
-### 🐛 Bug Fixes
-
-- Secrets decryption
-
-## [3.8.2] - 2022-08-26
-
-### 🚀 Features
-
-- *(ui)* Rework home UI and with responsive design
-
-### 🐛 Bug Fixes
-
-- Never stop deplyo queue
-- Build queue system
-- High cpu usage
-- Worker
-- Better worker system
-
-### 💼 Other
-
-- Dashboard fine-tunes
-- Fine-tune
-- Fixes
-- Fix
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.8.1] - 2022-08-24
-
-### 🐛 Bug Fixes
-
-- Ui buttons
-- Clear queue on cancelling jobs
-- Cancelling jobs
-- Dashboard for admins
-
-## [3.8.0] - 2022-08-23
-
-### 🚀 Features
-
-- Searxng service
-
-### 🐛 Bug Fixes
-
-- Port checker
-- Cancel build after 5 seconds
-- ExposedPort checker
-- Batch secret =
-- Dashboard for non-root users
-- Stream build logs
-- Show build log start/end
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.7.0] - 2022-08-19
-
-### 🚀 Features
-
-- Add GlitchTip service
-
-### 🐛 Bug Fixes
-
-- Missing commas
-- ExposedPort is just optional
-
-### ⚙️ Miscellaneous Tasks
-
-- Add .pnpm-store in .gitignore
-- Version++
-
-## [3.6.0] - 2022-08-18
-
-### 🚀 Features
-
-- Import public repos (wip)
-- Public repo deployment
-- Force rebuild + env.PORT for port + public repo build
-
-### 🐛 Bug Fixes
-
-- Bots without exposed ports
-
-### 💼 Other
-
-- Fixes here and there
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.5.2] - 2022-08-17
-
-### 🐛 Bug Fixes
-
-- Restart containers on-failure instead of always
-- Show that Ghost values could be changed
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.5.1] - 2022-08-17
-
-### 🐛 Bug Fixes
-
-- Revert docker compose version to 2.6.1
-- Trim secrets
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.5.0] - 2022-08-17
-
-### 🚀 Features
-
-- Deploy bots (no domains)
-- Custom dns servers
-
-### 🐛 Bug Fixes
-
-- Dns button ui
-- Bot deployments
-- Bots
-- AutoUpdater & cleanupStorage jobs
-
-### 💼 Other
-
-- Typing
-
-## [3.4.0] - 2022-08-16
-
-### 🚀 Features
-
-- Appwrite service
-- Heroku deployments
-
-### 🐛 Bug Fixes
-
-- Replace docker compose with docker-compose on CSB
-- Dashboard ui
-- Create coolify-infra, if it does not exists
-- Gitpod conf and heroku buildpacks
-- Appwrite
-- Autoimport + readme
-- Services import
-- Heroku icon
-- Heroku icon
-
-## [3.3.4] - 2022-08-15
-
-### 🐛 Bug Fixes
-
-- Make it public button
-- Loading indicator
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.3.3] - 2022-08-14
-
-### 🐛 Bug Fixes
-
-- Decryption errors
-- Postgresql on ARM
-
-## [3.3.2] - 2022-08-12
-
-### 🐛 Bug Fixes
-
-- Debounce dashboard status requests
-
-### 💼 Other
-
-- Fider
-
-## [3.3.1] - 2022-08-12
-
-### 🐛 Bug Fixes
-
-- Empty buildpack icons
-
-## [3.2.3] - 2022-08-12
-
-### 🚀 Features
-
-- Databases on ARM
-- Mongodb arm support
-- New dashboard
-
-### 🐛 Bug Fixes
-
-- Cleanup stucked prisma-engines
-- Toast
-- Secrets
-- Cleanup prisma engine if there is more than 1
-- !isARM to isARM
-- Enterprise GH link
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.2.2] - 2022-08-11
-
-### 🐛 Bug Fixes
-
-- Coolify-network on verification
-
-## [3.2.1] - 2022-08-11
-
-### 🚀 Features
-
-- Init heroku buildpacks
-
-### 🐛 Bug Fixes
-
-- Follow/cancel buttons
-- Only remove coolify managed containers
-- White-labeled env
-- Schema
-
-### 💼 Other
-
-- Fix
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.2.0] - 2022-08-11
-
-### 🚀 Features
-
-- Persistent storage for all services
-- Cleanup clickhouse db
-
-### 🐛 Bug Fixes
-
-- Rde local ports
-- Empty remote destinations could be removed
-- Tips
-- Lowercase issues fider
-- Tooltip colors
-- Update clickhouse configuration
-- Cleanup command
-- Enterprise Github instance endpoint
-
-### 💼 Other
-
-- Local ssh port
-- Redesign a lot
-- Fixes
-- Loading indicator for plausible buttons
-
-## [3.1.4] - 2022-08-01
-
-### 🚀 Features
-
-- Moodle init
-- Remote docker engine init
-- Working on remote docker engine
-- Rde
-- Remote docker engine
-- Ipv4 and ipv6
-- Contributors
-- Add arch to database
-- Stop preview deployment
-
-### 🐛 Bug Fixes
-
-- Settings from api
-- Selectable destinations
-- Gitpod hardcodes
-- Typo
-- Typo
-- Expose port checker
-- States and exposed ports
-- CleanupStorage
-- Remote traefik webhook
-- Remote engine ip address
-- RemoteipAddress
-- Explanation for remote engine url
-- Tcp proxy
-- Lol
-- Webhook
-- Dns check for rde
-- Gitpod
-- Revert last commit
-- Dns check
-- Dns checker
-- Webhook
-- Df and more debug
-- Webhooks
-- Load previews async
-- Destination icon
-- Pr webhook
-- Cache image
-- No ssh key found
-- Prisma migration + update of docker and stuffs
-- Ui
-- Ui
-- Only 1 ssh-agent is needed
-- Reuse ssh connection
-- Ssh tunnel
-- Dns checking
-- Fider BASE_URL set correctly
-
-### 💼 Other
-
-- Error message https://github.com/coollabsio/coolify/issues/502
-- Changes
-- Settings
-- For removing app
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.1.3] - 2022-07-18
-
-### 🚀 Features
-
-- Init moodle and separate stuffs to shared package
-
-### 🐛 Bug Fixes
-
-- More types for API
-- More types
-- Do not rebuild in case image exists and sha not changed
-- Gitpod urls
-- Remove new service start process
-- Remove shared dir, deployment does not work
-- Gitlab custom url
-- Location url for services and apps
-
-## [3.1.2] - 2022-07-14
-
-### 🐛 Bug Fixes
-
-- Admin password reset should not timeout
-- Message for double branches
-- Turn off autodeploy if double branch is configured
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.1.1] - 2022-07-13
-
-### 🚀 Features
-
-- Gitpod integration
-
-### 🐛 Bug Fixes
-
-- Cleanup less often and can do it manually
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version++
-
-## [3.1.0] - 2022-07-12
-
-### 🚀 Features
-
-- Ability to change deployment type for nextjs
-- Ability to change deployment type for nuxtjs
-- Gitpod ready code(almost)
-- Add Docker buildpack exposed port setting
-- Custom port for git instances
-
-### 🐛 Bug Fixes
-
-- GitLab pagination load data
-- Service domain checker
-- Wp missing ftp solution
-- Ftp WP issues
-- Ftp?!
-- Gitpod updates
-- Gitpod
-- Gitpod
-- Wordpress FTP permission issues
-- GitLab search fields
-- GitHub App button
-- GitLab loop on misconfigured source
-- Gitpod
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [3.0.3] - 2022-07-06
-
-### 🐛 Bug Fixes
-
-- Domain check
-- Domain check
-- TrustProxy for Fastify
-- Hostname issue
-
-## [3.0.2] - 2022-07-06
-
-### 🐛 Bug Fixes
-
-- New destination can be created
-- Include post
-- New destinations
-
-## [3.0.1] - 2022-07-06
-
-### 🐛 Bug Fixes
-
-- Seeding
-- Forgot that the version bump changed 😅
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.9.11] - 2022-06-20
-
-### 🐛 Bug Fixes
-
-- Be able to change database + service versions
-- Lock file
-
-## [2.9.10] - 2022-06-17
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.9.9] - 2022-06-10
-
-### 🐛 Bug Fixes
-
-- Host and reload for uvicorn
-- Remove package-lock
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.9.8] - 2022-06-10
-
-### 🐛 Bug Fixes
-
-- Persistent nocodb
-- Nocodb persistency
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.9.7] - 2022-06-09
-
-### 🐛 Bug Fixes
-
-- Plausible custom script
-- Plausible script and middlewares
-- Remove console log
-- Remove comments
-- Traefik middleware
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.9.6] - 2022-06-02
-
-### 🐛 Bug Fixes
-
-- Fider changed an env variable name
-- Pnpm command
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.9.5] - 2022-06-02
-
-### 🐛 Bug Fixes
-
-- Proxy stop missing argument
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.9.4] - 2022-06-01
-
-### 🐛 Bug Fixes
-
-- Demo version forms
-- Typo
-- Revert gh and gl cloning
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.9.3] - 2022-05-31
-
-### 🐛 Bug Fixes
-
-- Recurisve clone instead of submodule
-- Versions
-- Only reconfigure coolify proxy if its missconfigured
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.9.2] - 2022-05-31
-
-### 🐛 Bug Fixes
-
-- TrustProxy
-- Force restart proxy
-- Only restart coolify proxy in case of version prior to 2.9.2
-- Force restart proxy on seeding
-- Add GIT ENV variable for submodules
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.9.1] - 2022-05-31
-
-### 🐛 Bug Fixes
-
-- GitHub fixes
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.9.0] - 2022-05-31
-
-### 🚀 Features
-
-- PageLoader
-- Database + service usage
-
-### 🐛 Bug Fixes
-
-- Service checks
-- Remove console.log
-- Traefik
-- Remove debug things
-- WIP Traefik
-- Proxy for http
-- PR deployments view
-- Minio urls + domain checks
-- Remove gh token on git source changes
-- Do not fetch app state in case of missconfiguration
-- Demo instance save domain instantly
-- Instant save on demo instance
-- New source canceled view
-- Lint errors in database services
-- Otherfqdns
-- Host key verification
-- Ftp connection
-
-### 💼 Other
-
-- Appwrite
-- Testing WS
-- Traefik?!
-- Traefik
-- Traefik
-- Traefik migration
-- Traefik
-- Traefik
-- Traefik
-- Notifications and application usage
-- *(fix)* Traefik
-- Css
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.8.2] - 2022-05-16
-
-### 🐛 Bug Fixes
-
-- Gastby buildpack
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.8.1] - 2022-05-10
-
-### 🐛 Bug Fixes
-
-- WP custom db
-- UI
-
-## [2.6.1] - 2022-05-03
-
-### 🚀 Features
-
-- Basic server usage on dashboard
-- Show usage trends
-- Usage on dashboard
-- Custom script path for Plausible
-- WP could have custom db
-- Python image selection
-
-### 🐛 Bug Fixes
-
-- ExposedPorts
-- Logos for dbs
-- Do not run SSL renew in development
-- Check domain for coolify before saving
-- Remove debug info
-- Cancel jobs
-- Cancel old builds in database
-- Better DNS check to prevent errors
-- Check DNS in prod only
-- DNS check
-- Disable sentry for now
-- Cancel
-- Sentry
-- No image for Docker buildpack
-- Default packagemanager
-- Server usage only shown for root team
-- Expose ports for services
-- UI
-- Navbar UI
-- UI
-- UI
-- Remove RC python
-- UI
-- UI
-- UI
-- Default Python package
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version++
-- Version++
-- Version++
-
-## [2.6.0] - 2022-05-02
-
-### 🚀 Features
-
-- Hasura as a service
-- Gzip compression
-- Laravel buildpack is working!
-- Laravel
-- Fider service
-- Database and services logs
-- DNS check settings for SSL generation
-- Cancel builds!
-
-### 🐛 Bug Fixes
-
-- Unami svg size
-- Team switching moved to IAM menu
-- Always use IP address for webhooks
-- Remove unnecessary test endpoint
-- UI
-- Migration
-- Fider envs
-- Checking low disk space
-- Build image
-- Update autoupdate env variable
-- Renew certificates
-- Webhook build images
-- Missing node versions
-
-### 💼 Other
-
-- Laravel
-
-## [2.4.11] - 2022-04-20
-
-### 🚀 Features
-
-- Deno DB migration
-- Show exited containers on UI & better UX
-- Query container state periodically
-- Install svelte-18n and init setup
-- Umami service
-- Coolify auto-updater
-- Autoupdater
-- Select base image for buildpacks
-
-### 🐛 Bug Fixes
-
-- Deno configurations
-- Text on deno buildpack
-- Correct branch shown in build logs
-- Vscode permission fix
-- I18n
-- Locales
-- Application logs is not reversed and queried better
-- Do not activate i18n for now
-- GitHub token cleanup on team switch
-- No logs found
-- Code cleanups
-- Reactivate posgtres password
-- Contribution guide
-- Simplify list services
-- Contribution
-- Contribution guide
-- Contribution guide
-- Packagemanager finder
-
-### 💼 Other
-
-- Umami service
-- Base image selector
-
-### 📚 Documentation
-
-- How to add new services
-- Update
-- Update
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version++
-- Version++
-
-## [2.4.10] - 2022-04-17
-
-### 🚀 Features
-
-- Add persistent storage for services
-- Multiply dockerfile locations for docker buildpack
-- Testing fluentd logging driver
-- Fluentbit investigation
-- Initial deno support
-
-### 🐛 Bug Fixes
-
-- Switch from bitnami/redis to normal redis
-- Use redis-alpine
-- Wordpress extra config
-- Stop sFTP connection on wp stop
-- Change user's id in sftp wp instance
-- Use arm based certbot on arm
-- Buildlog line number is not string
-- Application logs paginated
-- Switch to stream on applications logs
-- Scroll to top for logs
-- Pull new images for services all the time it's started.
-- White-labeled custom logo
-- Application logs
-
-### 💼 Other
-
-- Show extraconfig if wp is running
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version++
-
-## [2.4.9] - 2022-04-14
-
-### 🐛 Bug Fixes
-
-- Postgres root pw is pw field
-- Teams view
-- Improved tcp proxy monitoring for databases/ftp
-- Add HTTP proxy checks
-- Loading of new destinations
-- Better performance for cleanup images
-- Remove proxy container in case of dependent container is down
-- Restart local docker coolify proxy in case of something happens to it
-- Id of service container
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.4.8] - 2022-04-13
-
-### 🐛 Bug Fixes
-
-- Register should happen if coolify proxy cannot be started
-- GitLab typo
-- Remove system wide pw reset
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.4.7] - 2022-04-13
-
-### 🐛 Bug Fixes
-
-- Destinations to HAProxy
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.4.6] - 2022-04-13
-
-### 🐛 Bug Fixes
-
-- Cleanup images older than a day
-- Meilisearch service
-- Load all branches, not just the first 30
-- ProjectID for Github
-- DNS check before creating SSL cert
-- Try catch me
-- Restart policy for resources
-- No permission on first registration
-- Reverting postgres password for now
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.4.5] - 2022-04-12
-
-### 🐛 Bug Fixes
-
-- Types
-- Invitations
-- Timeout values
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.4.4] - 2022-04-12
-
-### 🐛 Bug Fixes
-
-- Haproxy build stuffs
-- Proxy
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.4.3] - 2022-04-12
-
-### 🐛 Bug Fixes
-
-- Remove unnecessary save button haha
-- Update dockerfile
-
-### ⚙️ Miscellaneous Tasks
-
-- Update packages
-- Version++
-- Update build scripts
-- Update build packages
-
-## [2.4.2] - 2022-04-09
-
-### 🐛 Bug Fixes
-
-- Missing install repositories GitHub
-- Return own and other sources better
-- Show config missing on sources
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.4.1] - 2022-04-09
-
-### 🐛 Bug Fixes
-
-- Enable https for Ghost
-- Postgres root passwor shown and set
-- Able to change postgres user password from ui
-- DB Connecting string generator
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.4.0] - 2022-04-08
-
-### 🚀 Features
-
-- Wordpress on-demand SFTP
-- Finalize on-demand sftp for wp
-- PHP Composer support
-- Working on-demand sftp to wp data
-- Admin team sees everything
-- Able to change service version/tag
-- Basic white labeled version
-- Able to modify database passwords
-
-### 🐛 Bug Fixes
-
-- Add openssl to image
-- Permission issues
-- On-demand sFTP for wp
-- Fix for fix haha
-- Do not pull latest image
-- Updated db versions
-- Only show proxy for admin team
-- Team view for root team
-- Do not trigger >1 webhooks on GitLab
-- Possible fix for spikes in CPU usage
-- Last commit
-- Www or not-www, that's the question
-- Fix for the fix that fixes the fix
-- Ton of updates for users/teams
-- Small typo
-- Unique storage paths
-- Self-hosted GitLab URL
-- No line during buildLog
-- Html/apiUrls cannot end with /
-- Typo
-- Missing buildpack
-
-### 💼 Other
-
-- Fix
-- Better layout for root team
-- Fix
-- Fixes
-- Fix
-- Fix
-- Fix
-- Fix
-- Fix
-- Fix
-- Fix
-- Insane amount
-- Fix
-- Fixes
-- Fixes
-- Fix
-- Fixes
-- Fixes
-
-### 📚 Documentation
-
-- Contribution guide
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.3.3] - 2022-04-05
-
-### 🐛 Bug Fixes
-
-- Add git lfs while deploying
-- Try to update build status several times
-- Update stucked builds
-- Update stucked builds on startup
-- Revert seed
-- Lame fixing
-- Remove asyncUntil
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.3.2] - 2022-04-04
-
-### 🐛 Bug Fixes
-
-- *(php)* If .htaccess file found use apache
-- Add default webhook domain for n8n
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.3.1] - 2022-04-04
-
-### 🐛 Bug Fixes
-
-- Secrets build/runtime coudl be changed after save
-- Default configuration
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.3.0] - 2022-04-04
-
-### 🚀 Features
-
-- Initial python support
-- Add loading on register button
-- *(dev)* Allow windows users to use pnpm dev
-- MeiliSearch service
-- Add abilitry to paste env files
-
-### 🐛 Bug Fixes
-
-- Ignore coolify proxy error for now
-- Python no wsgi
-- If user not found
-- Rename envs to secrets
-- Infinite loop on www domains
-- No need to paste clear text env for previews
-- Build log fix attempt #1
-- Small UI fix on logs
-- Lets await!
-- Async progress
-- Remove console.log
-- Build log
-- UI
-- Gitlab & Github urls
-
-### 💼 Other
-
-- Improvements
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version++
-- Lock file + fix packages
-
-## [2.2.7] - 2022-04-01
-
-### 🐛 Bug Fixes
-
-- Haproxy errors
-- Build variables
-- Use NodeJS for sveltekit for now
-
-## [2.2.6] - 2022-03-31
-
-### 🐛 Bug Fixes
-
-- Add PROTO headers
-
-## [2.2.5] - 2022-03-31
-
-### 🐛 Bug Fixes
-
-- Registration enabled/disabled
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.2.4] - 2022-03-31
-
-### 🐛 Bug Fixes
-
-- Gitlab repo url
-- No need to dashify anymore
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.2.3] - 2022-03-31
-
-### 🐛 Bug Fixes
-
-- List ghost services
-- Reload window on settings saved
-- Persistent storage on webhooks
-- Add license
-- Space in repo names
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version++
-- Version++
-- Fixed typo on New Git Source view
-
-## [2.2.0] - 2022-03-27
-
-### 🚀 Features
-
-- Add n8n.io service
-- Add update kuma service
-- Ghost service
-
-### 🐛 Bug Fixes
-
-- Ghost logo size
-- Ghost icon, remove console.log
-
-### 💼 Other
-
-- Colors on svelte-select
-
-### ⚙️ Miscellaneous Tasks
-
-- Version ++
-
-## [2.1.1] - 2022-03-25
-
-### 🐛 Bug Fixes
-
-- Cleanup only 2 hours+ old images
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.1.0] - 2022-03-23
-
-### 🚀 Features
-
-- Use compose instead of normal docker cmd
-- Be able to redeploy PRs
-
-### 🐛 Bug Fixes
-
-- Skip ssl cert in case of error
-- Volumes
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.31] - 2022-03-20
-
-### 🚀 Features
-
-- Add PHP modules
-
-### 🐛 Bug Fixes
-
-- Cleanup old builds
-- Only cleanup same app
-- Add nginx + htaccess files
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.30] - 2022-03-19
-
-### 🐛 Bug Fixes
-
-- No cookie found
-- Missing session data
-- No error if GitSource is missing
-- No webhook secret found?
-- Basedir for dockerfiles
-- Better queue system + more support on monorepos
-- Remove build logs in case of app removed
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.29] - 2022-03-11
-
-### 🚀 Features
-
-- Webhooks inititate all applications with the correct branch
-- Check ssl for new apps/services first
-- Autodeploy pause
-- Install pnpm into docker image if pnpm lock file is used
-
-### 🐛 Bug Fixes
-
-- Personal Gitlab repos
-- Autodeploy true by default for GH repos
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.28] - 2022-03-04
-
-### 🚀 Features
-
-- Service secrets
-
-### 🐛 Bug Fixes
-
-- Do not error if proxy is not running
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.27] - 2022-03-02
-
-### 🚀 Features
-
-- Send version with update request
-
-### 🐛 Bug Fixes
-
-- Check when a container is running
-- Reload haproxy if new cert is added
-- Cleanup coolify images
-- Application state in UI
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.26] - 2022-03-02
-
-### 🐛 Bug Fixes
-
-- Update process
-
-## [2.0.25] - 2022-03-02
-
-### 🚀 Features
-
-- Languagetool service
-
-### 🐛 Bug Fixes
-
-- Reload proxy on ssl cert
-- Volume name
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.24] - 2022-03-02
-
-### 🐛 Bug Fixes
-
-- Better proxy check
-- Ssl + sslrenew
-- Null proxyhash on restart
-- Reconfigure proxy on restart
-- Update process
-
-## [2.0.23] - 2022-02-28
-
-### 🐛 Bug Fixes
-
-- Be sure .env exists
-- Missing fqdn for services
-- Default npm command
-- Add coolify-image label for build images
-- Cleanup old images, > 3 days
-
-### 💼 Other
-
-- Colorful states
-- Application start
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.22] - 2022-02-27
-
-### 🐛 Bug Fixes
-
-- Coolify image pulls
-- Remove wrong/stuck proxy configurations
-- Always use a buildpack
-- Add icons for eleventy + astro
-- Fix proxy every 10 secs
-- Do not remove coolify proxy
-- Update version
-
-### 💼 Other
-
-- Remote docker engine
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.21] - 2022-02-24
-
-### 🚀 Features
-
-- Random subdomain for demo
-- Random domain for services
-- Astro buildpack
-- 11ty buildpack
-- Registration page
-
-### 🐛 Bug Fixes
-
-- Http for demo, oops
-- Docker scanner
-- Improvement on image pulls
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.20] - 2022-02-23
-
-### 🐛 Bug Fixes
-
-- Revert default network
-
-### 💼 Other
-
-- Dns check
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.19] - 2022-02-23
-
-### 🐛 Bug Fixes
-
-- Random network name for demo
-- Settings fqdn grr
-
-## [2.0.18] - 2022-02-22
-
-### 🚀 Features
-
-- Ports range
-
-### 🐛 Bug Fixes
-
-- Email is lowercased in login
-- Lowercase email everywhere
-- Use normal docker-compose in dev
-
-### 💼 Other
-
-- Make copy/password visible
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.17] - 2022-02-21
-
-### 🐛 Bug Fixes
-
-- Move tokens from session to cookie/store
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.14] - 2022-02-18
-
-### 🚀 Features
-
-- Basic password reset form
-- Scan for lock files and set right commands
-- Public port range (WIP)
-
-### 🐛 Bug Fixes
-
-- SSL app off
-- Local docker host
-- Typo
-- Lets encrypt
-- Remove SSL with stop
-- SSL off for services
-- Grr
-- Running state css
-- Minor fixes
-- Remove force SSL when doing let's encrypt request
-- GhToken in session now
-- Random port for certbot
-- Follow icon
-- Plausible volume fixed
-- Database connection strings
-- Gitlab webhooks fixed
-- If DNS not found, do not redirect
-- Github token
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version ++
-
-## [2.0.13] - 2022-02-17
-
-### 🐛 Bug Fixes
-
-- Login issues
-
-## [2.0.11] - 2022-02-15
-
-### 🚀 Features
-
-- Follow logs
-- Generate www & non-www SSL certs
-
-### 🐛 Bug Fixes
-
-- Window error in SSR
-- GitHub sync PR's
-- Load more button
-- Small fixes
-- Typo
-- Error with follow logs
-- IsDomainConfigured
-- TransactionIds
-- Coolify image cleanup
-- Cleanup every 10 mins
-- Cleanup images
-- Add no user redis to uri
-- Secure cookie disabled by default
-- Buggy svelte-kit-cookie-session
-
-### 💼 Other
-
-- Only allow cleanup in production
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-- Version++
-
-## [2.0.10] - 2022-02-15
-
-### 🐛 Bug Fixes
-
-- Typo
-- Error handling
-- Stopping service without proxy
-- Coolify proxy start
-
-### ⚙️ Miscellaneous Tasks
-
-- Version++
-
-## [2.0.8] - 2022-02-14
-
-### 🐛 Bug Fixes
-
-- Validate secrets
-- Truncate git clone errors
-- Branch used does not throw error
-
-## [2.0.7] - 2022-02-13
-
-### 🚀 Features
-
-- Www <-> non-www redirection for apps
-- Www <-> non-www redirection
-
-### 🐛 Bug Fixes
-
-- Package.json
-- Build secrets should be visible in runtime
-- New secret should have default values
-
-## [2.0.5] - 2022-02-11
-
-### 🚀 Features
-
-- VaultWarden service
-
-### 🐛 Bug Fixes
-
-- PreventDefault on a button, thats all
-- Haproxy check should not throw error
-- Delete all build files
-- Cleanup images
-- More error handling in proxy configuration + cleanups
-- Local static assets
-- Check sentry
-- Typo
-
-### ⚙️ Miscellaneous Tasks
-
-- Version
-- Version
-
-## [2.0.4] - 2022-02-11
-
-### 🚀 Features
-
-- Use tags in update
-- New update process (#115)
-
-### 🐛 Bug Fixes
-
-- Docker Engine bug related to live-restore and IPs
-- Version
-
-## [2.0.3] - 2022-02-10
-
-### 🐛 Bug Fixes
-
-- Capture non-error as error
-- Only delete id.rsa in case of it exists
-- Status is not available yet
-
-### ⚙️ Miscellaneous Tasks
-
-- Version bump
-
-## [2.0.2] - 2022-02-10
-
-### 🐛 Bug Fixes
-
-- Secrets join
-- ENV variables set differently
-
-
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
deleted file mode 100644
index 246e0dae54..0000000000
--- a/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,94 +0,0 @@
-# Citizen Code of Conduct
-
-## 1. Purpose
-
-A primary goal of Coolify is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof).
-
-This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior.
-
-We invite all those who participate in Coolify to help us create safe and positive experiences for everyone.
-
-## 2. Open [Source/Culture/Tech] Citizenship
-
-A supplemental goal of this Code of Conduct is to increase open [source/culture/tech] citizenship by encouraging participants to recognize and strengthen the relationships between our actions and their effects on our community.
-
-Communities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society.
-
-If you see someone who is making an extra effort to ensure our community is welcoming, friendly, and encourages all participants to contribute to the fullest extent, we want to know.
-
-## 3. Expected Behavior
-
-The following behaviors are expected and requested of all community members:
-
- * Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community.
- * Exercise consideration and respect in your speech and actions.
- * Attempt collaboration before conflict.
- * Refrain from demeaning, discriminatory, or harassing behavior and speech.
- * Be mindful of your surroundings and of your fellow participants. Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential.
- * Remember that community event venues may be shared with members of the public; please be respectful to all patrons of these locations.
-
-## 4. Unacceptable Behavior
-
-The following behaviors are considered harassment and are unacceptable within our community:
-
- * Violence, threats of violence or violent language directed against another person.
- * Sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory jokes and language.
- * Posting or displaying sexually explicit or violent material.
- * Posting or threatening to post other people's personally identifying information ("doxing").
- * Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability.
- * Inappropriate photography or recording.
- * Inappropriate physical contact. You should have someone's consent before touching them.
- * Unwelcome sexual attention. This includes, sexualized comments or jokes; inappropriate touching, groping, and unwelcomed sexual advances.
- * Deliberate intimidation, stalking or following (online or in person).
- * Advocating for, or encouraging, any of the above behavior.
- * Sustained disruption of community events, including talks and presentations.
-
-## 5. Weapons Policy
-
-No weapons will be allowed at Coolify events, community spaces, or in other spaces covered by the scope of this Code of Conduct. Weapons include but are not limited to guns, explosives (including fireworks), and large knives such as those used for hunting or display, as well as any other item used for the purpose of causing injury or harm to others. Anyone seen in possession of one of these items will be asked to leave immediately, and will only be allowed to return without the weapon. Community members are further expected to comply with all state and local laws on this matter.
-
-## 6. Consequences of Unacceptable Behavior
-
-Unacceptable behavior from any community member, including sponsors and those with decision-making authority, will not be tolerated.
-
-Anyone asked to stop unacceptable behavior is expected to comply immediately.
-
-If a community member engages in unacceptable behavior, the community organizers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning (and without refund in the case of a paid event).
-
-## 7. Reporting Guidelines
-
-If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible. hi@coollabs.io.
-
-
-
-Additionally, community organizers are available to help community members engage with local law enforcement or to otherwise help those experiencing unacceptable behavior feel safe. In the context of in-person events, organizers will also provide escorts as desired by the person experiencing distress.
-
-## 8. Addressing Grievances
-
-If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify coollabsio with a concise description of your grievance. Your grievance will be handled in accordance with our existing governing policies.
-
-
-
-## 9. Scope
-
-We expect all community participants (contributors, paid or otherwise; sponsors; and other guests) to abide by this Code of Conduct in all community venues--online and in-person--as well as in all one-on-one communications pertaining to community business.
-
-This code of conduct and its related procedures also applies to unacceptable behavior occurring outside the scope of community activities when such behavior has the potential to adversely affect the safety and well-being of community members.
-
-## 10. Contact info
-
-hi@coollabs.io
-
-## 11. License and attribution
-
-The Citizen Code of Conduct is distributed by [Stumptown Syndicate](http://stumptownsyndicate.org) under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/).
-
-Portions of text derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/) and the [Geek Feminism Anti-Harassment Policy](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy).
-
-_Revision 2.3. Posted 6 March 2017._
-
-_Revision 2.2. Posted 4 February 2016._
-
-_Revision 2.1. Posted 23 June 2014._
-
-_Revision 2.0, adopted by the [Stumptown Syndicate](http://stumptownsyndicate.org) board on 10 January 2013. Posted 17 March 2013._
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index dba3676cfb..0000000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,245 +0,0 @@
-# Contributing to Coolify
-
-> "First, thanks for considering contributing to my project. It really means a lot!" - [@andrasbacsai](https://github.com/andrasbacsai)
-
-You can ask for guidance anytime on our [Discord server](https://coollabs.io/discord) in the `#contribute` channel.
-
-To understand the tech stack, please refer to the [Tech Stack](TECH_STACK.md) document.
-
-## Table of Contents
-
-1. [Setup Development Environment](#1-setup-development-environment)
-2. [Verify Installation](#2-verify-installation-optional)
-3. [Fork and Setup Local Repository](#3-fork-and-setup-local-repository)
-4. [Set up Environment Variables](#4-set-up-environment-variables)
-5. [Start Coolify](#5-start-coolify)
-6. [Start Development](#6-start-development)
-7. [Create a Pull Request](#7-create-a-pull-request)
-8. [Development Notes](#development-notes)
-9. [Resetting Development Environment](#resetting-development-environment)
-10. [Additional Contribution Guidelines](#additional-contribution-guidelines)
-
-## 1. Setup Development Environment
-
-Follow the steps below for your operating system:
-
-
-Windows
-
-1. Install `docker-ce`, Docker Desktop (or similar):
- - Docker CE (recommended):
- - Install Windows Subsystem for Linux v2 (WSL2) by following this guide: [Install WSL](https://learn.microsoft.com/en-us/windows/wsl/install?ref=coolify)
- - After installing WSL2, install Docker CE for your Linux distribution by following this guide: [Install Docker Engine](https://docs.docker.com/engine/install/?ref=coolify)
- - Make sure to choose the appropriate Linux distribution (e.g., Ubuntu) when following the Docker installation guide
- - Install Docker Desktop (easier):
- - Download and install [Docker Desktop for Windows](https://docs.docker.com/desktop/install/windows-install/?ref=coolify)
- - Ensure WSL2 backend is enabled in Docker Desktop settings
-
-2. Install Spin:
- - Follow the instructions to install Spin on Windows from the [Spin documentation](https://serversideup.net/open-source/spin/docs/installation/install-windows#download-and-install-spin-into-wsl2?ref=coolify)
-
-
-
-
-MacOS
-
-1. Install Orbstack, Docker Desktop (or similar):
- - Orbstack (recommended, as it is a faster and lighter alternative to Docker Desktop):
- - Download and install [Orbstack](https://docs.orbstack.dev/quick-start#installation?ref=coolify)
- - Docker Desktop:
- - Download and install [Docker Desktop for Mac](https://docs.docker.com/desktop/install/mac-install/?ref=coolify)
-
-2. Install Spin:
- - Follow the instructions to install Spin on MacOS from the [Spin documentation](https://serversideup.net/open-source/spin/docs/installation/install-macos/#download-and-install-spin?ref=coolify)
-
-
-
-
-Linux
-
-1. Install Docker Engine, Docker Desktop (or similar):
- - Docker Engine (recommended, as there is no VM overhead):
- - Follow the official [Docker Engine installation guide](https://docs.docker.com/engine/install/?ref=coolify) for your Linux distribution
- - Docker Desktop:
- - If you want a GUI, you can use [Docker Desktop for Linux](https://docs.docker.com/desktop/install/linux-install/?ref=coolify)
-
-2. Install Spin:
- - Follow the instructions to install Spin on Linux from the [Spin documentation](https://serversideup.net/open-source/spin/docs/installation/install-linux#configure-docker-permissions?ref=coolify)
-
-
-
-## 2. Verify Installation (Optional)
-
-After installing Docker (or Orbstack) and Spin, verify the installation:
-
-1. Open a terminal or command prompt
-2. Run the following commands:
- ```bash
- docker --version
- spin --version
- ```
- You should see version information for both Docker and Spin.
-
-## 3. Fork and Setup Local Repository
-
-1. Fork the [Coolify](https://github.com/coollabsio/coolify) repository to your GitHub account.
-
-2. Install a code editor on your machine (choose one):
-
- | Editor | Platform | Download Link |
- |--------|----------|---------------|
- | Visual Studio Code (recommended free) | Windows/macOS/Linux | [Download](https://code.visualstudio.com/download?ref=coolify) |
- | Cursor (recommended but paid) | Windows/macOS/Linux | [Download](https://www.cursor.com/?ref=coolify) |
- | Zed (very fast) | macOS/Linux | [Download](https://zed.dev/download?ref=coolify) |
-
-3. Clone the Coolify Repository from your fork to your local machine
- - Use `git clone` in the command line, or
- - Use GitHub Desktop (recommended):
- - Download and install from [https://desktop.github.com/](https://desktop.github.com/?ref=coolify)
- - Open GitHub Desktop and login with your GitHub account
- - Click on `File` -> `Clone Repository` select `github.com` as the repository location, then select your forked Coolify repository, choose the local path and then click `Clone`
-
-4. Open the cloned Coolify Repository in your chosen code editor.
-
-## 4. Set up Environment Variables
-
-1. In the Code Editor, locate the `.env.development.example` file in the root directory of your local Coolify repository.
-2. Duplicate the `.env.development.example` file and rename the copy to `.env`.
-3. Open the new `.env` file and review its contents. Adjust any environment variables as needed for your development setup.
-4. If you encounter errors during database migrations, update the database connection settings in your `.env` file. Use the IP address or hostname of your PostgreSQL database container. You can find this information by running `docker ps` after executing `spin up`.
-5. Save the changes to your `.env` file.
-
-## 5. Start Coolify
-
-1. Open a terminal in the local Coolify directory.
-2. Run the following command in the terminal (leave that terminal open):
- ```bash
- spin up
- ```
-
-> [!NOTE]
-> You may see some errors, but don't worry; this is expected.
-
-3. If you encounter permission errors, especially on macOS, use:
- ```bash
- sudo spin up
- ```
-
-> [!NOTE]
-> If you change environment variables afterwards or anything seems broken, press Ctrl + C to stop the process and run `spin up` again.
-
-## 6. Start Development
-
-1. Access your Coolify instance:
- - URL: `http://localhost:8000`
- - Login: `test@example.com`
- - Password: `password`
-
-2. Additional development tools:
- | Tool | URL | Note |
- |------|-----|------|
- | Laravel Horizon (scheduler) | `http://localhost:8000/horizon` | Only accessible when logged in as root user |
- | Mailpit (email catcher) | `http://localhost:8025` | |
- | Telescope (debugging tool) | `http://localhost:8000/telescope` | Disabled by default |
-
-> [!NOTE]
-> To enable Telescope, add the following to your `.env` file:
-> ```env
-> TELESCOPE_ENABLED=true
-> ```
-
-## 7. Create a Pull Request
-
-1. After making changes or adding a new service:
- - Commit your changes to your forked repository.
- - Push the changes to your GitHub account.
-
-2. Creating the Pull Request (PR):
- - Navigate to the main Coolify repository on GitHub.
- - Click the "Pull requests" tab.
- - Click the green "New pull request" button.
- - Choose your fork and branch as the compare branch.
- - Click "Create pull request".
-
-3. Filling out the PR details:
- - Give your PR a descriptive title.
- - Use the Pull Request Template provided and fill in the details.
-
-> [!IMPORTANT]
-> Always set the base branch for your PR to the `next` branch of the Coolify repository, not the `main` branch.
-
-4. Submit your PR:
- - Review your changes one last time.
- - Click "Create pull request" to submit.
-
-> [!NOTE]
-> Make sure your PR is out of draft mode as soon as it's ready for review. PRs that are in draft mode for a long time may be closed by maintainers.
-
-After submission, maintainers will review your PR and may request changes or provide feedback.
-
-## Development Notes
-
-When working on Coolify, keep the following in mind:
-
-1. **Database Migrations**: After switching branches or making changes to the database structure, always run migrations:
- ```bash
- docker exec -it coolify php artisan migrate
- ```
-
-2. **Resetting Development Setup**: To reset your development setup to a clean database with default values:
- ```bash
- docker exec -it coolify php artisan migrate:fresh --seed
- ```
-
-3. **Troubleshooting**: If you encounter unexpected behavior, ensure your database is up-to-date with the latest migrations and if possible reset the development setup to eliminate any environment-specific issues.
-
-> [!IMPORTANT]
-> Forgetting to migrate the database can cause problems, so make it a habit to run migrations after pulling changes or switching branches.
-
-## Resetting Development Environment
-
-If you encounter issues or break your database or something else, follow these steps to start from a clean slate (works since `v4.0.0-beta.342`):
-
-1. Stop all running containers `ctrl + c`.
-
-2. Remove all Coolify containers:
- ```bash
- docker rm coolify coolify-db coolify-redis coolify-realtime coolify-testing-host coolify-minio coolify-vite-1 coolify-mail
- ```
-
-3. Remove Coolify volumes (it is possible that the volumes have no `coolify` prefix on your machine, in that case remove the prefix from the command):
- ```bash
- docker volume rm coolify_dev_backups_data coolify_dev_postgres_data coolify_dev_redis_data coolify_dev_coolify_data coolify_dev_minio_data
- ```
-
-4. Remove unused images:
- ```bash
- docker image prune -a
- ```
-
-5. Start Coolify again:
- ```bash
- spin up
- ```
-
-6. Run database migrations and seeders:
- ```bash
- docker exec -it coolify php artisan migrate:fresh --seed
- ```
-
-After completing these steps, you'll have a fresh development setup.
-
-> [!IMPORTANT]
-> Always run database migrations and seeders after switching branches or pulling updates to ensure your local database structure matches the current codebase and includes necessary seed data.
-
-## Additional Contribution Guidelines
-
-### Contributing a New Service
-
-To add a new service to Coolify, please refer to our documentation:
-[Adding a New Service](https://coolify.io/docs/knowledge-base/contribute/service)
-
-### Contributing to Documentation
-
-To contribute to the Coolify documentation, please refer to this guide:
-[Contributing to the Coolify Documentation](https://github.com/coollabsio/documentation-coolify/blob/main/CONTRIBUTING.md)
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 86c87eba2d..0000000000
--- a/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [2022] [Andras Bacsai]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
\ No newline at end of file
diff --git a/README.md b/README.md
index 8670e9c76c..4fafb32cea 100644
--- a/README.md
+++ b/README.md
@@ -1,169 +1,3 @@
-
+## v5.x
-[](https://console.algora.io/org/coollabsio/bounties/new)
-
-# About the Project
-
-Coolify is an open-source & self-hostable alternative to Heroku / Netlify / Vercel / etc.
-
-It helps you manage your servers, applications, and databases on your own hardware; you only need an SSH connection. You can manage VPS, Bare Metal, Raspberry PIs, and anything else.
-
-Imagine having the ease of a cloud but with your own servers. That is **Coolify**.
-
-No vendor lock-in, which means that all the configurations for your applications/databases/etc are saved to your server. So, if you decide to stop using Coolify (oh nooo), you could still manage your running resources. You lose the automations and all the magic. 🪄️
-
-For more information, take a look at our landing page at [coolify.io](https://coolify.io).
-
-# Installation
-
-```bash
-curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
-```
-You can find the installation script source [here](./scripts/install.sh).
-
-> [!NOTE]
-> Please refer to the [docs](https://coolify.io/docs/installation) for more information about the installation.
-
-# Support
-
-Contact us at [coolify.io/docs/contact](https://coolify.io/docs/contact).
-
-# Donations
-To stay completely free and open-source, with no feature behind the paywall and evolve the project, we need your help. If you like Coolify, please consider donating to help us fund the project's future development.
-
-[coolify.io/sponsorships](https://coolify.io/sponsorships)
-
-Thank you so much!
-
-Special thanks to our biggest sponsors!
-
-### Special Sponsors
-
-
-
-
-* [CCCareers](https://cccareers.org/) - A career development platform connecting coding bootcamp graduates with job opportunities in the tech industry.
-* [Hetzner](http://htznr.li/CoolifyXHetzner) - A German web hosting company offering affordable dedicated servers, cloud services, and web hosting solutions.
-* [Logto](https://logto.io/?ref=coolify) - An open-source authentication and authorization solution for building secure login systems and managing user identities.
-* [Tolgee](https://tolgee.io/?ref=coolify) - Developer & translator friendly web-based localization platform.
-* [BC Direct](https://bc.direct/?ref=coolify.io) - A digital marketing agency specializing in e-commerce solutions and online business growth strategies.
-* [QuantCDN](https://www.quantcdn.io/?ref=coolify.io) - A content delivery network (CDN) optimizing website performance through global content distribution.
-* [Arcjet](https://arcjet.com/?ref=coolify.io) - A cloud-based platform providing real-time protection against API abuse and bot attacks.
-* [SupaGuide](https://supa.guide/?ref=coolify.io) - A comprehensive resource hub offering guides and tutorials for web development using Supabase.
-* [GoldenVM](https://billing.goldenvm.com/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes.
-* [Tigris](https://tigrisdata.com/?ref=coolify.io) - A fully managed serverless object storage service compatible with Amazon S3 API. Offers high performance, scalability, and built-in search capabilities for efficient data management.
-* [Convex](https://convex.link/coolify.io) - Convex is the open-source reactive database for web app developers.
-* [Cloudify.ro](https://cloudify.ro/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes.
-* [Syntaxfm](https://syntax.fm/?ref=coolify.io) - Podcast for web developers.
-* [PFGlabs](https://pfglabs.com/?ref=coolify.io) - Build real project with Golang.
-* [Treive](https://trieve.ai/?ref=coolify.io) - An AI-powered search and discovery platform for enhancing information retrieval in large datasets.
-* [Blacksmith](https://blacksmith.sh/?ref=coolify.io) - A cloud-native platform for automating infrastructure provisioning and management across multiple cloud providers.
-* [Brand Dev](https://brand.dev/?ref=coolify.io) - The #1 Brand API for B2B software startups - instantly pull logos, fonts, descriptions, social links, slogans, and so much more from any domain via a single api call.
-* [Jobscollider](https://jobscollider.com/remote-jobs?ref=coolify.io) - A job search platform connecting professionals with remote work opportunities across various industries.
-* [Hostinger](https://www.hostinger.com/vps/coolify-hosting?ref=coolify.io) - A web hosting provider offering affordable hosting solutions, domain registration, and website building tools.
-* [Glueops](https://www.glueops.dev/?ref=coolify.io) - A DevOps consulting company providing infrastructure automation and cloud optimization services.
-* [Ubicloud](https://ubicloud.com/?ref=coolify.io) - An open-source alternative to hyperscale cloud providers, offering high-performance cloud computing services.
-* [Juxtdigital](https://juxtdigital.dev/?ref=coolify.io) - A digital agency offering web development, design, and digital marketing services for businesses.
-* [Saasykit](https://saasykit.com/?ref=coolify.io) - A Laravel-based boilerplate providing essential components and features for building SaaS applications quickly.
-* [Massivegrid](https://massivegrid.com/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes.
-* [LiquidWeb](https://liquidweb.com/?utm_source=coolify.io) - A Fast web hosting provider.
-
-
-## Github Sponsors ($40+)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-## Organizations
-
-
-
-
-
-
-
-
-
-
-
-
-## Individuals
-
-
-
-# Cloud
-
-If you do not want to self-host Coolify, there is a paid cloud version available: [app.coolify.io](https://app.coolify.io)
-
-For more information & pricing, take a look at our landing page [coolify.io](https://coolify.io).
-
-## Why should I use the Cloud version?
-The recommended way to use Coolify is to have one server for Coolify and one (or more) for the resources you are deploying. A server is around 4-5$/month.
-
-By subscribing to the cloud version, you get the Coolify server for the same price, but with:
-- High-availability
-- Free email notifications
-- Better support
-- Less maintenance for you
-
-# Recognitions
-
-
-
-
-
-
-
-
-
-
-
-# Core Maintainers
-
-| Andras Bacsai | 🏔️ Peak |
-|------------|------------|
-| | |
-| | |
-
-# Repo Activity
-
-
-
-# Star History
-
-[](https://star-history.com/#coollabsio/coolify&Date)
+- WIP
\ No newline at end of file
diff --git a/RELEASE.md b/RELEASE.md
deleted file mode 100644
index bc159b0409..0000000000
--- a/RELEASE.md
+++ /dev/null
@@ -1,133 +0,0 @@
-# Coolify Release Guide
-
-This guide outlines the release process for Coolify, intended for developers and those interested in understanding how Coolify releases are managed and deployed.
-
-## Table of Contents
-- [Release Process](#release-process)
-- [Version Types](#version-types)
- - [Stable](#stable)
- - [Nightly](#nightly)
- - [Beta](#beta)
-- [Version Availability](#version-availability)
- - [Self-Hosted](#self-hosted)
- - [Cloud](#cloud)
-- [Manually Update to Specific Versions](#manually-update-to-specific-versions)
-
-## Release Process
-
-1. **Development on `next` or Feature Branches**
- - Improvements, fixes, and new features are developed on the `next` branch or separate feature branches.
-
-2. **Merging to `main`**
- - Once ready, changes are merged from the `next` branch into the `main` branch (via a pull request).
-
-3. **Building the Release**
- - After merging to `main`, GitHub Actions automatically builds release images for all architectures and pushes them to the GitHub Container Registry and Docker Hub with the specific version tag and the `latest` tag.
-
-4. **Creating a GitHub Release**
- - A new GitHub release is manually created with details of the changes made in the version.
-
-5. **Updating the CDN**
- - To make a new version publicly available, the version information on the CDN needs to be updated manually. After that the new version number will be available at [https://cdn.coollabs.io/coolify/versions.json](https://cdn.coollabs.io/coolify/versions.json).
-
-> [!NOTE]
-> The CDN update may not occur immediately after the GitHub release. It can take hours or even days due to additional testing, stability checks, or potential hotfixes. **The update becomes available only after the CDN is updated. After the CDN is updated, a discord announcement will be made in the Production Release channel.**
-
-## Version Types
-
-
- Stable (coming soon)
-
-- **Stable**
- - The production version suitable for stable, production environments (recommended).
- - **Update Frequency:** Every 2 to 4 weeks, with more frequent possible fixes.
- - **Release Size:** Larger but less frequent releases. Multiple nightly versions are consolidated into a single stable release.
- - **Versioning Scheme:** Follows semantic versioning (e.g., `v4.0.0`, `4.1.0`, etc.).
- - **Installation Command:**
- ```bash
- curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
- ```
-
-
-
-
- Nightly
-
-- **Nightly**
- - The latest development version, suitable for testing the latest changes and experimenting with new features.
- - **Update Frequency:** Daily or bi-weekly updates.
- - **Release Size:** Smaller, more frequent releases.
- - **Versioning Scheme:** Follows semantic versioning (e.g., `4.1.0-nightly.1`, `4.1.0-nightly.2`, etc.).
- - **Installation Command:**
- ```bash
- curl -fsSL https://cdn.coollabs.io/coolify-nightly/install.sh | bash -s next
- ```
-
-
-
-
- Beta
-
-- **Beta**
- - Test releases for the upcoming stable version.
- - **Purpose:** Allows users to test and provide feedback on new features and changes before they become stable.
- - **Update Frequency:** Available if we think beta testing is necessary.
- - **Release Size:** Same size as stable release as it will become the next stabe release after some time.
- - **Versioning Scheme:** Follows semantic versioning (e.g., `4.1.0-beta.1`, `4.1.0-beta.2`, etc.).
- - **Installation Command:**
- ```bash
- curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
- ```
-
-
-
-> [!WARNING]
-> Do not use nightly/beta builds in production as there is no guarantee of stability.
-
-## Version Availability
-
-When a new version is released and a new GitHub release is created, it doesn't immediately become available for your instance. Here's how version availability works for different instance types.
-
-### Self-Hosted
-
-- **Update Frequency:** More frequent updates, especially on the nightly release channel.
-- **Update Availability:** New versions are available once the CDN has been updated.
-- **Update Methods:**
- 1. **Manual Update in Instance Settings:**
- - Go to `Settings > Update Check Frequency` and click the `Check Manually` button.
- - If an update is available, an upgrade button will appear on the sidebar.
- 2. **Automatic Update:**
- - If enabled, the instance will update automatically at the time set in the settings.
- 3. **Re-run Installation Script:**
- - Run the installation script again to upgrade to the latest version available on the CDN:
- ```bash
- curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
- ```
-
-> [!IMPORTANT]
-> If a new release is available on GitHub but your instance hasn't updated yet or no upgrade button is shown in the UI, the CDN might not have been updated yet. This intentional delay ensures stability and allows for hotfixes before official release.
-
-### Cloud
-
-- **Update Frequency:** Less frequent as it's a managed service.
-- **Update Availability:** New versions are available once Andras has updated the cloud version manually.
-- **Update Method:**
- - Updates are managed by Andras, who ensures each cloud version is thoroughly tested and stable before releasing it.
-
-> [!IMPORTANT]
-> The cloud version of Coolify may be several versions behind the latest GitHub releases even if the CDN is updated. This is intentional to ensure stability and reliability for cloud users and Andras will manully update the cloud version when the update is ready.
-
-## Manually Update/ Downgrade to Specific Versions
-
-> [!CAUTION]
-> Updating to unreleased versions is not recommended and can cause issues.
-
-> [!IMPORTANT]
-> Downgrading is supported but not recommended and can cause issues because of database migrations and other changes.
-
-To update your Coolify instance to a specific version, use the following command:
-
-```bash
-curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash -s
-```
-Replace `` with the version you want to update to (for example `4.0.0-beta.332`).
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index 0711bf5b5e..0000000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Security Policy
-
-## Supported Versions
-
-Currently supported, maintained and updated versions:
-
-| Version | Supported | Support Status |
-| ------- | ------------------ | -------------- |
-| 4.x | :white_check_mark: | Active Development & Security Updates |
-| < 4.0 | :x: | End of Life (no security updates) |
-
-## Security Updates
-
-We take security seriously. Security updates are released as soon as possible after a vulnerability is discovered and verified.
-
-## Reporting a Vulnerability
-
-If you discover a security vulnerability, please follow these steps:
-
-1. **DO NOT** disclose the vulnerability publicly.
-2. Send a detailed report to: `hi@coollabs.io`.
-3. Include in your report:
- - A description of the vulnerability
- - Steps to reproduce the issue
- - Potential impact
diff --git a/TECH_STACK.md b/TECH_STACK.md
deleted file mode 100644
index 6a779eb293..0000000000
--- a/TECH_STACK.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# Coolify Technology Stack
-
-## Frontend
-
-- Livewire and Alpine.js
-- Blade (PHP templating engine)
-- Tailwind CSS
-- Monaco Editor (Code editor component)
-- XTerm.js (Terminal component)
-
-## Backend
-
-- Laravel 11 (PHP Framework)
-- PostgreSQL 15 (Database)
-- Redis 7 (Caching & Real-time features)
-- Soketi (WebSocket Server)
-
-## DevOps & Infrastructure
-
-- Docker & Docker Compose
-- Nginx (Web Server)
-- S6 Overlay (Process Supervisor)
-- GitHub Actions (CI/CD)
-
-## Languages
-
-- PHP 8.4
-- JavaScript
-- Shell/Bash scripts
diff --git a/app/Actions/Application/GenerateConfig.php b/app/Actions/Application/GenerateConfig.php
deleted file mode 100644
index 991146b482..0000000000
--- a/app/Actions/Application/GenerateConfig.php
+++ /dev/null
@@ -1,16 +0,0 @@
-generateConfig(is_json: $is_json);
- }
-}
diff --git a/app/Actions/Application/IsHorizonQueueEmpty.php b/app/Actions/Application/IsHorizonQueueEmpty.php
deleted file mode 100644
index 17966b8a0d..0000000000
--- a/app/Actions/Application/IsHorizonQueueEmpty.php
+++ /dev/null
@@ -1,37 +0,0 @@
-getRecent();
- if ($recent) {
- $running = $recent->filter(function ($job) use ($hostname) {
- $payload = json_decode($job->payload);
- $tags = data_get($payload, 'tags');
-
- return $job->status != 'completed' &&
- $job->status != 'failed' &&
- isset($tags) &&
- is_array($tags) &&
- in_array('server:'.$hostname, $tags);
- });
- if ($running->count() > 0) {
- echo 'false';
-
- return false;
- }
- }
- echo 'true';
-
- return true;
- }
-}
diff --git a/app/Actions/Application/LoadComposeFile.php b/app/Actions/Application/LoadComposeFile.php
deleted file mode 100644
index 838b541e2f..0000000000
--- a/app/Actions/Application/LoadComposeFile.php
+++ /dev/null
@@ -1,16 +0,0 @@
-loadComposeFile();
- }
-}
diff --git a/app/Actions/Application/StopApplication.php b/app/Actions/Application/StopApplication.php
deleted file mode 100644
index 642b4ba456..0000000000
--- a/app/Actions/Application/StopApplication.php
+++ /dev/null
@@ -1,43 +0,0 @@
-destination->server;
- if (! $server->isFunctional()) {
- return 'Server is not functional';
- }
-
- if ($server->isSwarm()) {
- instant_remote_process(["docker stack rm {$application->uuid}"], $server);
-
- return;
- }
-
- $containersToStop = $application->getContainersToStop($previewDeployments);
- $application->stopContainers($containersToStop, $server);
-
- if ($application->build_pack === 'dockercompose') {
- $application->delete_connected_networks($application->uuid);
- }
-
- if ($dockerCleanup) {
- CleanupDocker::dispatch($server, true);
- }
- } catch (\Exception $e) {
- return $e->getMessage();
- }
- }
-}
diff --git a/app/Actions/Application/StopApplicationOneServer.php b/app/Actions/Application/StopApplicationOneServer.php
deleted file mode 100644
index b13b10efd6..0000000000
--- a/app/Actions/Application/StopApplicationOneServer.php
+++ /dev/null
@@ -1,38 +0,0 @@
-destination->server->isSwarm()) {
- return;
- }
- if (! $server->isFunctional()) {
- return 'Server is not functional';
- }
- try {
- $containers = getCurrentApplicationContainerStatus($server, $application->id, 0);
- if ($containers->count() > 0) {
- foreach ($containers as $container) {
- $containerName = data_get($container, 'Names');
- if ($containerName) {
- instant_remote_process(
- ["docker rm -f {$containerName}"],
- $server
- );
- }
- }
- }
- } catch (\Exception $e) {
- return $e->getMessage();
- }
- }
-}
diff --git a/app/Actions/CoolifyTask/PrepareCoolifyTask.php b/app/Actions/CoolifyTask/PrepareCoolifyTask.php
deleted file mode 100644
index 3f76a2e3c7..0000000000
--- a/app/Actions/CoolifyTask/PrepareCoolifyTask.php
+++ /dev/null
@@ -1,54 +0,0 @@
-remoteProcessArgs = $remoteProcessArgs;
-
- if ($remoteProcessArgs->model) {
- $properties = $remoteProcessArgs->toArray();
- unset($properties['model']);
-
- $this->activity = activity()
- ->withProperties($properties)
- ->performedOn($remoteProcessArgs->model)
- ->event($remoteProcessArgs->type)
- ->log('[]');
- } else {
- $this->activity = activity()
- ->withProperties($remoteProcessArgs->toArray())
- ->event($remoteProcessArgs->type)
- ->log('[]');
- }
- }
-
- public function __invoke(): Activity
- {
- $job = new CoolifyTask(
- activity: $this->activity,
- ignore_errors: $this->remoteProcessArgs->ignore_errors,
- call_event_on_finish: $this->remoteProcessArgs->call_event_on_finish,
- call_event_data: $this->remoteProcessArgs->call_event_data,
- );
- dispatch($job);
- $this->activity->refresh();
-
- return $this->activity;
- }
-}
diff --git a/app/Actions/CoolifyTask/RunRemoteProcess.php b/app/Actions/CoolifyTask/RunRemoteProcess.php
deleted file mode 100644
index 926d30fe6c..0000000000
--- a/app/Actions/CoolifyTask/RunRemoteProcess.php
+++ /dev/null
@@ -1,198 +0,0 @@
-getExtraProperty('type') !== ActivityTypes::INLINE->value && $activity->getExtraProperty('type') !== ActivityTypes::COMMAND->value) {
- throw new \RuntimeException('Incompatible Activity to run a remote command.');
- }
-
- $this->activity = $activity;
- $this->hide_from_output = $hide_from_output;
- $this->ignore_errors = $ignore_errors;
- $this->call_event_on_finish = $call_event_on_finish;
- $this->call_event_data = $call_event_data;
- }
-
- public static function decodeOutput(?Activity $activity = null): string
- {
- if (is_null($activity)) {
- return '';
- }
-
- try {
- $decoded = json_decode(
- data_get($activity, 'description'),
- associative: true,
- flags: JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE
- );
- } catch (\JsonException $exception) {
- return '';
- }
-
- return collect($decoded)
- ->sortBy(fn ($i) => $i['order'])
- ->map(fn ($i) => $i['output'])
- ->implode('');
- }
-
- public function __invoke(): ProcessResult
- {
- $this->time_start = hrtime(true);
-
- $status = ProcessStatus::IN_PROGRESS;
- $timeout = config('constants.ssh.command_timeout');
- $process = Process::timeout($timeout)->start($this->getCommand(), $this->handleOutput(...));
- $this->activity->properties = $this->activity->properties->merge([
- 'process_id' => $process->id(),
- ]);
-
- $processResult = $process->wait();
- // $processResult = Process::timeout($timeout)->run($this->getCommand(), $this->handleOutput(...));
- if ($this->activity->properties->get('status') === ProcessStatus::ERROR->value) {
- $status = ProcessStatus::ERROR;
- } else {
- if ($processResult->exitCode() == 0) {
- $status = ProcessStatus::FINISHED;
- } else {
- $status = ProcessStatus::ERROR;
- }
- }
-
- $this->activity->properties = $this->activity->properties->merge([
- 'exitCode' => $processResult->exitCode(),
- 'stdout' => $processResult->output(),
- 'stderr' => $processResult->errorOutput(),
- 'status' => $status->value,
- ]);
- $this->activity->save();
- if ($this->call_event_on_finish) {
- try {
- if ($this->call_event_data) {
- event(resolve("App\\Events\\$this->call_event_on_finish", [
- 'data' => $this->call_event_data,
- ]));
- } else {
- event(resolve("App\\Events\\$this->call_event_on_finish", [
- 'userId' => $this->activity->causer_id,
- ]));
- }
- } catch (\Throwable $e) {
- Log::error('Error calling event: '.$e->getMessage());
- }
- }
- if ($processResult->exitCode() != 0 && ! $this->ignore_errors) {
- throw new \RuntimeException($processResult->errorOutput(), $processResult->exitCode());
- }
-
- return $processResult;
- }
-
- protected function getCommand(): string
- {
- $server_uuid = $this->activity->getExtraProperty('server_uuid');
- $command = $this->activity->getExtraProperty('command');
- $server = Server::whereUuid($server_uuid)->firstOrFail();
-
- return SshMultiplexingHelper::generateSshCommand($server, $command);
- }
-
- protected function handleOutput(string $type, string $output)
- {
- if ($this->hide_from_output) {
- return;
- }
- $this->current_time = $this->elapsedTime();
- $this->activity->description = $this->encodeOutput($type, $output);
- if ($this->isAfterLastThrottle()) {
- // Let's write to database.
- DB::transaction(function () {
- $this->activity->save();
- $this->last_write_at = $this->current_time;
- });
- }
- }
-
- protected function elapsedTime(): int
- {
- $timeMs = (hrtime(true) - $this->time_start) / 1_000_000;
-
- return intval($timeMs);
- }
-
- public function encodeOutput($type, $output)
- {
- $outputStack = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
- $outputStack[] = [
- 'type' => $type,
- 'output' => $output,
- 'timestamp' => hrtime(true),
- 'batch' => ApplicationDeploymentJob::$batch_counter,
- 'order' => $this->getLatestCounter(),
- ];
-
- return json_encode($outputStack, flags: JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
- }
-
- protected function getLatestCounter(): int
- {
- $description = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
- if ($description === null || count($description) === 0) {
- return 1;
- }
-
- return end($description)['order'] + 1;
- }
-
- /**
- * Determines if it's time to write again to database.
- *
- * @return bool
- */
- protected function isAfterLastThrottle()
- {
- // If DB was never written, then we immediately decide we have to write.
- if ($this->last_write_at === 0) {
- return true;
- }
-
- return ($this->current_time - $this->throttle_interval_ms) > $this->last_write_at;
- }
-}
diff --git a/app/Actions/Database/RestartDatabase.php b/app/Actions/Database/RestartDatabase.php
deleted file mode 100644
index 0400d924dd..0000000000
--- a/app/Actions/Database/RestartDatabase.php
+++ /dev/null
@@ -1,29 +0,0 @@
-destination->server;
- if (! $server->isFunctional()) {
- return 'Server is not functional';
- }
- StopDatabase::run($database);
-
- return StartDatabase::run($database);
- }
-}
diff --git a/app/Actions/Database/StartClickhouse.php b/app/Actions/Database/StartClickhouse.php
deleted file mode 100644
index f218fcabb0..0000000000
--- a/app/Actions/Database/StartClickhouse.php
+++ /dev/null
@@ -1,165 +0,0 @@
-database = $database;
-
- $container_name = $this->database->uuid;
- $this->configuration_dir = database_configuration_dir().'/'.$container_name;
-
- $this->commands = [
- "echo 'Starting database.'",
- "mkdir -p $this->configuration_dir",
- ];
-
- $persistent_storages = $this->generate_local_persistent_volumes();
- $persistent_file_volumes = $this->database->fileStorages()->get();
- $volume_names = $this->generate_local_persistent_volumes_only_volume_names();
- $environment_variables = $this->generate_environment_variables();
-
- $docker_compose = [
- 'services' => [
- $container_name => [
- 'image' => $this->database->image,
- 'container_name' => $container_name,
- 'environment' => $environment_variables,
- 'restart' => RESTART_MODE,
- 'networks' => [
- $this->database->destination->network,
- ],
- 'ulimits' => [
- 'nofile' => [
- 'soft' => 262144,
- 'hard' => 262144,
- ],
- ],
- 'labels' => defaultDatabaseLabels($this->database)->toArray(),
- 'healthcheck' => [
- 'test' => "clickhouse-client --password {$this->database->clickhouse_admin_password} --query 'SELECT 1'",
- 'interval' => '5s',
- 'timeout' => '5s',
- 'retries' => 10,
- 'start_period' => '5s',
- ],
- 'mem_limit' => $this->database->limits_memory,
- 'memswap_limit' => $this->database->limits_memory_swap,
- 'mem_swappiness' => $this->database->limits_memory_swappiness,
- 'mem_reservation' => $this->database->limits_memory_reservation,
- 'cpus' => (float) $this->database->limits_cpus,
- 'cpu_shares' => $this->database->limits_cpu_shares,
- ],
- ],
- 'networks' => [
- $this->database->destination->network => [
- 'external' => true,
- 'name' => $this->database->destination->network,
- 'attachable' => true,
- ],
- ],
- ];
- if (! is_null($this->database->limits_cpuset)) {
- data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
- }
- if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
- $docker_compose['services'][$container_name]['logging'] = generate_fluentd_configuration();
- }
- if (count($this->database->ports_mappings_array) > 0) {
- $docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
- }
- if (count($persistent_storages) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
- }
- if (count($persistent_file_volumes) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
- return "$item->fs_path:$item->mount_path";
- })->toArray();
- }
- if (count($volume_names) > 0) {
- $docker_compose['volumes'] = $volume_names;
- }
-
- // Add custom docker run options
- $docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
- $docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
-
- $docker_compose = Yaml::dump($docker_compose, 10);
- $docker_compose_base64 = base64_encode($docker_compose);
- $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
- $readme = generate_readme_file($this->database->name, now());
- $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
- $this->commands[] = "echo 'Pulling {$database->image} image.'";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
- $this->commands[] = "echo 'Database started.'";
-
- return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
- }
-
- private function generate_local_persistent_volumes()
- {
- $local_persistent_volumes = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
- $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
- } else {
- $volume_name = $persistentStorage->name;
- $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
- }
- }
-
- return $local_persistent_volumes;
- }
-
- private function generate_local_persistent_volumes_only_volume_names()
- {
- $local_persistent_volumes_names = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path) {
- continue;
- }
- $name = $persistentStorage->name;
- $local_persistent_volumes_names[$name] = [
- 'name' => $name,
- 'external' => false,
- ];
- }
-
- return $local_persistent_volumes_names;
- }
-
- private function generate_environment_variables()
- {
- $environment_variables = collect();
- foreach ($this->database->runtime_environment_variables as $env) {
- $environment_variables->push("$env->key=$env->real_value");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_ADMIN_USER'))->isEmpty()) {
- $environment_variables->push("CLICKHOUSE_ADMIN_USER={$this->database->clickhouse_admin_user}");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_ADMIN_PASSWORD'))->isEmpty()) {
- $environment_variables->push("CLICKHOUSE_ADMIN_PASSWORD={$this->database->clickhouse_admin_password}");
- }
-
- add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables);
-
- return $environment_variables->all();
- }
-}
diff --git a/app/Actions/Database/StartDatabase.php b/app/Actions/Database/StartDatabase.php
deleted file mode 100644
index e2fa6fc871..0000000000
--- a/app/Actions/Database/StartDatabase.php
+++ /dev/null
@@ -1,59 +0,0 @@
-destination->server;
- if (! $server->isFunctional()) {
- return 'Server is not functional';
- }
- switch ($database->getMorphClass()) {
- case \App\Models\StandalonePostgresql::class:
- $activity = StartPostgresql::run($database);
- break;
- case \App\Models\StandaloneRedis::class:
- $activity = StartRedis::run($database);
- break;
- case \App\Models\StandaloneMongodb::class:
- $activity = StartMongodb::run($database);
- break;
- case \App\Models\StandaloneMysql::class:
- $activity = StartMysql::run($database);
- break;
- case \App\Models\StandaloneMariadb::class:
- $activity = StartMariadb::run($database);
- break;
- case \App\Models\StandaloneKeydb::class:
- $activity = StartKeydb::run($database);
- break;
- case \App\Models\StandaloneDragonfly::class:
- $activity = StartDragonfly::run($database);
- break;
- case \App\Models\StandaloneClickhouse::class:
- $activity = StartClickhouse::run($database);
- break;
- }
- if ($database->is_public && $database->public_port) {
- StartDatabaseProxy::dispatch($database);
- }
-
- return $activity;
- }
-}
diff --git a/app/Actions/Database/StartDatabaseProxy.php b/app/Actions/Database/StartDatabaseProxy.php
deleted file mode 100644
index c4a40f020c..0000000000
--- a/app/Actions/Database/StartDatabaseProxy.php
+++ /dev/null
@@ -1,117 +0,0 @@
-database_type;
- $network = data_get($database, 'destination.network');
- $server = data_get($database, 'destination.server');
- $containerName = data_get($database, 'uuid');
- $proxyContainerName = "{$database->uuid}-proxy";
- if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
- $databaseType = $database->databaseType();
- $network = $database->service->uuid;
- $server = data_get($database, 'service.destination.server');
- $proxyContainerName = "{$database->service->uuid}-proxy";
- $containerName = "{$database->name}-{$database->service->uuid}";
- }
- $internalPort = match ($databaseType) {
- 'standalone-mariadb', 'standalone-mysql' => 3306,
- 'standalone-postgresql', 'standalone-supabase/postgres' => 5432,
- 'standalone-redis', 'standalone-keydb', 'standalone-dragonfly' => 6379,
- 'standalone-clickhouse' => 9000,
- 'standalone-mongodb' => 27017,
- default => throw new \Exception("Unsupported database type: $databaseType"),
- };
-
- $configuration_dir = database_proxy_dir($database->uuid);
- $nginxconf = <<public_port;
- proxy_pass $containerName:$internalPort;
- }
- }
- EOF;
- $dockerfile = <<< 'EOF'
- FROM nginx:stable-alpine
-
- COPY nginx.conf /etc/nginx/nginx.conf
- EOF;
- $docker_compose = [
- 'services' => [
- $proxyContainerName => [
- 'build' => [
- 'context' => $configuration_dir,
- 'dockerfile' => 'Dockerfile',
- ],
- 'image' => 'nginx:stable-alpine',
- 'container_name' => $proxyContainerName,
- 'restart' => RESTART_MODE,
- 'ports' => [
- "$database->public_port:$database->public_port",
- ],
- 'networks' => [
- $network,
- ],
- 'healthcheck' => [
- 'test' => [
- 'CMD-SHELL',
- 'stat /etc/nginx/nginx.conf || exit 1',
- ],
- 'interval' => '5s',
- 'timeout' => '5s',
- 'retries' => 3,
- 'start_period' => '1s',
- ],
- ],
- ],
- 'networks' => [
- $network => [
- 'external' => true,
- 'name' => $network,
- 'attachable' => true,
- ],
- ],
- ];
- $dockercompose_base64 = base64_encode(Yaml::dump($docker_compose, 4, 2));
- $nginxconf_base64 = base64_encode($nginxconf);
- $dockerfile_base64 = base64_encode($dockerfile);
- instant_remote_process(["docker rm -f $proxyContainerName"], $server, false);
- instant_remote_process([
- "mkdir -p $configuration_dir",
- "echo '{$dockerfile_base64}' | base64 -d | tee $configuration_dir/Dockerfile > /dev/null",
- "echo '{$nginxconf_base64}' | base64 -d | tee $configuration_dir/nginx.conf > /dev/null",
- "echo '{$dockercompose_base64}' | base64 -d | tee $configuration_dir/docker-compose.yaml > /dev/null",
- "docker compose --project-directory {$configuration_dir} pull",
- "docker compose --project-directory {$configuration_dir} up --build -d",
- ], $server);
- }
-}
diff --git a/app/Actions/Database/StartDragonfly.php b/app/Actions/Database/StartDragonfly.php
deleted file mode 100644
index 4f9f45b7c7..0000000000
--- a/app/Actions/Database/StartDragonfly.php
+++ /dev/null
@@ -1,156 +0,0 @@
-database = $database;
-
- $startCommand = "dragonfly --requirepass {$this->database->dragonfly_password}";
-
- $container_name = $this->database->uuid;
- $this->configuration_dir = database_configuration_dir().'/'.$container_name;
-
- $this->commands = [
- "echo 'Starting database.'",
- "mkdir -p $this->configuration_dir",
- ];
-
- $persistent_storages = $this->generate_local_persistent_volumes();
- $persistent_file_volumes = $this->database->fileStorages()->get();
- $volume_names = $this->generate_local_persistent_volumes_only_volume_names();
- $environment_variables = $this->generate_environment_variables();
-
- $docker_compose = [
- 'services' => [
- $container_name => [
- 'image' => $this->database->image,
- 'command' => $startCommand,
- 'container_name' => $container_name,
- 'environment' => $environment_variables,
- 'restart' => RESTART_MODE,
- 'networks' => [
- $this->database->destination->network,
- ],
- 'labels' => defaultDatabaseLabels($this->database)->toArray(),
- 'healthcheck' => [
- 'test' => "redis-cli -a {$this->database->dragonfly_password} ping",
- 'interval' => '5s',
- 'timeout' => '5s',
- 'retries' => 10,
- 'start_period' => '5s',
- ],
- 'mem_limit' => $this->database->limits_memory,
- 'memswap_limit' => $this->database->limits_memory_swap,
- 'mem_swappiness' => $this->database->limits_memory_swappiness,
- 'mem_reservation' => $this->database->limits_memory_reservation,
- 'cpus' => (float) $this->database->limits_cpus,
- 'cpu_shares' => $this->database->limits_cpu_shares,
- ],
- ],
- 'networks' => [
- $this->database->destination->network => [
- 'external' => true,
- 'name' => $this->database->destination->network,
- 'attachable' => true,
- ],
- ],
- ];
- if (! is_null($this->database->limits_cpuset)) {
- data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
- }
- if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
- $docker_compose['services'][$container_name]['logging'] = generate_fluentd_configuration();
- }
- if (count($this->database->ports_mappings_array) > 0) {
- $docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
- }
- if (count($persistent_storages) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
- }
- if (count($persistent_file_volumes) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
- return "$item->fs_path:$item->mount_path";
- })->toArray();
- }
- if (count($volume_names) > 0) {
- $docker_compose['volumes'] = $volume_names;
- }
-
- // Add custom docker run options
- $docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
- $docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
-
- $docker_compose = Yaml::dump($docker_compose, 10);
- $docker_compose_base64 = base64_encode($docker_compose);
- $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
- $readme = generate_readme_file($this->database->name, now());
- $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
- $this->commands[] = "echo 'Pulling {$database->image} image.'";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
- $this->commands[] = "echo 'Database started.'";
-
- return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
- }
-
- private function generate_local_persistent_volumes()
- {
- $local_persistent_volumes = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
- $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
- } else {
- $volume_name = $persistentStorage->name;
- $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
- }
- }
-
- return $local_persistent_volumes;
- }
-
- private function generate_local_persistent_volumes_only_volume_names()
- {
- $local_persistent_volumes_names = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path) {
- continue;
- }
- $name = $persistentStorage->name;
- $local_persistent_volumes_names[$name] = [
- 'name' => $name,
- 'external' => false,
- ];
- }
-
- return $local_persistent_volumes_names;
- }
-
- private function generate_environment_variables()
- {
- $environment_variables = collect();
- foreach ($this->database->runtime_environment_variables as $env) {
- $environment_variables->push("$env->key=$env->real_value");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
- $environment_variables->push("REDIS_PASSWORD={$this->database->dragonfly_password}");
- }
-
- return $environment_variables->all();
- }
-}
diff --git a/app/Actions/Database/StartKeydb.php b/app/Actions/Database/StartKeydb.php
deleted file mode 100644
index 6c733d3180..0000000000
--- a/app/Actions/Database/StartKeydb.php
+++ /dev/null
@@ -1,180 +0,0 @@
-database = $database;
-
- $startCommand = "keydb-server --requirepass {$this->database->keydb_password} --appendonly yes";
-
- $container_name = $this->database->uuid;
- $this->configuration_dir = database_configuration_dir().'/'.$container_name;
-
- $this->commands = [
- "echo 'Starting database.'",
- "mkdir -p $this->configuration_dir",
- ];
-
- $persistent_storages = $this->generate_local_persistent_volumes();
- $persistent_file_volumes = $this->database->fileStorages()->get();
- $volume_names = $this->generate_local_persistent_volumes_only_volume_names();
- $environment_variables = $this->generate_environment_variables();
- $this->add_custom_keydb();
-
- $docker_compose = [
- 'services' => [
- $container_name => [
- 'image' => $this->database->image,
- 'command' => $startCommand,
- 'container_name' => $container_name,
- 'environment' => $environment_variables,
- 'restart' => RESTART_MODE,
- 'networks' => [
- $this->database->destination->network,
- ],
- 'labels' => defaultDatabaseLabels($this->database)->toArray(),
- 'healthcheck' => [
- 'test' => "keydb-cli --pass {$this->database->keydb_password} ping",
- 'interval' => '5s',
- 'timeout' => '5s',
- 'retries' => 10,
- 'start_period' => '5s',
- ],
- 'mem_limit' => $this->database->limits_memory,
- 'memswap_limit' => $this->database->limits_memory_swap,
- 'mem_swappiness' => $this->database->limits_memory_swappiness,
- 'mem_reservation' => $this->database->limits_memory_reservation,
- 'cpus' => (float) $this->database->limits_cpus,
- 'cpu_shares' => $this->database->limits_cpu_shares,
- ],
- ],
- 'networks' => [
- $this->database->destination->network => [
- 'external' => true,
- 'name' => $this->database->destination->network,
- 'attachable' => true,
- ],
- ],
- ];
- if (! is_null($this->database->limits_cpuset)) {
- data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
- }
- if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
- $docker_compose['services'][$container_name]['logging'] = generate_fluentd_configuration();
- }
- if (count($this->database->ports_mappings_array) > 0) {
- $docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
- }
- if (count($persistent_storages) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
- }
- if (count($persistent_file_volumes) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
- return "$item->fs_path:$item->mount_path";
- })->toArray();
- }
- if (count($volume_names) > 0) {
- $docker_compose['volumes'] = $volume_names;
- }
- if (! is_null($this->database->keydb_conf) || ! empty($this->database->keydb_conf)) {
- $docker_compose['services'][$container_name]['volumes'][] = [
- 'type' => 'bind',
- 'source' => $this->configuration_dir.'/keydb.conf',
- 'target' => '/etc/keydb/keydb.conf',
- 'read_only' => true,
- ];
- $docker_compose['services'][$container_name]['command'] = "keydb-server /etc/keydb/keydb.conf --requirepass {$this->database->keydb_password} --appendonly yes";
- }
-
- // Add custom docker run options
- $docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
- $docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
- $docker_compose = Yaml::dump($docker_compose, 10);
- $docker_compose_base64 = base64_encode($docker_compose);
- $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
- $readme = generate_readme_file($this->database->name, now());
- $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
- $this->commands[] = "echo 'Pulling {$database->image} image.'";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
- $this->commands[] = "echo 'Database started.'";
-
- return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
- }
-
- private function generate_local_persistent_volumes()
- {
- $local_persistent_volumes = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
- $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
- } else {
- $volume_name = $persistentStorage->name;
- $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
- }
- }
-
- return $local_persistent_volumes;
- }
-
- private function generate_local_persistent_volumes_only_volume_names()
- {
- $local_persistent_volumes_names = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path) {
- continue;
- }
- $name = $persistentStorage->name;
- $local_persistent_volumes_names[$name] = [
- 'name' => $name,
- 'external' => false,
- ];
- }
-
- return $local_persistent_volumes_names;
- }
-
- private function generate_environment_variables()
- {
- $environment_variables = collect();
- foreach ($this->database->runtime_environment_variables as $env) {
- $environment_variables->push("$env->key=$env->real_value");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
- $environment_variables->push("REDIS_PASSWORD={$this->database->keydb_password}");
- }
-
- add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables);
-
- return $environment_variables->all();
- }
-
- private function add_custom_keydb()
- {
- if (is_null($this->database->keydb_conf) || empty($this->database->keydb_conf)) {
- return;
- }
- $filename = 'keydb.conf';
- Storage::disk('local')->put("tmp/keydb.conf_{$this->database->uuid}", $this->database->keydb_conf);
- $path = Storage::path("tmp/keydb.conf_{$this->database->uuid}");
- instant_scp($path, "{$this->configuration_dir}/{$filename}", $this->database->destination->server);
- Storage::disk('local')->delete("tmp/keydb.conf_{$this->database->uuid}");
- }
-}
diff --git a/app/Actions/Database/StartMariadb.php b/app/Actions/Database/StartMariadb.php
deleted file mode 100644
index 299b07385b..0000000000
--- a/app/Actions/Database/StartMariadb.php
+++ /dev/null
@@ -1,185 +0,0 @@
-database = $database;
-
- $container_name = $this->database->uuid;
- $this->configuration_dir = database_configuration_dir().'/'.$container_name;
-
- $this->commands = [
- "echo 'Starting database.'",
- "mkdir -p $this->configuration_dir",
- ];
-
- $persistent_storages = $this->generate_local_persistent_volumes();
- $persistent_file_volumes = $this->database->fileStorages()->get();
- $volume_names = $this->generate_local_persistent_volumes_only_volume_names();
- $environment_variables = $this->generate_environment_variables();
- $this->add_custom_mysql();
- $docker_compose = [
- 'services' => [
- $container_name => [
- 'image' => $this->database->image,
- 'container_name' => $container_name,
- 'environment' => $environment_variables,
- 'restart' => RESTART_MODE,
- 'networks' => [
- $this->database->destination->network,
- ],
- 'labels' => defaultDatabaseLabels($this->database)->toArray(),
- 'healthcheck' => [
- 'test' => ['CMD', 'healthcheck.sh', '--connect', '--innodb_initialized'],
- 'interval' => '5s',
- 'timeout' => '5s',
- 'retries' => 10,
- 'start_period' => '5s',
- ],
- 'mem_limit' => $this->database->limits_memory,
- 'memswap_limit' => $this->database->limits_memory_swap,
- 'mem_swappiness' => $this->database->limits_memory_swappiness,
- 'mem_reservation' => $this->database->limits_memory_reservation,
- 'cpus' => (float) $this->database->limits_cpus,
- 'cpu_shares' => $this->database->limits_cpu_shares,
- ],
- ],
- 'networks' => [
- $this->database->destination->network => [
- 'external' => true,
- 'name' => $this->database->destination->network,
- 'attachable' => true,
- ],
- ],
- ];
- if (! is_null($this->database->limits_cpuset)) {
- data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
- }
- if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
- $docker_compose['services'][$container_name]['logging'] = generate_fluentd_configuration();
- }
- if (count($this->database->ports_mappings_array) > 0) {
- $docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
- }
- if (count($persistent_storages) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
- }
- if (count($persistent_file_volumes) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
- return "$item->fs_path:$item->mount_path";
- })->toArray();
- }
- if (count($volume_names) > 0) {
- $docker_compose['volumes'] = $volume_names;
- }
- if (! is_null($this->database->mariadb_conf) || ! empty($this->database->mariadb_conf)) {
- $docker_compose['services'][$container_name]['volumes'][] = [
- 'type' => 'bind',
- 'source' => $this->configuration_dir.'/custom-config.cnf',
- 'target' => '/etc/mysql/conf.d/custom-config.cnf',
- 'read_only' => true,
- ];
- }
-
- // Add custom docker run options
- $docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
- $docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
-
- $docker_compose = Yaml::dump($docker_compose, 10);
- $docker_compose_base64 = base64_encode($docker_compose);
- $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
- $readme = generate_readme_file($this->database->name, now());
- $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
- $this->commands[] = "echo 'Pulling {$database->image} image.'";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
- $this->commands[] = "echo 'Database started.'";
-
- return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
- }
-
- private function generate_local_persistent_volumes()
- {
- $local_persistent_volumes = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
- $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
- } else {
- $volume_name = $persistentStorage->name;
- $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
- }
- }
-
- return $local_persistent_volumes;
- }
-
- private function generate_local_persistent_volumes_only_volume_names()
- {
- $local_persistent_volumes_names = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path) {
- continue;
- }
- $name = $persistentStorage->name;
- $local_persistent_volumes_names[$name] = [
- 'name' => $name,
- 'external' => false,
- ];
- }
-
- return $local_persistent_volumes_names;
- }
-
- private function generate_environment_variables()
- {
- $environment_variables = collect();
- foreach ($this->database->runtime_environment_variables as $env) {
- $environment_variables->push("$env->key=$env->real_value");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_ROOT_PASSWORD'))->isEmpty()) {
- $environment_variables->push("MARIADB_ROOT_PASSWORD={$this->database->mariadb_root_password}");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_DATABASE'))->isEmpty()) {
- $environment_variables->push("MARIADB_DATABASE={$this->database->mariadb_database}");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_USER'))->isEmpty()) {
- $environment_variables->push("MARIADB_USER={$this->database->mariadb_user}");
- }
- if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_PASSWORD'))->isEmpty()) {
- $environment_variables->push("MARIADB_PASSWORD={$this->database->mariadb_password}");
- }
-
- add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables);
-
- return $environment_variables->all();
- }
-
- private function add_custom_mysql()
- {
- if (is_null($this->database->mariadb_conf) || empty($this->database->mariadb_conf)) {
- return;
- }
- $filename = 'custom-config.cnf';
- $content = $this->database->mariadb_conf;
- $content_base64 = base64_encode($content);
- $this->commands[] = "echo '{$content_base64}' | base64 -d | tee $this->configuration_dir/{$filename} > /dev/null";
- }
-}
diff --git a/app/Actions/Database/StartMongodb.php b/app/Actions/Database/StartMongodb.php
deleted file mode 100644
index 89d35ca7b4..0000000000
--- a/app/Actions/Database/StartMongodb.php
+++ /dev/null
@@ -1,210 +0,0 @@
-database = $database;
-
- $startCommand = 'mongod';
-
- $container_name = $this->database->uuid;
- $this->configuration_dir = database_configuration_dir().'/'.$container_name;
-
- if (isDev()) {
- $this->configuration_dir = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/databases/'.$container_name;
- }
-
- $this->commands = [
- "echo 'Starting database.'",
- "mkdir -p $this->configuration_dir",
- ];
-
- $persistent_storages = $this->generate_local_persistent_volumes();
- $persistent_file_volumes = $this->database->fileStorages()->get();
- $volume_names = $this->generate_local_persistent_volumes_only_volume_names();
- $environment_variables = $this->generate_environment_variables();
- $this->add_custom_mongo_conf();
-
- $docker_compose = [
- 'services' => [
- $container_name => [
- 'image' => $this->database->image,
- 'command' => $startCommand,
- 'container_name' => $container_name,
- 'environment' => $environment_variables,
- 'restart' => RESTART_MODE,
- 'networks' => [
- $this->database->destination->network,
- ],
- 'labels' => defaultDatabaseLabels($this->database)->toArray(),
- 'healthcheck' => [
- 'test' => [
- 'CMD',
- 'echo',
- 'ok',
- ],
- 'interval' => '5s',
- 'timeout' => '5s',
- 'retries' => 10,
- 'start_period' => '5s',
- ],
- 'mem_limit' => $this->database->limits_memory,
- 'memswap_limit' => $this->database->limits_memory_swap,
- 'mem_swappiness' => $this->database->limits_memory_swappiness,
- 'mem_reservation' => $this->database->limits_memory_reservation,
- 'cpus' => (float) $this->database->limits_cpus,
- 'cpu_shares' => $this->database->limits_cpu_shares,
- ],
- ],
- 'networks' => [
- $this->database->destination->network => [
- 'external' => true,
- 'name' => $this->database->destination->network,
- 'attachable' => true,
- ],
- ],
- ];
- if (! is_null($this->database->limits_cpuset)) {
- data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
- }
- if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
- $docker_compose['services'][$container_name]['logging'] = generate_fluentd_configuration();
- }
- if (count($this->database->ports_mappings_array) > 0) {
- $docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
- }
- if (count($persistent_storages) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
- }
- if (count($persistent_file_volumes) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
- return "$item->fs_path:$item->mount_path";
- })->toArray();
- }
- if (count($volume_names) > 0) {
- $docker_compose['volumes'] = $volume_names;
- }
- if (! is_null($this->database->mongo_conf) || ! empty($this->database->mongo_conf)) {
- $docker_compose['services'][$container_name]['volumes'][] = [
- 'type' => 'bind',
- 'source' => $this->configuration_dir.'/mongod.conf',
- 'target' => '/etc/mongo/mongod.conf',
- 'read_only' => true,
- ];
- $docker_compose['services'][$container_name]['command'] = $startCommand.' --config /etc/mongo/mongod.conf';
- }
- $this->add_default_database();
- $docker_compose['services'][$container_name]['volumes'][] = [
- 'type' => 'bind',
- 'source' => $this->configuration_dir.'/docker-entrypoint-initdb.d',
- 'target' => '/docker-entrypoint-initdb.d',
- 'read_only' => true,
- ];
-
- // Add custom docker run options
- $docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
- $docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
-
- $docker_compose = Yaml::dump($docker_compose, 10);
- $docker_compose_base64 = base64_encode($docker_compose);
- $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
- $readme = generate_readme_file($this->database->name, now());
- $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
- $this->commands[] = "echo 'Pulling {$database->image} image.'";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
- $this->commands[] = "echo 'Database started.'";
-
- return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
- }
-
- private function generate_local_persistent_volumes()
- {
- $local_persistent_volumes = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
- $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
- } else {
- $volume_name = $persistentStorage->name;
- $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
- }
- }
-
- return $local_persistent_volumes;
- }
-
- private function generate_local_persistent_volumes_only_volume_names()
- {
- $local_persistent_volumes_names = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path) {
- continue;
- }
- $name = $persistentStorage->name;
- $local_persistent_volumes_names[$name] = [
- 'name' => $name,
- 'external' => false,
- ];
- }
-
- return $local_persistent_volumes_names;
- }
-
- private function generate_environment_variables()
- {
- $environment_variables = collect();
- foreach ($this->database->runtime_environment_variables as $env) {
- $environment_variables->push("$env->key=$env->real_value");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_ROOT_USERNAME'))->isEmpty()) {
- $environment_variables->push("MONGO_INITDB_ROOT_USERNAME={$this->database->mongo_initdb_root_username}");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_ROOT_PASSWORD'))->isEmpty()) {
- $environment_variables->push("MONGO_INITDB_ROOT_PASSWORD={$this->database->mongo_initdb_root_password}");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_DATABASE'))->isEmpty()) {
- $environment_variables->push("MONGO_INITDB_DATABASE={$this->database->mongo_initdb_database}");
- }
-
- add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables);
-
- return $environment_variables->all();
- }
-
- private function add_custom_mongo_conf()
- {
- if (is_null($this->database->mongo_conf) || empty($this->database->mongo_conf)) {
- return;
- }
- $filename = 'mongod.conf';
- $content = $this->database->mongo_conf;
- $content_base64 = base64_encode($content);
- $this->commands[] = "echo '{$content_base64}' | base64 -d | tee $this->configuration_dir/{$filename} > /dev/null";
- }
-
- private function add_default_database()
- {
- $content = "db = db.getSiblingDB(\"{$this->database->mongo_initdb_database}\");db.createCollection('init_collection');db.createUser({user: \"{$this->database->mongo_initdb_root_username}\", pwd: \"{$this->database->mongo_initdb_root_password}\",roles: [{role:\"readWrite\",db:\"{$this->database->mongo_initdb_database}\"}]});";
- $content_base64 = base64_encode($content);
- $this->commands[] = "mkdir -p $this->configuration_dir/docker-entrypoint-initdb.d";
- $this->commands[] = "echo '{$content_base64}' | base64 -d | tee $this->configuration_dir/docker-entrypoint-initdb.d/01-default-database.js > /dev/null";
- }
-}
diff --git a/app/Actions/Database/StartMysql.php b/app/Actions/Database/StartMysql.php
deleted file mode 100644
index 73db1512a3..0000000000
--- a/app/Actions/Database/StartMysql.php
+++ /dev/null
@@ -1,185 +0,0 @@
-database = $database;
-
- $container_name = $this->database->uuid;
- $this->configuration_dir = database_configuration_dir().'/'.$container_name;
-
- $this->commands = [
- "echo 'Starting database.'",
- "mkdir -p $this->configuration_dir",
- ];
-
- $persistent_storages = $this->generate_local_persistent_volumes();
- $persistent_file_volumes = $this->database->fileStorages()->get();
- $volume_names = $this->generate_local_persistent_volumes_only_volume_names();
- $environment_variables = $this->generate_environment_variables();
- $this->add_custom_mysql();
- $docker_compose = [
- 'services' => [
- $container_name => [
- 'image' => $this->database->image,
- 'container_name' => $container_name,
- 'environment' => $environment_variables,
- 'restart' => RESTART_MODE,
- 'networks' => [
- $this->database->destination->network,
- ],
- 'labels' => defaultDatabaseLabels($this->database)->toArray(),
- 'healthcheck' => [
- 'test' => ['CMD', 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', "-p{$this->database->mysql_root_password}"],
- 'interval' => '5s',
- 'timeout' => '5s',
- 'retries' => 10,
- 'start_period' => '5s',
- ],
- 'mem_limit' => $this->database->limits_memory,
- 'memswap_limit' => $this->database->limits_memory_swap,
- 'mem_swappiness' => $this->database->limits_memory_swappiness,
- 'mem_reservation' => $this->database->limits_memory_reservation,
- 'cpus' => (float) $this->database->limits_cpus,
- 'cpu_shares' => $this->database->limits_cpu_shares,
- ],
- ],
- 'networks' => [
- $this->database->destination->network => [
- 'external' => true,
- 'name' => $this->database->destination->network,
- 'attachable' => true,
- ],
- ],
- ];
- if (! is_null($this->database->limits_cpuset)) {
- data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
- }
- if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
- $docker_compose['services'][$container_name]['logging'] = generate_fluentd_configuration();
- }
- if (count($this->database->ports_mappings_array) > 0) {
- $docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
- }
- if (count($persistent_storages) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
- }
- if (count($persistent_file_volumes) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
- return "$item->fs_path:$item->mount_path";
- })->toArray();
- }
- if (count($volume_names) > 0) {
- $docker_compose['volumes'] = $volume_names;
- }
- if (! is_null($this->database->mysql_conf) || ! empty($this->database->mysql_conf)) {
- $docker_compose['services'][$container_name]['volumes'][] = [
- 'type' => 'bind',
- 'source' => $this->configuration_dir.'/custom-config.cnf',
- 'target' => '/etc/mysql/conf.d/custom-config.cnf',
- 'read_only' => true,
- ];
- }
-
- // Add custom docker run options
- $docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
- $docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
-
- $docker_compose = Yaml::dump($docker_compose, 10);
- $docker_compose_base64 = base64_encode($docker_compose);
- $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
- $readme = generate_readme_file($this->database->name, now());
- $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
- $this->commands[] = "echo 'Pulling {$database->image} image.'";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
- $this->commands[] = "echo 'Database started.'";
-
- return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
- }
-
- private function generate_local_persistent_volumes()
- {
- $local_persistent_volumes = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
- $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
- } else {
- $volume_name = $persistentStorage->name;
- $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
- }
- }
-
- return $local_persistent_volumes;
- }
-
- private function generate_local_persistent_volumes_only_volume_names()
- {
- $local_persistent_volumes_names = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path) {
- continue;
- }
- $name = $persistentStorage->name;
- $local_persistent_volumes_names[$name] = [
- 'name' => $name,
- 'external' => false,
- ];
- }
-
- return $local_persistent_volumes_names;
- }
-
- private function generate_environment_variables()
- {
- $environment_variables = collect();
- foreach ($this->database->runtime_environment_variables as $env) {
- $environment_variables->push("$env->key=$env->real_value");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_ROOT_PASSWORD'))->isEmpty()) {
- $environment_variables->push("MYSQL_ROOT_PASSWORD={$this->database->mysql_root_password}");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_DATABASE'))->isEmpty()) {
- $environment_variables->push("MYSQL_DATABASE={$this->database->mysql_database}");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_USER'))->isEmpty()) {
- $environment_variables->push("MYSQL_USER={$this->database->mysql_user}");
- }
- if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_PASSWORD'))->isEmpty()) {
- $environment_variables->push("MYSQL_PASSWORD={$this->database->mysql_password}");
- }
-
- add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables);
-
- return $environment_variables->all();
- }
-
- private function add_custom_mysql()
- {
- if (is_null($this->database->mysql_conf) || empty($this->database->mysql_conf)) {
- return;
- }
- $filename = 'custom-config.cnf';
- $content = $this->database->mysql_conf;
- $content_base64 = base64_encode($content);
- $this->commands[] = "echo '{$content_base64}' | base64 -d | tee $this->configuration_dir/{$filename} > /dev/null";
- }
-}
diff --git a/app/Actions/Database/StartPostgresql.php b/app/Actions/Database/StartPostgresql.php
deleted file mode 100644
index 035849340d..0000000000
--- a/app/Actions/Database/StartPostgresql.php
+++ /dev/null
@@ -1,236 +0,0 @@
-database = $database;
- $container_name = $this->database->uuid;
- $this->configuration_dir = database_configuration_dir().'/'.$container_name;
- if (isDev()) {
- $this->configuration_dir = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/databases/'.$container_name;
- }
-
- $this->commands = [
- "echo 'Starting database.'",
- "mkdir -p $this->configuration_dir",
- "mkdir -p $this->configuration_dir/docker-entrypoint-initdb.d/",
- ];
-
- $persistent_storages = $this->generate_local_persistent_volumes();
- $persistent_file_volumes = $this->database->fileStorages()->get();
- $volume_names = $this->generate_local_persistent_volumes_only_volume_names();
- $environment_variables = $this->generate_environment_variables();
- $this->generate_init_scripts();
- $this->add_custom_conf();
-
- $docker_compose = [
- 'services' => [
- $container_name => [
- 'image' => $this->database->image,
- 'container_name' => $container_name,
- 'environment' => $environment_variables,
- 'restart' => RESTART_MODE,
- 'networks' => [
- $this->database->destination->network,
- ],
- 'labels' => defaultDatabaseLabels($this->database)->toArray(),
- 'healthcheck' => [
- 'test' => [
- 'CMD-SHELL',
- "psql -U {$this->database->postgres_user} -d {$this->database->postgres_db} -c 'SELECT 1' || exit 1",
- ],
- 'interval' => '5s',
- 'timeout' => '5s',
- 'retries' => 10,
- 'start_period' => '5s',
- ],
- 'mem_limit' => $this->database->limits_memory,
- 'memswap_limit' => $this->database->limits_memory_swap,
- 'mem_swappiness' => $this->database->limits_memory_swappiness,
- 'mem_reservation' => $this->database->limits_memory_reservation,
- 'cpus' => (float) $this->database->limits_cpus,
- 'cpu_shares' => $this->database->limits_cpu_shares,
- ],
- ],
- 'networks' => [
- $this->database->destination->network => [
- 'external' => true,
- 'name' => $this->database->destination->network,
- 'attachable' => true,
- ],
- ],
- ];
- if (filled($this->database->limits_cpuset)) {
- data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
- }
- if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
- $docker_compose['services'][$container_name]['logging'] = generate_fluentd_configuration();
- }
- if (count($this->database->ports_mappings_array) > 0) {
- $docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
- }
- if (count($persistent_storages) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
- }
- if (count($persistent_file_volumes) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
- return "$item->fs_path:$item->mount_path";
- })->toArray();
- }
- if (count($volume_names) > 0) {
- $docker_compose['volumes'] = $volume_names;
- }
- if (count($this->init_scripts) > 0) {
- foreach ($this->init_scripts as $init_script) {
- $docker_compose['services'][$container_name]['volumes'][] = [
- 'type' => 'bind',
- 'source' => $init_script,
- 'target' => '/docker-entrypoint-initdb.d/'.basename($init_script),
- 'read_only' => true,
- ];
- }
- }
- if (filled($this->database->postgres_conf)) {
- $docker_compose['services'][$container_name]['volumes'][] = [
- 'type' => 'bind',
- 'source' => $this->configuration_dir.'/custom-postgres.conf',
- 'target' => '/etc/postgresql/postgresql.conf',
- 'read_only' => true,
- ];
- $docker_compose['services'][$container_name]['command'] = [
- 'postgres',
- '-c',
- 'config_file=/etc/postgresql/postgresql.conf',
- ];
- }
- // Add custom docker run options
- $docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
- $docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
-
- $docker_compose = Yaml::dump($docker_compose, 10);
- $docker_compose_base64 = base64_encode($docker_compose);
- $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
- $readme = generate_readme_file($this->database->name, now());
- $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
- $this->commands[] = "echo 'Pulling {$database->image} image.'";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
- $this->commands[] = "echo 'Database started.'";
-
- return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
- }
-
- private function generate_local_persistent_volumes()
- {
- $local_persistent_volumes = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
- $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
- } else {
- $volume_name = $persistentStorage->name;
- $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
- }
- }
-
- return $local_persistent_volumes;
- }
-
- private function generate_local_persistent_volumes_only_volume_names()
- {
- $local_persistent_volumes_names = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path) {
- continue;
- }
- $name = $persistentStorage->name;
- $local_persistent_volumes_names[$name] = [
- 'name' => $name,
- 'external' => false,
- ];
- }
-
- return $local_persistent_volumes_names;
- }
-
- private function generate_environment_variables()
- {
- $environment_variables = collect();
- foreach ($this->database->runtime_environment_variables as $env) {
- $environment_variables->push("$env->key=$env->real_value");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('POSTGRES_USER'))->isEmpty()) {
- $environment_variables->push("POSTGRES_USER={$this->database->postgres_user}");
- }
- if ($environment_variables->filter(fn ($env) => str($env)->contains('PGUSER'))->isEmpty()) {
- $environment_variables->push("PGUSER={$this->database->postgres_user}");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('POSTGRES_PASSWORD'))->isEmpty()) {
- $environment_variables->push("POSTGRES_PASSWORD={$this->database->postgres_password}");
- }
-
- if ($environment_variables->filter(fn ($env) => str($env)->contains('POSTGRES_DB'))->isEmpty()) {
- $environment_variables->push("POSTGRES_DB={$this->database->postgres_db}");
- }
-
- add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables);
-
- return $environment_variables->all();
- }
-
- private function generate_init_scripts()
- {
- $this->commands[] = "rm -rf $this->configuration_dir/docker-entrypoint-initdb.d/*";
-
- if (blank($this->database->init_scripts) || count($this->database->init_scripts) === 0) {
- return;
- }
-
- foreach ($this->database->init_scripts as $init_script) {
- $filename = data_get($init_script, 'filename');
- $content = data_get($init_script, 'content');
- $content_base64 = base64_encode($content);
- $this->commands[] = "echo '{$content_base64}' | base64 -d | tee $this->configuration_dir/docker-entrypoint-initdb.d/{$filename} > /dev/null";
- $this->init_scripts[] = "$this->configuration_dir/docker-entrypoint-initdb.d/{$filename}";
- }
- }
-
- private function add_custom_conf()
- {
- $filename = 'custom-postgres.conf';
- $config_file_path = "$this->configuration_dir/$filename";
-
- if (blank($this->database->postgres_conf)) {
- $this->commands[] = "rm -f $config_file_path";
-
- return;
- }
-
- $content = $this->database->postgres_conf;
- if (! str($content)->contains('listen_addresses')) {
- $content .= "\nlisten_addresses = '*'";
- $this->database->postgres_conf = $content;
- $this->database->save();
- }
- $content_base64 = base64_encode($content);
- $this->commands[] = "echo '{$content_base64}' | base64 -d | tee $config_file_path > /dev/null";
- }
-}
diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php
deleted file mode 100644
index 1beebd134b..0000000000
--- a/app/Actions/Database/StartRedis.php
+++ /dev/null
@@ -1,219 +0,0 @@
-database = $database;
-
- $container_name = $this->database->uuid;
- $this->configuration_dir = database_configuration_dir().'/'.$container_name;
-
- $this->commands = [
- "echo 'Starting database.'",
- "mkdir -p $this->configuration_dir",
- ];
-
- $persistent_storages = $this->generate_local_persistent_volumes();
- $persistent_file_volumes = $this->database->fileStorages()->get();
- $volume_names = $this->generate_local_persistent_volumes_only_volume_names();
- $environment_variables = $this->generate_environment_variables();
- $this->add_custom_redis();
-
- $startCommand = $this->buildStartCommand();
-
- $docker_compose = [
- 'services' => [
- $container_name => [
- 'image' => $this->database->image,
- 'command' => $startCommand,
- 'container_name' => $container_name,
- 'environment' => $environment_variables,
- 'restart' => RESTART_MODE,
- 'networks' => [
- $this->database->destination->network,
- ],
- 'labels' => defaultDatabaseLabels($this->database)->toArray(),
- 'healthcheck' => [
- 'test' => [
- 'CMD-SHELL',
- 'redis-cli',
- 'ping',
- ],
- 'interval' => '5s',
- 'timeout' => '5s',
- 'retries' => 10,
- 'start_period' => '5s',
- ],
- 'mem_limit' => $this->database->limits_memory,
- 'memswap_limit' => $this->database->limits_memory_swap,
- 'mem_swappiness' => $this->database->limits_memory_swappiness,
- 'mem_reservation' => $this->database->limits_memory_reservation,
- 'cpus' => (float) $this->database->limits_cpus,
- 'cpu_shares' => $this->database->limits_cpu_shares,
- ],
- ],
- 'networks' => [
- $this->database->destination->network => [
- 'external' => true,
- 'name' => $this->database->destination->network,
- 'attachable' => true,
- ],
- ],
- ];
- if (! is_null($this->database->limits_cpuset)) {
- data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
- }
- if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
- $docker_compose['services'][$container_name]['logging'] = generate_fluentd_configuration();
- }
- if (count($this->database->ports_mappings_array) > 0) {
- $docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
- }
- if (count($persistent_storages) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
- }
- if (count($persistent_file_volumes) > 0) {
- $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
- return "$item->fs_path:$item->mount_path";
- })->toArray();
- }
- if (count($volume_names) > 0) {
- $docker_compose['volumes'] = $volume_names;
- }
- if (! is_null($this->database->redis_conf) || ! empty($this->database->redis_conf)) {
- $docker_compose['services'][$container_name]['volumes'][] = [
- 'type' => 'bind',
- 'source' => $this->configuration_dir.'/redis.conf',
- 'target' => '/usr/local/etc/redis/redis.conf',
- 'read_only' => true,
- ];
- }
-
- // Add custom docker run options
- $docker_run_options = convertDockerRunToCompose($this->database->custom_docker_run_options);
- $docker_compose = generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
-
- $docker_compose = Yaml::dump($docker_compose, 10);
- $docker_compose_base64 = base64_encode($docker_compose);
- $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
- $readme = generate_readme_file($this->database->name, now());
- $this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
- $this->commands[] = "echo 'Pulling {$database->image} image.'";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
- $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
- $this->commands[] = "echo 'Database started.'";
-
- return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
- }
-
- private function generate_local_persistent_volumes()
- {
- $local_persistent_volumes = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
- $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
- } else {
- $volume_name = $persistentStorage->name;
- $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
- }
- }
-
- return $local_persistent_volumes;
- }
-
- private function generate_local_persistent_volumes_only_volume_names()
- {
- $local_persistent_volumes_names = [];
- foreach ($this->database->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path) {
- continue;
- }
- $name = $persistentStorage->name;
- $local_persistent_volumes_names[$name] = [
- 'name' => $name,
- 'external' => false,
- ];
- }
-
- return $local_persistent_volumes_names;
- }
-
- private function generate_environment_variables()
- {
- $environment_variables = collect();
-
- foreach ($this->database->runtime_environment_variables as $env) {
- if ($env->is_shared) {
- $environment_variables->push("$env->key=$env->real_value");
-
- if ($env->key === 'REDIS_PASSWORD') {
- $this->database->update(['redis_password' => $env->real_value]);
- }
-
- if ($env->key === 'REDIS_USERNAME') {
- $this->database->update(['redis_username' => $env->real_value]);
- }
- } else {
- if ($env->key === 'REDIS_PASSWORD') {
- $env->update(['value' => $this->database->redis_password]);
- } elseif ($env->key === 'REDIS_USERNAME') {
- $env->update(['value' => $this->database->redis_username]);
- }
- $environment_variables->push("$env->key=$env->real_value");
- }
- }
-
- add_coolify_default_environment_variables($this->database, $environment_variables, $environment_variables);
-
- return $environment_variables->all();
- }
-
- private function buildStartCommand(): string
- {
- $hasRedisConf = ! is_null($this->database->redis_conf) && ! empty($this->database->redis_conf);
- $redisConfPath = '/usr/local/etc/redis/redis.conf';
-
- if ($hasRedisConf) {
- $confContent = $this->database->redis_conf;
- $hasRequirePass = str_contains($confContent, 'requirepass');
-
- if ($hasRequirePass) {
- $command = "redis-server $redisConfPath";
- } else {
- $command = "redis-server $redisConfPath --requirepass {$this->database->redis_password}";
- }
- } else {
- $command = "redis-server --requirepass {$this->database->redis_password} --appendonly yes";
- }
-
- return $command;
- }
-
- private function add_custom_redis()
- {
- if (is_null($this->database->redis_conf) || empty($this->database->redis_conf)) {
- return;
- }
- $filename = 'redis.conf';
- Storage::disk('local')->put("tmp/redis.conf_{$this->database->uuid}", $this->database->redis_conf);
- $path = Storage::path("tmp/redis.conf_{$this->database->uuid}");
- instant_scp($path, "{$this->configuration_dir}/{$filename}", $this->database->destination->server);
- Storage::disk('local')->delete("tmp/redis.conf_{$this->database->uuid}");
- }
-}
diff --git a/app/Actions/Database/StopDatabase.php b/app/Actions/Database/StopDatabase.php
deleted file mode 100644
index e4cea7cee8..0000000000
--- a/app/Actions/Database/StopDatabase.php
+++ /dev/null
@@ -1,75 +0,0 @@
-destination->server;
- if (! $server->isFunctional()) {
- return 'Server is not functional';
- }
-
- $this->stopContainer($database, $database->uuid, 300);
- if (! $isDeleteOperation) {
- if ($dockerCleanup) {
- CleanupDocker::dispatch($server, true);
- }
- }
-
- if ($database->is_public) {
- StopDatabaseProxy::run($database);
- }
-
- return 'Database stopped successfully';
- }
-
- private function stopContainer($database, string $containerName, int $timeout = 300): void
- {
- $server = $database->destination->server;
-
- $process = Process::timeout($timeout)->start("docker stop --time=$timeout $containerName");
-
- $startTime = time();
- while ($process->running()) {
- if (time() - $startTime >= $timeout) {
- $this->forceStopContainer($containerName, $server);
- break;
- }
- usleep(100000);
- }
-
- $this->removeContainer($containerName, $server);
- }
-
- private function forceStopContainer(string $containerName, $server): void
- {
- instant_remote_process(command: ["docker kill $containerName"], server: $server, throwError: false);
- }
-
- private function removeContainer(string $containerName, $server): void
- {
- instant_remote_process(command: ["docker rm -f $containerName"], server: $server, throwError: false);
- }
-
- private function deleteConnectedNetworks($uuid, $server)
- {
- instant_remote_process(["docker network disconnect {$uuid} coolify-proxy"], $server, false);
- instant_remote_process(["docker network rm {$uuid}"], $server, false);
- }
-}
diff --git a/app/Actions/Database/StopDatabaseProxy.php b/app/Actions/Database/StopDatabaseProxy.php
deleted file mode 100644
index a753153eb5..0000000000
--- a/app/Actions/Database/StopDatabaseProxy.php
+++ /dev/null
@@ -1,38 +0,0 @@
-uuid;
- if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
- $uuid = $database->service->uuid;
- $server = data_get($database, 'service.server');
- }
- instant_remote_process(["docker rm -f {$uuid}-proxy"], $server);
-
- $database->save();
-
- DatabaseProxyStopped::dispatch();
-
- }
-}
diff --git a/app/Actions/Docker/GetContainersStatus.php b/app/Actions/Docker/GetContainersStatus.php
deleted file mode 100644
index 091268043e..0000000000
--- a/app/Actions/Docker/GetContainersStatus.php
+++ /dev/null
@@ -1,345 +0,0 @@
-containers = $containers;
- $this->containerReplicates = $containerReplicates;
- $this->server = $server;
- if (! $this->server->isFunctional()) {
- return 'Server is not functional.';
- }
- $this->applications = $this->server->applications();
- $skip_these_applications = collect([]);
- foreach ($this->applications as $application) {
- if ($application->additional_servers->count() > 0) {
- $skip_these_applications->push($application);
- ComplexStatusCheck::run($application);
- $this->applications = $this->applications->filter(function ($value, $key) use ($application) {
- return $value->id !== $application->id;
- });
- }
- }
- $this->applications = $this->applications->filter(function ($value, $key) use ($skip_these_applications) {
- return ! $skip_these_applications->pluck('id')->contains($value->id);
- });
- if ($this->containers === null) {
- ['containers' => $this->containers, 'containerReplicates' => $this->containerReplicates] = $this->server->getContainers();
- }
-
- if (is_null($this->containers)) {
- return;
- }
-
- if ($this->containerReplicates) {
- foreach ($this->containerReplicates as $containerReplica) {
- $name = data_get($containerReplica, 'Name');
- $this->containers = $this->containers->map(function ($container) use ($name, $containerReplica) {
- if (data_get($container, 'Spec.Name') === $name) {
- $replicas = data_get($containerReplica, 'Replicas');
- $running = str($replicas)->explode('/')[0];
- $total = str($replicas)->explode('/')[1];
- if ($running === $total) {
- data_set($container, 'State.Status', 'running');
- data_set($container, 'State.Health.Status', 'healthy');
- } else {
- data_set($container, 'State.Status', 'starting');
- data_set($container, 'State.Health.Status', 'unhealthy');
- }
- }
-
- return $container;
- });
- }
- }
- $databases = $this->server->databases();
- $services = $this->server->services()->get();
- $previews = $this->server->previews();
- $foundApplications = [];
- $foundApplicationPreviews = [];
- $foundDatabases = [];
- $foundServices = [];
-
- foreach ($this->containers as $container) {
- if ($this->server->isSwarm()) {
- $labels = data_get($container, 'Spec.Labels');
- $uuid = data_get($labels, 'coolify.name');
- } else {
- $labels = data_get($container, 'Config.Labels');
- }
- $containerStatus = data_get($container, 'State.Status');
- $containerHealth = data_get($container, 'State.Health.Status', 'unhealthy');
- $containerStatus = "$containerStatus ($containerHealth)";
- $labels = Arr::undot(format_docker_labels_to_json($labels));
- $applicationId = data_get($labels, 'coolify.applicationId');
- if ($applicationId) {
- $pullRequestId = data_get($labels, 'coolify.pullRequestId');
- if ($pullRequestId) {
- if (str($applicationId)->contains('-')) {
- $applicationId = str($applicationId)->before('-');
- }
- $preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first();
- if ($preview) {
- $foundApplicationPreviews[] = $preview->id;
- $statusFromDb = $preview->status;
- if ($statusFromDb !== $containerStatus) {
- $preview->update(['status' => $containerStatus]);
- } else {
- $preview->update(['last_online_at' => now()]);
- }
- } else {
- // Notify user that this container should not be there.
- }
- } else {
- $application = $this->applications->where('id', $applicationId)->first();
- if ($application) {
- $foundApplications[] = $application->id;
- $statusFromDb = $application->status;
- if ($statusFromDb !== $containerStatus) {
- $application->update(['status' => $containerStatus]);
- } else {
- $application->update(['last_online_at' => now()]);
- }
- } else {
- // Notify user that this container should not be there.
- }
- }
- } else {
- $uuid = data_get($labels, 'com.docker.compose.service');
- $type = data_get($labels, 'coolify.type');
-
- if ($uuid) {
- if ($type === 'service') {
- $database_id = data_get($labels, 'coolify.service.subId');
- if ($database_id) {
- $service_db = ServiceDatabase::where('id', $database_id)->first();
- if ($service_db) {
- $uuid = data_get($service_db, 'service.uuid');
- if ($uuid) {
- $isPublic = data_get($service_db, 'is_public');
- if ($isPublic) {
- $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
- if ($this->server->isSwarm()) {
- return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
- } else {
- return data_get($value, 'Name') === "/$uuid-proxy";
- }
- })->first();
- if (! $foundTcpProxy) {
- StartDatabaseProxy::run($service_db);
- // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
- }
- }
- }
- }
- }
- } else {
- $database = $databases->where('uuid', $uuid)->first();
- if ($database) {
- $isPublic = data_get($database, 'is_public');
- $foundDatabases[] = $database->id;
- $statusFromDb = $database->status;
- if ($statusFromDb !== $containerStatus) {
- $database->update(['status' => $containerStatus]);
- } else {
- $database->update(['last_online_at' => now()]);
- }
-
- if ($isPublic) {
- $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
- if ($this->server->isSwarm()) {
- return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
- } else {
- return data_get($value, 'Name') === "/$uuid-proxy";
- }
- })->first();
- if (! $foundTcpProxy) {
- StartDatabaseProxy::run($database);
- // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for database", $this->server));
- }
- }
- } else {
- // Notify user that this container should not be there.
- }
- }
- }
- if (data_get($container, 'Name') === '/coolify-db') {
- $foundDatabases[] = 0;
- }
- }
- $serviceLabelId = data_get($labels, 'coolify.serviceId');
- if ($serviceLabelId) {
- $subType = data_get($labels, 'coolify.service.subType');
- $subId = data_get($labels, 'coolify.service.subId');
- $service = $services->where('id', $serviceLabelId)->first();
- if (! $service) {
- continue;
- }
- if ($subType === 'application') {
- $service = $service->applications()->where('id', $subId)->first();
- } else {
- $service = $service->databases()->where('id', $subId)->first();
- }
- if ($service) {
- $foundServices[] = "$service->id-$service->name";
- $statusFromDb = $service->status;
- if ($statusFromDb !== $containerStatus) {
- $service->update(['status' => $containerStatus]);
- } else {
- $service->update(['last_online_at' => now()]);
- }
- }
- }
- }
- $exitedServices = collect([]);
- foreach ($services as $service) {
- $apps = $service->applications()->get();
- $dbs = $service->databases()->get();
- foreach ($apps as $app) {
- if (in_array("$app->id-$app->name", $foundServices)) {
- continue;
- } else {
- $exitedServices->push($app);
- }
- }
- foreach ($dbs as $db) {
- if (in_array("$db->id-$db->name", $foundServices)) {
- continue;
- } else {
- $exitedServices->push($db);
- }
- }
- }
- $exitedServices = $exitedServices->unique('uuid');
- foreach ($exitedServices as $exitedService) {
- if (str($exitedService->status)->startsWith('exited')) {
- continue;
- }
- $name = data_get($exitedService, 'name');
- $fqdn = data_get($exitedService, 'fqdn');
- if ($name) {
- if ($fqdn) {
- $containerName = "$name, available at $fqdn";
- } else {
- $containerName = $name;
- }
- } else {
- if ($fqdn) {
- $containerName = $fqdn;
- } else {
- $containerName = null;
- }
- }
- $projectUuid = data_get($service, 'environment.project.uuid');
- $serviceUuid = data_get($service, 'uuid');
- $environmentName = data_get($service, 'environment.name');
-
- if ($projectUuid && $serviceUuid && $environmentName) {
- $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/service/'.$serviceUuid;
- } else {
- $url = null;
- }
- // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
- $exitedService->update(['status' => 'exited']);
- }
-
- $notRunningApplications = $this->applications->pluck('id')->diff($foundApplications);
- foreach ($notRunningApplications as $applicationId) {
- $application = $this->applications->where('id', $applicationId)->first();
- if (str($application->status)->startsWith('exited')) {
- continue;
- }
- $application->update(['status' => 'exited']);
-
- $name = data_get($application, 'name');
- $fqdn = data_get($application, 'fqdn');
-
- $containerName = $name ? "$name ($fqdn)" : $fqdn;
-
- $projectUuid = data_get($application, 'environment.project.uuid');
- $applicationUuid = data_get($application, 'uuid');
- $environment = data_get($application, 'environment.name');
-
- if ($projectUuid && $applicationUuid && $environment) {
- $url = base_url().'/project/'.$projectUuid.'/'.$environment.'/application/'.$applicationUuid;
- } else {
- $url = null;
- }
-
- // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
- }
- $notRunningApplicationPreviews = $previews->pluck('id')->diff($foundApplicationPreviews);
- foreach ($notRunningApplicationPreviews as $previewId) {
- $preview = $previews->where('id', $previewId)->first();
- if (str($preview->status)->startsWith('exited')) {
- continue;
- }
- $preview->update(['status' => 'exited']);
-
- $name = data_get($preview, 'name');
- $fqdn = data_get($preview, 'fqdn');
-
- $containerName = $name ? "$name ($fqdn)" : $fqdn;
-
- $projectUuid = data_get($preview, 'application.environment.project.uuid');
- $environmentName = data_get($preview, 'application.environment.name');
- $applicationUuid = data_get($preview, 'application.uuid');
-
- if ($projectUuid && $applicationUuid && $environmentName) {
- $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/application/'.$applicationUuid;
- } else {
- $url = null;
- }
-
- // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
- }
- $notRunningDatabases = $databases->pluck('id')->diff($foundDatabases);
- foreach ($notRunningDatabases as $database) {
- $database = $databases->where('id', $database)->first();
- if (str($database->status)->startsWith('exited')) {
- continue;
- }
- $database->update(['status' => 'exited']);
-
- $name = data_get($database, 'name');
- $fqdn = data_get($database, 'fqdn');
-
- $containerName = $name;
-
- $projectUuid = data_get($database, 'environment.project.uuid');
- $environmentName = data_get($database, 'environment.name');
- $databaseUuid = data_get($database, 'uuid');
-
- if ($projectUuid && $databaseUuid && $environmentName) {
- $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/database/'.$databaseUuid;
- } else {
- $url = null;
- }
- // $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
- }
- }
-}
diff --git a/app/Actions/Fortify/CreateNewUser.php b/app/Actions/Fortify/CreateNewUser.php
deleted file mode 100644
index ea2befd3a8..0000000000
--- a/app/Actions/Fortify/CreateNewUser.php
+++ /dev/null
@@ -1,70 +0,0 @@
- $input
- */
- public function create(array $input): User
- {
- $settings = instanceSettings();
- if (! $settings->is_registration_enabled) {
- abort(403);
- }
- Validator::make($input, [
- 'name' => ['required', 'string', 'max:255'],
- 'email' => [
- 'required',
- 'string',
- 'email',
- 'max:255',
- Rule::unique(User::class),
- ],
- 'password' => ['required', Password::defaults(), 'confirmed'],
- ])->validate();
-
- if (User::count() == 0) {
- // If this is the first user, make them the root user
- // Team is already created in the database/seeders/ProductionSeeder.php
- $user = User::create([
- 'id' => 0,
- 'name' => $input['name'],
- 'email' => strtolower($input['email']),
- 'password' => Hash::make($input['password']),
- ]);
- $team = $user->teams()->first();
-
- // Disable registration after first user is created
- $settings = instanceSettings();
- $settings->is_registration_enabled = false;
- $settings->save();
- } else {
- $user = User::create([
- 'name' => $input['name'],
- 'email' => strtolower($input['email']),
- 'password' => Hash::make($input['password']),
- ]);
- $team = $user->teams()->first();
- if (isCloud()) {
- $user->sendVerificationEmail();
- } else {
- $user->markEmailAsVerified();
- }
- }
- // Set session variable
- session(['currentTeam' => $user->currentTeam = $team]);
-
- return $user;
- }
-}
diff --git a/app/Actions/Fortify/ResetUserPassword.php b/app/Actions/Fortify/ResetUserPassword.php
deleted file mode 100644
index d3727a52cd..0000000000
--- a/app/Actions/Fortify/ResetUserPassword.php
+++ /dev/null
@@ -1,28 +0,0 @@
- $input
- */
- public function reset(User $user, array $input): void
- {
- Validator::make($input, [
- 'password' => ['required', Password::defaults(), 'confirmed'],
- ])->validate();
-
- $user->forceFill([
- 'password' => Hash::make($input['password']),
- ])->save();
- }
-}
diff --git a/app/Actions/Fortify/UpdateUserPassword.php b/app/Actions/Fortify/UpdateUserPassword.php
deleted file mode 100644
index 0c51ec56db..0000000000
--- a/app/Actions/Fortify/UpdateUserPassword.php
+++ /dev/null
@@ -1,31 +0,0 @@
- $input
- */
- public function update(User $user, array $input): void
- {
- Validator::make($input, [
- 'current_password' => ['required', 'string', 'current_password:web'],
- 'password' => ['required', Password::defaults(), 'confirmed'],
- ], [
- 'current_password.current_password' => __('The provided password does not match your current password.'),
- ])->validateWithBag('updatePassword');
-
- $user->forceFill([
- 'password' => Hash::make($input['password']),
- ])->save();
- }
-}
diff --git a/app/Actions/Fortify/UpdateUserProfileInformation.php b/app/Actions/Fortify/UpdateUserProfileInformation.php
deleted file mode 100644
index c8bfd930a6..0000000000
--- a/app/Actions/Fortify/UpdateUserProfileInformation.php
+++ /dev/null
@@ -1,60 +0,0 @@
- $input
- */
- public function update(User $user, array $input): void
- {
- Validator::make($input, [
- 'name' => ['required', 'string', 'max:255'],
-
- 'email' => [
- 'required',
- 'string',
- 'email',
- 'max:255',
- Rule::unique('users')->ignore($user->id),
- ],
- ])->validateWithBag('updateProfileInformation');
-
- if (
- $input['email'] !== $user->email &&
- $user instanceof MustVerifyEmail
- ) {
- $this->updateVerifiedUser($user, $input);
- } else {
- $user->forceFill([
- 'name' => $input['name'],
- 'email' => $input['email'],
- ])->save();
- }
- }
-
- /**
- * Update the given verified user's profile information.
- *
- * @param array $input
- */
- protected function updateVerifiedUser(User $user, array $input): void
- {
- $user->forceFill([
- 'name' => $input['name'],
- 'email' => $input['email'],
- 'email_verified_at' => null,
- ])->save();
-
- $user->sendEmailVerificationNotification();
- }
-}
diff --git a/app/Actions/Proxy/CheckConfiguration.php b/app/Actions/Proxy/CheckConfiguration.php
deleted file mode 100644
index bdeafd0611..0000000000
--- a/app/Actions/Proxy/CheckConfiguration.php
+++ /dev/null
@@ -1,33 +0,0 @@
-proxyType();
- if ($proxyType === 'NONE') {
- return 'OK';
- }
- $proxy_path = $server->proxyPath();
- $payload = [
- "mkdir -p $proxy_path",
- "cat $proxy_path/docker-compose.yml",
- ];
- $proxy_configuration = instant_remote_process($payload, $server, false);
- if ($reset || ! $proxy_configuration || is_null($proxy_configuration)) {
- $proxy_configuration = str(generate_default_proxy_configuration($server))->trim()->value();
- }
- if (! $proxy_configuration || is_null($proxy_configuration)) {
- throw new \Exception('Could not generate proxy configuration');
- }
-
- return $proxy_configuration;
- }
-}
diff --git a/app/Actions/Proxy/CheckProxy.php b/app/Actions/Proxy/CheckProxy.php
deleted file mode 100644
index 6c8dd52347..0000000000
--- a/app/Actions/Proxy/CheckProxy.php
+++ /dev/null
@@ -1,111 +0,0 @@
-isFunctional()) {
- return false;
- }
- if ($server->isBuildServer()) {
- if ($server->proxy) {
- $server->proxy = null;
- $server->save();
- }
-
- return false;
- }
- $proxyType = $server->proxyType();
- if (is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop) {
- return false;
- }
- ['uptime' => $uptime, 'error' => $error] = $server->validateConnection();
- if (! $uptime) {
- throw new \Exception($error);
- }
- if (! $server->isProxyShouldRun()) {
- if ($fromUI) {
- throw new \Exception('Proxy should not run. You selected the Custom Proxy.');
- } else {
- return false;
- }
- }
- if ($server->isSwarm()) {
- $status = getContainerStatus($server, 'coolify-proxy_traefik');
- $server->proxy->set('status', $status);
- $server->save();
- if ($status === 'running') {
- return false;
- }
-
- return true;
- } else {
- $status = getContainerStatus($server, 'coolify-proxy');
- if ($status === 'running') {
- $server->proxy->set('status', 'running');
- $server->save();
-
- return false;
- }
- if ($server->settings->is_cloudflare_tunnel) {
- return false;
- }
- $ip = $server->ip;
- if ($server->id === 0) {
- $ip = 'host.docker.internal';
- }
-
- $portsToCheck = ['80', '443'];
-
- try {
- if ($server->proxyType() !== ProxyTypes::NONE->value) {
- $proxyCompose = CheckConfiguration::run($server);
- if (isset($proxyCompose)) {
- $yaml = Yaml::parse($proxyCompose);
- $portsToCheck = [];
- if ($server->proxyType() === ProxyTypes::TRAEFIK->value) {
- $ports = data_get($yaml, 'services.traefik.ports');
- } elseif ($server->proxyType() === ProxyTypes::CADDY->value) {
- $ports = data_get($yaml, 'services.caddy.ports');
- }
- if (isset($ports)) {
- foreach ($ports as $port) {
- $portsToCheck[] = str($port)->before(':')->value();
- }
- }
- }
- } else {
- $portsToCheck = [];
- }
- } catch (\Exception $e) {
- Log::error('Error checking proxy: '.$e->getMessage());
- }
- if (count($portsToCheck) === 0) {
- return false;
- }
- foreach ($portsToCheck as $port) {
- $connection = @fsockopen($ip, $port);
- if (is_resource($connection) && fclose($connection)) {
- if ($fromUI) {
- throw new \Exception("Port $port is in use. You must stop the process using this port. Docs: https://coolify.io/docs Discord: https://coollabs.io/discord ");
- } else {
- return false;
- }
- }
- }
-
- return true;
- }
- }
-}
diff --git a/app/Actions/Proxy/SaveConfiguration.php b/app/Actions/Proxy/SaveConfiguration.php
deleted file mode 100644
index f2de2b3f5a..0000000000
--- a/app/Actions/Proxy/SaveConfiguration.php
+++ /dev/null
@@ -1,28 +0,0 @@
-proxyPath();
- $docker_compose_yml_base64 = base64_encode($proxy_settings);
-
- $server->proxy->last_saved_settings = str($docker_compose_yml_base64)->pipe('md5')->value;
- $server->save();
-
- return instant_remote_process([
- "mkdir -p $proxy_path",
- "echo '$docker_compose_yml_base64' | base64 -d | tee $proxy_path/docker-compose.yml > /dev/null",
- ], $server);
- }
-}
diff --git a/app/Actions/Proxy/StartProxy.php b/app/Actions/Proxy/StartProxy.php
deleted file mode 100644
index 1fff558618..0000000000
--- a/app/Actions/Proxy/StartProxy.php
+++ /dev/null
@@ -1,78 +0,0 @@
-proxyType();
- if ((is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop || $server->isBuildServer()) && $force === false) {
- return 'OK';
- }
- $commands = collect([]);
- $proxy_path = $server->proxyPath();
- $configuration = CheckConfiguration::run($server);
- if (! $configuration) {
- throw new \Exception('Configuration is not synced');
- }
- SaveConfiguration::run($server, $configuration);
- $docker_compose_yml_base64 = base64_encode($configuration);
- $server->proxy->last_applied_settings = str($docker_compose_yml_base64)->pipe('md5')->value();
- $server->save();
- if ($server->isSwarmManager()) {
- $commands = $commands->merge([
- "mkdir -p $proxy_path/dynamic",
- "cd $proxy_path",
- "echo 'Creating required Docker Compose file.'",
- "echo 'Starting coolify-proxy.'",
- 'docker stack deploy --detach=true -c docker-compose.yml coolify-proxy',
- "echo 'Successfully started coolify-proxy.'",
- ]);
- } else {
- if (isDev()) {
- if ($proxyType === ProxyTypes::CADDY->value) {
- $proxy_path = '/data/coolify/proxy/caddy';
- }
- }
- $caddyfile = 'import /dynamic/*.caddy';
- $commands = $commands->merge([
- "mkdir -p $proxy_path/dynamic",
- "cd $proxy_path",
- "echo '$caddyfile' > $proxy_path/dynamic/Caddyfile",
- "echo 'Creating required Docker Compose file.'",
- "echo 'Pulling docker image.'",
- 'docker compose pull',
- 'if docker ps -a --format "{{.Names}}" | grep -q "^coolify-proxy$"; then',
- " echo 'Stopping and removing existing coolify-proxy.'",
- ' docker rm -f coolify-proxy || true',
- " echo 'Successfully stopped and removed existing coolify-proxy.'",
- 'fi',
- "echo 'Starting coolify-proxy.'",
- 'docker compose up -d',
- "echo 'Successfully started coolify-proxy.'",
- ]);
- $commands = $commands->merge(connectProxyToNetworks($server));
- }
-
- if ($async) {
- return remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server);
- } else {
- instant_remote_process($commands, $server);
- $server->proxy->set('status', 'running');
- $server->proxy->set('type', $proxyType);
- $server->save();
- ProxyStarted::dispatch($server);
-
- return 'OK';
- }
- }
-}
diff --git a/app/Actions/Server/CleanupDocker.php b/app/Actions/Server/CleanupDocker.php
deleted file mode 100644
index ba4c2311ae..0000000000
--- a/app/Actions/Server/CleanupDocker.php
+++ /dev/null
@@ -1,49 +0,0 @@
-settings->delete_unused_volumes) {
- $commands[] = 'docker volume prune -af';
- }
-
- if ($server->settings->delete_unused_networks) {
- $commands[] = 'docker network prune -f';
- }
-
- $cleanupLog = [];
- foreach ($commands as $command) {
- $commandOutput = instant_remote_process([$command], $server, false);
- if ($commandOutput !== null) {
- $cleanupLog[] = [
- 'command' => $command,
- 'output' => $commandOutput,
- ];
- }
- }
-
- return $cleanupLog;
- }
-}
diff --git a/app/Actions/Server/ConfigureCloudflared.php b/app/Actions/Server/ConfigureCloudflared.php
deleted file mode 100644
index fc04e67a45..0000000000
--- a/app/Actions/Server/ConfigureCloudflared.php
+++ /dev/null
@@ -1,55 +0,0 @@
- [
- 'coolify-cloudflared' => [
- 'container_name' => 'coolify-cloudflared',
- 'image' => 'cloudflare/cloudflared:latest',
- 'restart' => RESTART_MODE,
- 'network_mode' => 'host',
- 'command' => 'tunnel run',
- 'environment' => [
- "TUNNEL_TOKEN={$cloudflare_token}",
- ],
- ],
- ],
- ];
- $config = Yaml::dump($config, 12, 2);
- $docker_compose_yml_base64 = base64_encode($config);
- $commands = collect([
- 'mkdir -p /tmp/cloudflared',
- 'cd /tmp/cloudflared',
- "echo '$docker_compose_yml_base64' | base64 -d | tee docker-compose.yml > /dev/null",
- 'docker compose pull',
- 'docker compose down -v --remove-orphans > /dev/null 2>&1',
- 'docker compose up -d --remove-orphans',
- ]);
- instant_remote_process($commands, $server);
- } catch (\Throwable $e) {
- $server->settings->is_cloudflare_tunnel = false;
- $server->settings->save();
- throw $e;
- } finally {
- CloudflareTunnelConfigured::dispatch($server->team_id);
-
- $commands = collect([
- 'rm -fr /tmp/cloudflared',
- ]);
- instant_remote_process($commands, $server);
- }
- }
-}
diff --git a/app/Actions/Server/DeleteServer.php b/app/Actions/Server/DeleteServer.php
deleted file mode 100644
index 15c892e755..0000000000
--- a/app/Actions/Server/DeleteServer.php
+++ /dev/null
@@ -1,17 +0,0 @@
-forceDelete();
- }
-}
diff --git a/app/Actions/Server/InstallDocker.php b/app/Actions/Server/InstallDocker.php
deleted file mode 100644
index cbcb20368c..0000000000
--- a/app/Actions/Server/InstallDocker.php
+++ /dev/null
@@ -1,109 +0,0 @@
-validateOS();
- if (! $supported_os_type) {
- throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: documentation .');
- }
- $config = base64_encode('{
- "log-driver": "json-file",
- "log-opts": {
- "max-size": "10m",
- "max-file": "3"
- }
- }');
- $found = StandaloneDocker::where('server_id', $server->id);
- if ($found->count() == 0 && $server->id) {
- StandaloneDocker::create([
- 'name' => 'coolify',
- 'network' => 'coolify',
- 'server_id' => $server->id,
- ]);
- }
- $command = collect([]);
- if (isDev() && $server->id === 0) {
- $command = $command->merge([
- "echo 'Installing Prerequisites...'",
- 'sleep 1',
- "echo 'Installing Docker Engine...'",
- "echo 'Configuring Docker Engine (merging existing configuration with the required)...'",
- 'sleep 4',
- "echo 'Restarting Docker Engine...'",
- 'ls -l /tmp',
- ]);
-
- return remote_process($command, $server);
- } else {
- if ($supported_os_type->contains('debian')) {
- $command = $command->merge([
- "echo 'Installing Prerequisites...'",
- 'apt-get update -y',
- 'command -v curl >/dev/null || apt install -y curl',
- 'command -v wget >/dev/null || apt install -y wget',
- 'command -v git >/dev/null || apt install -y git',
- 'command -v jq >/dev/null || apt install -y jq',
- ]);
- } elseif ($supported_os_type->contains('rhel')) {
- $command = $command->merge([
- "echo 'Installing Prerequisites...'",
- 'command -v curl >/dev/null || dnf install -y curl',
- 'command -v wget >/dev/null || dnf install -y wget',
- 'command -v git >/dev/null || dnf install -y git',
- 'command -v jq >/dev/null || dnf install -y jq',
- ]);
- } elseif ($supported_os_type->contains('sles')) {
- $command = $command->merge([
- "echo 'Installing Prerequisites...'",
- 'zypper update -y',
- 'command -v curl >/dev/null || zypper install -y curl',
- 'command -v wget >/dev/null || zypper install -y wget',
- 'command -v git >/dev/null || zypper install -y git',
- 'command -v jq >/dev/null || zypper install -y jq',
- ]);
- } else {
- throw new \Exception('Unsupported OS');
- }
- $command = $command->merge([
- "echo 'Installing Docker Engine...'",
- "curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh || curl https://get.docker.com | sh -s -- --version {$dockerVersion}",
- "echo 'Configuring Docker Engine (merging existing configuration with the required)...'",
- 'test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json "/etc/docker/daemon.json.original-$(date +"%Y%m%d-%H%M%S")"',
- "test ! -s /etc/docker/daemon.json && echo '{$config}' | base64 -d | tee /etc/docker/daemon.json > /dev/null",
- "echo '{$config}' | base64 -d | tee /etc/docker/daemon.json.coolify > /dev/null",
- 'jq . /etc/docker/daemon.json.coolify | tee /etc/docker/daemon.json.coolify.pretty > /dev/null',
- 'mv /etc/docker/daemon.json.coolify.pretty /etc/docker/daemon.json.coolify',
- "jq -s '.[0] * .[1]' /etc/docker/daemon.json.coolify /etc/docker/daemon.json | tee /etc/docker/daemon.json.appended > /dev/null",
- 'mv /etc/docker/daemon.json.appended /etc/docker/daemon.json',
- "echo 'Restarting Docker Engine...'",
- 'systemctl enable docker >/dev/null 2>&1 || true',
- 'systemctl restart docker',
- ]);
- if ($server->isSwarm()) {
- $command = $command->merge([
- 'docker network create --attachable --driver overlay coolify-overlay >/dev/null 2>&1 || true',
- ]);
- } else {
- $command = $command->merge([
- 'docker network create --attachable coolify >/dev/null 2>&1 || true',
- ]);
- $command = $command->merge([
- "echo 'Done!'",
- ]);
- }
-
- return remote_process($command, $server);
- }
- }
-}
diff --git a/app/Actions/Server/ResourcesCheck.php b/app/Actions/Server/ResourcesCheck.php
deleted file mode 100644
index e6b90ba380..0000000000
--- a/app/Actions/Server/ResourcesCheck.php
+++ /dev/null
@@ -1,41 +0,0 @@
-subSeconds($seconds))->update(['status' => 'exited']);
- ServiceApplication::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
- ServiceDatabase::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
- StandalonePostgresql::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
- StandaloneRedis::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
- StandaloneMongodb::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
- StandaloneMysql::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
- StandaloneMariadb::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
- StandaloneKeydb::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
- StandaloneDragonfly::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
- StandaloneClickhouse::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
- } catch (\Throwable $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Actions/Server/RestartContainer.php b/app/Actions/Server/RestartContainer.php
deleted file mode 100644
index 63361d8b71..0000000000
--- a/app/Actions/Server/RestartContainer.php
+++ /dev/null
@@ -1,16 +0,0 @@
-restartContainer($containerName);
- }
-}
diff --git a/app/Actions/Server/RunCommand.php b/app/Actions/Server/RunCommand.php
deleted file mode 100644
index 254c78587c..0000000000
--- a/app/Actions/Server/RunCommand.php
+++ /dev/null
@@ -1,17 +0,0 @@
-value);
- }
-}
diff --git a/app/Actions/Server/ServerCheck.php b/app/Actions/Server/ServerCheck.php
deleted file mode 100644
index 75b8501f32..0000000000
--- a/app/Actions/Server/ServerCheck.php
+++ /dev/null
@@ -1,267 +0,0 @@
-server = $server;
- try {
- if ($this->server->isFunctional() === false) {
- return 'Server is not functional.';
- }
-
- if (! $this->server->isSwarmWorker() && ! $this->server->isBuildServer()) {
-
- if (isset($data)) {
- $data = collect($data);
-
- $this->server->sentinelHeartbeat();
-
- $this->containers = collect(data_get($data, 'containers'));
-
- $filesystemUsageRoot = data_get($data, 'filesystem_usage_root.used_percentage');
- ServerStorageCheckJob::dispatch($this->server, $filesystemUsageRoot);
-
- $containerReplicates = null;
- $this->isSentinel = true;
- } else {
- ['containers' => $this->containers, 'containerReplicates' => $containerReplicates] = $this->server->getContainers();
- // ServerStorageCheckJob::dispatch($this->server);
- }
-
- if (is_null($this->containers)) {
- return 'No containers found.';
- }
-
- if (isset($containerReplicates)) {
- foreach ($containerReplicates as $containerReplica) {
- $name = data_get($containerReplica, 'Name');
- $this->containers = $this->containers->map(function ($container) use ($name, $containerReplica) {
- if (data_get($container, 'Spec.Name') === $name) {
- $replicas = data_get($containerReplica, 'Replicas');
- $running = str($replicas)->explode('/')[0];
- $total = str($replicas)->explode('/')[1];
- if ($running === $total) {
- data_set($container, 'State.Status', 'running');
- data_set($container, 'State.Health.Status', 'healthy');
- } else {
- data_set($container, 'State.Status', 'starting');
- data_set($container, 'State.Health.Status', 'unhealthy');
- }
- }
-
- return $container;
- });
- }
- }
- $this->checkContainers();
-
- if ($this->server->isSentinelEnabled() && $this->isSentinel === false) {
- CheckAndStartSentinelJob::dispatch($this->server);
- }
-
- if ($this->server->isLogDrainEnabled()) {
- $this->checkLogDrainContainer();
- }
-
- if ($this->server->proxySet() && ! $this->server->proxy->force_stop) {
- $foundProxyContainer = $this->containers->filter(function ($value, $key) {
- if ($this->server->isSwarm()) {
- return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik';
- } else {
- return data_get($value, 'Name') === '/coolify-proxy';
- }
- })->first();
- if (! $foundProxyContainer) {
- try {
- $shouldStart = CheckProxy::run($this->server);
- if ($shouldStart) {
- StartProxy::run($this->server, false);
- $this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server));
- }
- } catch (\Throwable $e) {
- }
- } else {
- $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status');
- $this->server->save();
- $connectProxyToDockerNetworks = connectProxyToNetworks($this->server);
- instant_remote_process($connectProxyToDockerNetworks, $this->server, false);
- }
- }
- }
- } catch (\Throwable $e) {
- return handleError($e);
- }
- }
-
- private function checkLogDrainContainer()
- {
- $foundLogDrainContainer = $this->containers->filter(function ($value, $key) {
- return data_get($value, 'Name') === '/coolify-log-drain';
- })->first();
- if ($foundLogDrainContainer) {
- $status = data_get($foundLogDrainContainer, 'State.Status');
- if ($status !== 'running') {
- StartLogDrain::dispatch($this->server);
- }
- } else {
- StartLogDrain::dispatch($this->server);
- }
- }
-
- private function checkContainers()
- {
- foreach ($this->containers as $container) {
- if ($this->isSentinel) {
- $labels = Arr::undot(data_get($container, 'labels'));
- } else {
- if ($this->server->isSwarm()) {
- $labels = Arr::undot(data_get($container, 'Spec.Labels'));
- } else {
- $labels = Arr::undot(data_get($container, 'Config.Labels'));
- }
- }
- $managed = data_get($labels, 'coolify.managed');
- if (! $managed) {
- continue;
- }
- $uuid = data_get($labels, 'coolify.name');
- if (! $uuid) {
- $uuid = data_get($labels, 'com.docker.compose.service');
- }
-
- if ($this->isSentinel) {
- $containerStatus = data_get($container, 'state');
- $containerHealth = data_get($container, 'health_status');
- } else {
- $containerStatus = data_get($container, 'State.Status');
- $containerHealth = data_get($container, 'State.Health.Status', 'unhealthy');
- }
- $containerStatus = "$containerStatus ($containerHealth)";
-
- $applicationId = data_get($labels, 'coolify.applicationId');
- $serviceId = data_get($labels, 'coolify.serviceId');
- $databaseId = data_get($labels, 'coolify.databaseId');
- $pullRequestId = data_get($labels, 'coolify.pullRequestId');
-
- if ($applicationId) {
- // Application
- if ($pullRequestId != 0) {
- if (str($applicationId)->contains('-')) {
- $applicationId = str($applicationId)->before('-');
- }
- $preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first();
- if ($preview) {
- $preview->update(['status' => $containerStatus]);
- }
- } else {
- $application = Application::where('id', $applicationId)->first();
- if ($application) {
- $application->update([
- 'status' => $containerStatus,
- 'last_online_at' => now(),
- ]);
- }
- }
- } elseif (isset($serviceId)) {
- // Service
- $subType = data_get($labels, 'coolify.service.subType');
- $subId = data_get($labels, 'coolify.service.subId');
- $service = Service::where('id', $serviceId)->first();
- if (! $service) {
- continue;
- }
- if ($subType === 'application') {
- $service = ServiceApplication::where('id', $subId)->first();
- } else {
- $service = ServiceDatabase::where('id', $subId)->first();
- }
- if ($service) {
- $service->update([
- 'status' => $containerStatus,
- 'last_online_at' => now(),
- ]);
- if ($subType === 'database') {
- $isPublic = data_get($service, 'is_public');
- if ($isPublic) {
- $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
- if ($this->isSentinel) {
- return data_get($value, 'name') === $uuid.'-proxy';
- } else {
-
- if ($this->server->isSwarm()) {
- return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
- } else {
- return data_get($value, 'Name') === "/$uuid-proxy";
- }
- }
- })->first();
- if (! $foundTcpProxy) {
- StartDatabaseProxy::run($service);
- }
- }
- }
- }
- } else {
- // Database
- if (is_null($this->databases)) {
- $this->databases = $this->server->databases();
- }
- $database = $this->databases->where('uuid', $uuid)->first();
- if ($database) {
- $database->update([
- 'status' => $containerStatus,
- 'last_online_at' => now(),
- ]);
-
- $isPublic = data_get($database, 'is_public');
- if ($isPublic) {
- $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
- if ($this->isSentinel) {
- return data_get($value, 'name') === $uuid.'-proxy';
- } else {
- if ($this->server->isSwarm()) {
- return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
- } else {
-
- return data_get($value, 'Name') === "/$uuid-proxy";
- }
- }
- })->first();
- if (! $foundTcpProxy) {
- StartDatabaseProxy::run($database);
- // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for database", $this->server));
- }
- }
- }
- }
- }
- }
-}
diff --git a/app/Actions/Server/StartLogDrain.php b/app/Actions/Server/StartLogDrain.php
deleted file mode 100644
index 0d28a00994..0000000000
--- a/app/Actions/Server/StartLogDrain.php
+++ /dev/null
@@ -1,223 +0,0 @@
-settings->is_logdrain_newrelic_enabled) {
- $type = 'newrelic';
- StopLogDrain::run($server);
- } elseif ($server->settings->is_logdrain_highlight_enabled) {
- $type = 'highlight';
- StopLogDrain::run($server);
- } elseif ($server->settings->is_logdrain_axiom_enabled) {
- $type = 'axiom';
- StopLogDrain::run($server);
- } elseif ($server->settings->is_logdrain_custom_enabled) {
- $type = 'custom';
- StopLogDrain::run($server);
- } else {
- $type = 'none';
- }
- try {
- if ($type === 'none') {
- return 'No log drain is enabled.';
- } elseif ($type === 'newrelic') {
- if (! $server->settings->is_logdrain_newrelic_enabled) {
- throw new \Exception('New Relic log drain is not enabled.');
- }
- $config = base64_encode("
-[SERVICE]
- Flush 5
- Daemon off
- Tag container_logs
- Log_Level debug
- Parsers_File parsers.conf
-[INPUT]
- Name forward
- Buffer_Chunk_Size 1M
- Buffer_Max_Size 6M
-[FILTER]
- Name grep
- Match *
- Exclude log 127.0.0.1
-[FILTER]
- Name modify
- Match *
- Set coolify.server_name {$server->name}
- Rename COOLIFY_APP_NAME coolify.app_name
- Rename COOLIFY_PROJECT_NAME coolify.project_name
- Rename COOLIFY_SERVER_IP coolify.server_ip
- Rename COOLIFY_ENVIRONMENT_NAME coolify.environment_name
-[OUTPUT]
- Name nrlogs
- Match *
- license_key \${LICENSE_KEY}
- # https://log-api.eu.newrelic.com/log/v1 - EU
- # https://log-api.newrelic.com/log/v1 - US
- base_uri \${BASE_URI}
-");
- } elseif ($type === 'highlight') {
- if (! $server->settings->is_logdrain_highlight_enabled) {
- throw new \Exception('Highlight log drain is not enabled.');
- }
- $config = base64_encode('
-[SERVICE]
- Flush 5
- Daemon off
- Log_Level debug
- Parsers_File parsers.conf
-[INPUT]
- Name forward
- tag ${HIGHLIGHT_PROJECT_ID}
- Buffer_Chunk_Size 1M
- Buffer_Max_Size 6M
-[OUTPUT]
- Name forward
- Match *
- Host otel.highlight.io
- Port 24224
-');
- } elseif ($type === 'axiom') {
- if (! $server->settings->is_logdrain_axiom_enabled) {
- throw new \Exception('Axiom log drain is not enabled.');
- }
- $config = base64_encode("
-[SERVICE]
- Flush 5
- Daemon off
- Log_Level debug
- Parsers_File parsers.conf
-[INPUT]
- Name forward
- Buffer_Chunk_Size 1M
- Buffer_Max_Size 6M
-[FILTER]
- Name grep
- Match *
- Exclude log 127.0.0.1
-[FILTER]
- Name modify
- Match *
- Set coolify.server_name {$server->name}
- Rename COOLIFY_APP_NAME coolify.app_name
- Rename COOLIFY_PROJECT_NAME coolify.project_name
- Rename COOLIFY_SERVER_IP coolify.server_ip
- Rename COOLIFY_ENVIRONMENT_NAME coolify.environment_name
-[OUTPUT]
- Name http
- Match *
- Host api.axiom.co
- Port 443
- URI /v1/datasets/\${AXIOM_DATASET_NAME}/ingest
- # Authorization Bearer should be an API token
- Header Authorization Bearer \${AXIOM_API_KEY}
- compress gzip
- format json
- json_date_key _time
- json_date_format iso8601
- tls On
-");
- } elseif ($type === 'custom') {
- if (! $server->settings->is_logdrain_custom_enabled) {
- throw new \Exception('Custom log drain is not enabled.');
- }
- $config = base64_encode($server->settings->logdrain_custom_config);
- $parsers = base64_encode($server->settings->logdrain_custom_config_parser);
- } else {
- throw new \Exception('Unknown log drain type.');
- }
- if ($type !== 'custom') {
- $parsers = base64_encode("
-[PARSER]
- Name empty_line_skipper
- Format regex
- Regex /^(?!\s*$).+/
-");
- }
- $compose = base64_encode('
-services:
- coolify-log-drain:
- image: cr.fluentbit.io/fluent/fluent-bit:2.0
- container_name: coolify-log-drain
- command: -c /fluent-bit.conf
- env_file:
- - .env
- volumes:
- - ./fluent-bit.conf:/fluent-bit.conf
- - ./parsers.conf:/parsers.conf
- ports:
- - 127.0.0.1:24224:24224
- labels:
- - coolify.managed=true
- restart: unless-stopped
-');
- $readme = base64_encode('# New Relic Log Drain
-This log drain is based on [Fluent Bit](https://fluentbit.io/) and New Relic Log Forwarder.
-
-Files:
-- `fluent-bit.conf` - configuration file for Fluent Bit
-- `docker-compose.yml` - docker-compose file to run Fluent Bit
-- `.env` - environment variables for Fluent Bit
-');
- $license_key = $server->settings->logdrain_newrelic_license_key;
- $base_uri = $server->settings->logdrain_newrelic_base_uri;
- $base_path = config('constants.coolify.base_config_path');
-
- $config_path = $base_path.'/log-drains';
- $fluent_bit_config = $config_path.'/fluent-bit.conf';
- $parsers_config = $config_path.'/parsers.conf';
- $compose_path = $config_path.'/docker-compose.yml';
- $readme_path = $config_path.'/README.md';
- $command = [
- "echo 'Saving configuration'",
- "mkdir -p $config_path",
- "echo '{$parsers}' | base64 -d | tee $parsers_config > /dev/null",
- "echo '{$config}' | base64 -d | tee $fluent_bit_config > /dev/null",
- "echo '{$compose}' | base64 -d | tee $compose_path > /dev/null",
- "echo '{$readme}' | base64 -d | tee $readme_path > /dev/null",
- "test -f $config_path/.env && rm $config_path/.env",
-
- ];
- if ($type === 'newrelic') {
- $add_envs_command = [
- "echo LICENSE_KEY=$license_key >> $config_path/.env",
- "echo BASE_URI=$base_uri >> $config_path/.env",
- ];
- } elseif ($type === 'highlight') {
- $add_envs_command = [
- "echo HIGHLIGHT_PROJECT_ID={$server->settings->logdrain_highlight_project_id} >> $config_path/.env",
- ];
- } elseif ($type === 'axiom') {
- $add_envs_command = [
- "echo AXIOM_DATASET_NAME={$server->settings->logdrain_axiom_dataset_name} >> $config_path/.env",
- "echo AXIOM_API_KEY={$server->settings->logdrain_axiom_api_key} >> $config_path/.env",
- ];
- } elseif ($type === 'custom') {
- $add_envs_command = [
- "touch $config_path/.env",
- ];
- } else {
- throw new \Exception('Unknown log drain type.');
- }
- $restart_command = [
- "echo 'Starting Fluent Bit'",
- "cd $config_path && docker compose up -d",
- ];
- $command = array_merge($command, $add_envs_command, $restart_command);
-
- return instant_remote_process($command, $server);
- } catch (\Throwable $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Actions/Server/StartSentinel.php b/app/Actions/Server/StartSentinel.php
deleted file mode 100644
index 587ac4a8db..0000000000
--- a/app/Actions/Server/StartSentinel.php
+++ /dev/null
@@ -1,65 +0,0 @@
-isSwarm() || $server->isBuildServer()) {
- return;
- }
- if ($restart) {
- StopSentinel::run($server);
- }
- $version = $latestVersion ?? get_latest_sentinel_version();
- $metricsHistory = data_get($server, 'settings.sentinel_metrics_history_days');
- $refreshRate = data_get($server, 'settings.sentinel_metrics_refresh_rate_seconds');
- $pushInterval = data_get($server, 'settings.sentinel_push_interval_seconds');
- $token = data_get($server, 'settings.sentinel_token');
- $endpoint = data_get($server, 'settings.sentinel_custom_url');
- $debug = data_get($server, 'settings.is_sentinel_debug_enabled');
- $mountDir = '/data/coolify/sentinel';
- $image = "ghcr.io/coollabsio/sentinel:$version";
- if (! $endpoint) {
- throw new \Exception('You should set FQDN in Instance Settings.');
- }
- $environments = [
- 'TOKEN' => $token,
- 'DEBUG' => $debug ? 'true' : 'false',
- 'PUSH_ENDPOINT' => $endpoint,
- 'PUSH_INTERVAL_SECONDS' => $pushInterval,
- 'COLLECTOR_ENABLED' => $server->isMetricsEnabled() ? 'true' : 'false',
- 'COLLECTOR_REFRESH_RATE_SECONDS' => $refreshRate,
- 'COLLECTOR_RETENTION_PERIOD_DAYS' => $metricsHistory,
- ];
- $labels = [
- 'coolify.managed' => 'true',
- ];
- if (isDev()) {
- // data_set($environments, 'DEBUG', 'true');
- // $image = 'sentinel';
- $mountDir = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/sentinel';
- }
- $dockerEnvironments = '-e "'.implode('" -e "', array_map(fn ($key, $value) => "$key=$value", array_keys($environments), $environments)).'"';
- $dockerLabels = implode(' ', array_map(fn ($key, $value) => "$key=$value", array_keys($labels), $labels));
- $dockerCommand = "docker run -d $dockerEnvironments --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v $mountDir:/app/db --pid host --health-cmd \"curl --fail http://127.0.0.1:8888/api/health || exit 1\" --health-interval 10s --health-retries 3 --add-host=host.docker.internal:host-gateway --label $dockerLabels $image";
-
- instant_remote_process([
- 'docker rm -f coolify-sentinel || true',
- "mkdir -p $mountDir",
- $dockerCommand,
- "chown -R 9999:root $mountDir",
- "chmod -R 700 $mountDir",
- ], $server);
-
- $server->settings->is_sentinel_enabled = true;
- $server->settings->save();
- $server->sentinelHeartbeat();
- }
-}
diff --git a/app/Actions/Server/StopLogDrain.php b/app/Actions/Server/StopLogDrain.php
deleted file mode 100644
index 96c2466dec..0000000000
--- a/app/Actions/Server/StopLogDrain.php
+++ /dev/null
@@ -1,20 +0,0 @@
-sentinelHeartbeat(isReset: true);
- }
-}
diff --git a/app/Actions/Server/UpdateCoolify.php b/app/Actions/Server/UpdateCoolify.php
deleted file mode 100644
index be9b4062c9..0000000000
--- a/app/Actions/Server/UpdateCoolify.php
+++ /dev/null
@@ -1,62 +0,0 @@
-seconds();
-
- return;
- }
- $settings = instanceSettings();
- $this->server = Server::find(0);
- if (! $this->server) {
- return;
- }
- CleanupDocker::dispatch($this->server);
- $this->latestVersion = get_latest_version_of_coolify();
- $this->currentVersion = config('constants.coolify.version');
- if (! $manual_update) {
- if (! $settings->is_auto_update_enabled) {
- return;
- }
- if ($this->latestVersion === $this->currentVersion) {
- return;
- }
- if (version_compare($this->latestVersion, $this->currentVersion, '<')) {
- return;
- }
- }
- $this->update();
- $settings->new_version_available = false;
- $settings->save();
- }
-
- private function update()
- {
- PullHelperImageJob::dispatch($this->server);
-
- instant_remote_process(["docker pull -q ghcr.io/coollabsio/coolify:{$this->latestVersion}"], $this->server, false);
-
- remote_process([
- 'curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh',
- "bash /data/coolify/source/upgrade.sh $this->latestVersion",
- ], $this->server);
- }
-}
diff --git a/app/Actions/Server/ValidateServer.php b/app/Actions/Server/ValidateServer.php
deleted file mode 100644
index 55b37a77c0..0000000000
--- a/app/Actions/Server/ValidateServer.php
+++ /dev/null
@@ -1,69 +0,0 @@
-update([
- 'validation_logs' => null,
- ]);
- ['uptime' => $this->uptime, 'error' => $error] = $server->validateConnection();
- if (! $this->uptime) {
- $this->error = 'Server is not reachable. Please validate your configuration and connection. Check this documentation for further help. Error: '.$error.'
';
- $server->update([
- 'validation_logs' => $this->error,
- ]);
- throw new \Exception($this->error);
- }
- $this->supported_os_type = $server->validateOS();
- if (! $this->supported_os_type) {
- $this->error = 'Server OS type is not supported. Please install Docker manually before continuing: documentation .';
- $server->update([
- 'validation_logs' => $this->error,
- ]);
- throw new \Exception($this->error);
- }
-
- $this->docker_installed = $server->validateDockerEngine();
- $this->docker_compose_installed = $server->validateDockerCompose();
- if (! $this->docker_installed || ! $this->docker_compose_installed) {
- $this->error = 'Docker Engine is not installed. Please install Docker manually before continuing: documentation .';
- $server->update([
- 'validation_logs' => $this->error,
- ]);
- throw new \Exception($this->error);
- }
- $this->docker_version = $server->validateDockerEngineVersion();
-
- if ($this->docker_version) {
- return 'OK';
- } else {
- $this->error = 'Docker Engine is not installed. Please install Docker manually before continuing: documentation .';
- $server->update([
- 'validation_logs' => $this->error,
- ]);
- throw new \Exception($this->error);
- }
- }
-}
diff --git a/app/Actions/Service/DeleteService.php b/app/Actions/Service/DeleteService.php
deleted file mode 100644
index 9b87454dac..0000000000
--- a/app/Actions/Service/DeleteService.php
+++ /dev/null
@@ -1,78 +0,0 @@
-isFunctional()) {
- $storagesToDelete = collect([]);
-
- $service->environment_variables()->delete();
- $commands = [];
- foreach ($service->applications()->get() as $application) {
- $storages = $application->persistentStorages()->get();
- foreach ($storages as $storage) {
- $storagesToDelete->push($storage);
- }
- }
- foreach ($service->databases()->get() as $database) {
- $storages = $database->persistentStorages()->get();
- foreach ($storages as $storage) {
- $storagesToDelete->push($storage);
- }
- }
- foreach ($storagesToDelete as $storage) {
- $commands[] = "docker volume rm -f $storage->name";
- }
-
- // Execute volume deletion first, this must be done first otherwise volumes will not be deleted.
- if (! empty($commands)) {
- foreach ($commands as $command) {
- $result = instant_remote_process([$command], $server, false);
- if ($result !== null && $result !== 0) {
- Log::error('Error deleting volumes: '.$result);
- }
- }
- }
- }
-
- if ($deleteConnectedNetworks) {
- $service->delete_connected_networks($service->uuid);
- }
-
- instant_remote_process(["docker rm -f $service->uuid"], $server, throwError: false);
- } catch (\Exception $e) {
- throw new \Exception($e->getMessage());
- } finally {
- if ($deleteConfigurations) {
- $service->delete_configurations();
- }
- foreach ($service->applications()->get() as $application) {
- $application->forceDelete();
- }
- foreach ($service->databases()->get() as $database) {
- $database->forceDelete();
- }
- foreach ($service->scheduled_tasks as $task) {
- $task->delete();
- }
- $service->tags()->detach();
- $service->forceDelete();
-
- if ($dockerCleanup) {
- CleanupDocker::dispatch($server, true);
- }
- }
- }
-}
diff --git a/app/Actions/Service/RestartService.php b/app/Actions/Service/RestartService.php
deleted file mode 100644
index 4151ea9474..0000000000
--- a/app/Actions/Service/RestartService.php
+++ /dev/null
@@ -1,20 +0,0 @@
-parse();
- if ($stopBeforeStart) {
- StopService::run(service: $service, dockerCleanup: false);
- }
- $service->saveComposeConfigs();
- $commands[] = 'cd '.$service->workdir();
- $commands[] = "echo 'Saved configuration files to {$service->workdir()}.'";
- if ($pullLatestImages) {
- $commands[] = "echo 'Pulling images.'";
- $commands[] = 'docker compose pull';
- }
- if ($service->networks()->count() > 0) {
- $commands[] = "echo 'Creating Docker network.'";
- $commands[] = "docker network inspect $service->uuid >/dev/null 2>&1 || docker network create --attachable $service->uuid";
- }
- $commands[] = 'echo Starting service.';
- $commands[] = 'docker compose up -d --remove-orphans --force-recreate --build';
- $commands[] = "docker network connect $service->uuid coolify-proxy >/dev/null 2>&1 || true";
- if (data_get($service, 'connect_to_docker_network')) {
- $compose = data_get($service, 'docker_compose', []);
- $network = $service->destination->network;
- $serviceNames = data_get(Yaml::parse($compose), 'services', []);
- foreach ($serviceNames as $serviceName => $serviceConfig) {
- $commands[] = "docker network connect --alias {$serviceName}-{$service->uuid} $network {$serviceName}-{$service->uuid} >/dev/null 2>&1 || true";
- }
- }
-
- return remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged');
- }
-}
diff --git a/app/Actions/Service/StopService.php b/app/Actions/Service/StopService.php
deleted file mode 100644
index 95b08b4370..0000000000
--- a/app/Actions/Service/StopService.php
+++ /dev/null
@@ -1,36 +0,0 @@
-destination->server;
- if (! $server->isFunctional()) {
- return 'Server is not functional';
- }
-
- $containersToStop = $service->getContainersToStop();
- $service->stopContainers($containersToStop, $server);
-
- if (! $isDeleteOperation) {
- $service->delete_connected_networks($service->uuid);
- if ($dockerCleanup) {
- CleanupDocker::dispatch($server, true);
- }
- }
- } catch (\Exception $e) {
- return $e->getMessage();
- }
- }
-}
diff --git a/app/Actions/Shared/ComplexStatusCheck.php b/app/Actions/Shared/ComplexStatusCheck.php
deleted file mode 100644
index 5a7ba6637c..0000000000
--- a/app/Actions/Shared/ComplexStatusCheck.php
+++ /dev/null
@@ -1,60 +0,0 @@
-additional_servers;
- $servers->push($application->destination->server);
- foreach ($servers as $server) {
- $is_main_server = $application->destination->server->id === $server->id;
- if (! $server->isFunctional()) {
- if ($is_main_server) {
- $application->update(['status' => 'exited:unhealthy']);
-
- continue;
- } else {
- $application->additional_servers()->updateExistingPivot($server->id, ['status' => 'exited:unhealthy']);
-
- continue;
- }
- }
- $container = instant_remote_process(["docker container inspect $(docker container ls -q --filter 'label=coolify.applicationId={$application->id}' --filter 'label=coolify.pullRequestId=0') --format '{{json .}}'"], $server, false);
- $container = format_docker_command_output_to_json($container);
- if ($container->count() === 1) {
- $container = $container->first();
- $containerStatus = data_get($container, 'State.Status');
- $containerHealth = data_get($container, 'State.Health.Status', 'unhealthy');
- if ($is_main_server) {
- $statusFromDb = $application->status;
- if ($statusFromDb !== $containerStatus) {
- $application->update(['status' => "$containerStatus:$containerHealth"]);
- }
- } else {
- $additional_server = $application->additional_servers()->wherePivot('server_id', $server->id);
- $statusFromDb = $additional_server->first()->pivot->status;
- if ($statusFromDb !== $containerStatus) {
- $additional_server->updateExistingPivot($server->id, ['status' => "$containerStatus:$containerHealth"]);
- }
- }
- } else {
- if ($is_main_server) {
- $application->update(['status' => 'exited:unhealthy']);
-
- continue;
- } else {
- $application->additional_servers()->updateExistingPivot($server->id, ['status' => 'exited:unhealthy']);
-
- continue;
- }
- }
- }
- }
-}
diff --git a/app/Console/Commands/AdminRemoveUser.php b/app/Console/Commands/AdminRemoveUser.php
deleted file mode 100644
index d4534399cd..0000000000
--- a/app/Console/Commands/AdminRemoveUser.php
+++ /dev/null
@@ -1,56 +0,0 @@
-argument('email');
- $confirm = $this->confirm('Are you sure you want to remove user with email: '.$email.'?');
- if (! $confirm) {
- $this->info('User removal cancelled.');
-
- return;
- }
- $this->info("Removing user with email: $email");
- $user = User::whereEmail($email)->firstOrFail();
- $teams = $user->teams;
- foreach ($teams as $team) {
- if ($team->members->count() > 1) {
- $this->error('User is a member of a team with more than one member. Please remove user from team first.');
-
- return;
- }
- $team->delete();
- }
- $user->delete();
- } catch (\Exception $e) {
- $this->error('Failed to remove user.');
- $this->error($e->getMessage());
-
- return;
- }
- }
-}
diff --git a/app/Console/Commands/CheckApplicationDeploymentQueue.php b/app/Console/Commands/CheckApplicationDeploymentQueue.php
deleted file mode 100644
index e89d26f2c3..0000000000
--- a/app/Console/Commands/CheckApplicationDeploymentQueue.php
+++ /dev/null
@@ -1,50 +0,0 @@
-option('seconds');
- $deployments = ApplicationDeploymentQueue::whereIn('status', [
- ApplicationDeploymentStatus::IN_PROGRESS,
- ApplicationDeploymentStatus::QUEUED,
- ])->where('created_at', '<=', now()->subSeconds($seconds))->get();
- if ($deployments->isEmpty()) {
- $this->info('No deployments found in the last '.$seconds.' seconds.');
-
- return;
- }
-
- $this->info('Found '.$deployments->count().' deployments created in the last '.$seconds.' seconds.');
-
- foreach ($deployments as $deployment) {
- if ($this->option('force')) {
- $this->info('Deployment '.$deployment->id.' created at '.$deployment->created_at.' is older than '.$seconds.' seconds. Setting status to failed.');
- $this->cancelDeployment($deployment);
- } else {
- $this->info('Deployment '.$deployment->id.' created at '.$deployment->created_at.' is older than '.$seconds.' seconds. Setting status to failed.');
- if ($this->confirm('Do you want to cancel this deployment?', true)) {
- $this->cancelDeployment($deployment);
- }
- }
- }
- }
-
- private function cancelDeployment(ApplicationDeploymentQueue $deployment)
- {
- $deployment->update(['status' => ApplicationDeploymentStatus::FAILED]);
- if ($deployment->server?->isFunctional()) {
- remote_process(['docker rm -f '.$deployment->deployment_uuid], $deployment->server, false);
- }
- }
-}
diff --git a/app/Console/Commands/CleanupApplicationDeploymentQueue.php b/app/Console/Commands/CleanupApplicationDeploymentQueue.php
deleted file mode 100644
index 3aae28ae60..0000000000
--- a/app/Console/Commands/CleanupApplicationDeploymentQueue.php
+++ /dev/null
@@ -1,26 +0,0 @@
-option('team-id');
- $servers = \App\Models\Server::where('team_id', $team_id)->get();
- foreach ($servers as $server) {
- $deployments = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->where('server_id', $server->id)->get();
- foreach ($deployments as $deployment) {
- $deployment->update(['status' => 'failed']);
- instant_remote_process(['docker rm -f '.$deployment->deployment_uuid], $server, false);
- }
- }
- }
-}
diff --git a/app/Console/Commands/CleanupDatabase.php b/app/Console/Commands/CleanupDatabase.php
deleted file mode 100644
index 2ccb76529d..0000000000
--- a/app/Console/Commands/CleanupDatabase.php
+++ /dev/null
@@ -1,76 +0,0 @@
-option('yes')) {
- echo "Running database cleanup...\n";
- } else {
- echo "Running database cleanup in dry-run mode...\n";
- }
- if (isCloud()) {
- // Later on we can increase this to 180 days or dynamically set
- $keep_days = $this->option('keep-days') ?? 60;
- } else {
- $keep_days = $this->option('keep-days') ?? 60;
- }
- echo "Keep days: $keep_days\n";
- // Cleanup failed jobs table
- $failed_jobs = DB::table('failed_jobs')->where('failed_at', '<', now()->subDays(1));
- $count = $failed_jobs->count();
- echo "Delete $count entries from failed_jobs.\n";
- if ($this->option('yes')) {
- $failed_jobs->delete();
- }
-
- // Cleanup sessions table
- $sessions = DB::table('sessions')->where('last_activity', '<', now()->subDays($keep_days)->timestamp);
- $count = $sessions->count();
- echo "Delete $count entries from sessions.\n";
- if ($this->option('yes')) {
- $sessions->delete();
- }
-
- // Cleanup activity_log table
- $activity_log = DB::table('activity_log')->where('created_at', '<', now()->subDays($keep_days))->orderBy('created_at', 'desc')->skip(10);
- $count = $activity_log->count();
- echo "Delete $count entries from activity_log.\n";
- if ($this->option('yes')) {
- $activity_log->delete();
- }
-
- // Cleanup application_deployment_queues table
- $application_deployment_queues = DB::table('application_deployment_queues')->where('created_at', '<', now()->subDays($keep_days))->orderBy('created_at', 'desc')->skip(10);
- $count = $application_deployment_queues->count();
- echo "Delete $count entries from application_deployment_queues.\n";
- if ($this->option('yes')) {
- $application_deployment_queues->delete();
- }
-
- // Cleanup scheduled_task_executions table
- $scheduled_task_executions = DB::table('scheduled_task_executions')->where('created_at', '<', now()->subDays($keep_days))->orderBy('created_at', 'desc');
- $count = $scheduled_task_executions->count();
- echo "Delete $count entries from scheduled_task_executions.\n";
- if ($this->option('yes')) {
- $scheduled_task_executions->delete();
- }
-
- // Cleanup webhooks table
- $webhooks = DB::table('webhooks')->where('created_at', '<', now()->subDays($keep_days));
- $count = $webhooks->count();
- echo "Delete $count entries from webhooks.\n";
- if ($this->option('yes')) {
- $webhooks->delete();
- }
- }
-}
diff --git a/app/Console/Commands/CleanupRedis.php b/app/Console/Commands/CleanupRedis.php
deleted file mode 100644
index e16a82be4c..0000000000
--- a/app/Console/Commands/CleanupRedis.php
+++ /dev/null
@@ -1,29 +0,0 @@
-keys('*:laravel*');
- collect($keys)->each(function ($key) use ($prefix) {
- $keyWithoutPrefix = str_replace($prefix, '', $key);
- Redis::connection()->del($keyWithoutPrefix);
- });
-
- $queueOverlaps = Redis::connection()->keys('*laravel-queue-overlap*');
- collect($queueOverlaps)->each(function ($key) {
- Redis::connection()->del($key);
- });
- }
-}
diff --git a/app/Console/Commands/CleanupStuckedResources.php b/app/Console/Commands/CleanupStuckedResources.php
deleted file mode 100644
index 0b5eef84d5..0000000000
--- a/app/Console/Commands/CleanupStuckedResources.php
+++ /dev/null
@@ -1,414 +0,0 @@
-cleanup_stucked_resources();
- }
-
- private function cleanup_stucked_resources()
- {
- try {
- $servers = Server::all()->filter(function ($server) {
- return $server->isFunctional();
- });
- if (isCloud()) {
- $servers = $servers->filter(function ($server) {
- return data_get($server->team->subscription, 'stripe_invoice_paid', false) === true;
- });
- }
- foreach ($servers as $server) {
- CleanupHelperContainersJob::dispatch($server);
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stucked resources: {$e->getMessage()}\n";
- }
- try {
- $applicationsDeploymentQueue = ApplicationDeploymentQueue::get();
- foreach ($applicationsDeploymentQueue as $applicationDeploymentQueue) {
- if (is_null($applicationDeploymentQueue->application)) {
- echo "Deleting stuck application deployment queue: {$applicationDeploymentQueue->id}\n";
- $applicationDeploymentQueue->delete();
- }
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck application deployment queue: {$e->getMessage()}\n";
- }
- try {
- $applications = Application::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($applications as $application) {
- echo "Deleting stuck application: {$application->name}\n";
- $application->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck application: {$e->getMessage()}\n";
- }
- try {
- $applicationsPreviews = ApplicationPreview::get();
- foreach ($applicationsPreviews as $applicationPreview) {
- if (! data_get($applicationPreview, 'application')) {
- echo "Deleting stuck application preview: {$applicationPreview->uuid}\n";
- $applicationPreview->delete();
- }
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck application: {$e->getMessage()}\n";
- }
- try {
- $postgresqls = StandalonePostgresql::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($postgresqls as $postgresql) {
- echo "Deleting stuck postgresql: {$postgresql->name}\n";
- $postgresql->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck postgresql: {$e->getMessage()}\n";
- }
- try {
- $redis = StandaloneRedis::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($redis as $redis) {
- echo "Deleting stuck redis: {$redis->name}\n";
- $redis->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck redis: {$e->getMessage()}\n";
- }
- try {
- $keydbs = StandaloneKeydb::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($keydbs as $keydb) {
- echo "Deleting stuck keydb: {$keydb->name}\n";
- $keydb->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck keydb: {$e->getMessage()}\n";
- }
- try {
- $dragonflies = StandaloneDragonfly::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($dragonflies as $dragonfly) {
- echo "Deleting stuck dragonfly: {$dragonfly->name}\n";
- $dragonfly->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck dragonfly: {$e->getMessage()}\n";
- }
- try {
- $clickhouses = StandaloneClickhouse::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($clickhouses as $clickhouse) {
- echo "Deleting stuck clickhouse: {$clickhouse->name}\n";
- $clickhouse->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck clickhouse: {$e->getMessage()}\n";
- }
- try {
- $mongodbs = StandaloneMongodb::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($mongodbs as $mongodb) {
- echo "Deleting stuck mongodb: {$mongodb->name}\n";
- $mongodb->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck mongodb: {$e->getMessage()}\n";
- }
- try {
- $mysqls = StandaloneMysql::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($mysqls as $mysql) {
- echo "Deleting stuck mysql: {$mysql->name}\n";
- $mysql->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck mysql: {$e->getMessage()}\n";
- }
- try {
- $mariadbs = StandaloneMariadb::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($mariadbs as $mariadb) {
- echo "Deleting stuck mariadb: {$mariadb->name}\n";
- $mariadb->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck mariadb: {$e->getMessage()}\n";
- }
- try {
- $services = Service::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($services as $service) {
- echo "Deleting stuck service: {$service->name}\n";
- $service->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck service: {$e->getMessage()}\n";
- }
- try {
- $serviceApps = ServiceApplication::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($serviceApps as $serviceApp) {
- echo "Deleting stuck serviceapp: {$serviceApp->name}\n";
- $serviceApp->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck serviceapp: {$e->getMessage()}\n";
- }
- try {
- $serviceDbs = ServiceDatabase::withTrashed()->whereNotNull('deleted_at')->get();
- foreach ($serviceDbs as $serviceDb) {
- echo "Deleting stuck serviceapp: {$serviceDb->name}\n";
- $serviceDb->forceDelete();
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck serviceapp: {$e->getMessage()}\n";
- }
- try {
- $scheduled_tasks = ScheduledTask::all();
- foreach ($scheduled_tasks as $scheduled_task) {
- if (! $scheduled_task->service && ! $scheduled_task->application) {
- echo "Deleting stuck scheduledtask: {$scheduled_task->name}\n";
- $scheduled_task->delete();
- }
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck scheduledtasks: {$e->getMessage()}\n";
- }
-
- try {
- $scheduled_backups = ScheduledDatabaseBackup::all();
- foreach ($scheduled_backups as $scheduled_backup) {
- if (! $scheduled_backup->server()) {
- echo "Deleting stuck scheduledbackup: {$scheduled_backup->name}\n";
- $scheduled_backup->delete();
- }
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning stuck scheduledbackups: {$e->getMessage()}\n";
- }
-
- // Cleanup any resources that are not attached to any environment or destination or server
- try {
- $applications = Application::all();
- foreach ($applications as $application) {
- if (! data_get($application, 'environment')) {
- echo 'Application without environment: '.$application->name.'\n';
- $application->forceDelete();
-
- continue;
- }
- if (! $application->destination()) {
- echo 'Application without destination: '.$application->name.'\n';
- $application->forceDelete();
-
- continue;
- }
- if (! data_get($application, 'destination.server')) {
- echo 'Application without server: '.$application->name.'\n';
- $application->forceDelete();
-
- continue;
- }
- }
- } catch (\Throwable $e) {
- echo "Error in application: {$e->getMessage()}\n";
- }
- try {
- $postgresqls = StandalonePostgresql::all()->where('id', '!=', 0);
- foreach ($postgresqls as $postgresql) {
- if (! data_get($postgresql, 'environment')) {
- echo 'Postgresql without environment: '.$postgresql->name.'\n';
- $postgresql->forceDelete();
-
- continue;
- }
- if (! $postgresql->destination()) {
- echo 'Postgresql without destination: '.$postgresql->name.'\n';
- $postgresql->forceDelete();
-
- continue;
- }
- if (! data_get($postgresql, 'destination.server')) {
- echo 'Postgresql without server: '.$postgresql->name.'\n';
- $postgresql->forceDelete();
-
- continue;
- }
- }
- } catch (\Throwable $e) {
- echo "Error in postgresql: {$e->getMessage()}\n";
- }
- try {
- $redis = StandaloneRedis::all();
- foreach ($redis as $redis) {
- if (! data_get($redis, 'environment')) {
- echo 'Redis without environment: '.$redis->name.'\n';
- $redis->forceDelete();
-
- continue;
- }
- if (! $redis->destination()) {
- echo 'Redis without destination: '.$redis->name.'\n';
- $redis->forceDelete();
-
- continue;
- }
- if (! data_get($redis, 'destination.server')) {
- echo 'Redis without server: '.$redis->name.'\n';
- $redis->forceDelete();
-
- continue;
- }
- }
- } catch (\Throwable $e) {
- echo "Error in redis: {$e->getMessage()}\n";
- }
-
- try {
- $mongodbs = StandaloneMongodb::all();
- foreach ($mongodbs as $mongodb) {
- if (! data_get($mongodb, 'environment')) {
- echo 'Mongodb without environment: '.$mongodb->name.'\n';
- $mongodb->forceDelete();
-
- continue;
- }
- if (! $mongodb->destination()) {
- echo 'Mongodb without destination: '.$mongodb->name.'\n';
- $mongodb->forceDelete();
-
- continue;
- }
- if (! data_get($mongodb, 'destination.server')) {
- echo 'Mongodb without server: '.$mongodb->name.'\n';
- $mongodb->forceDelete();
-
- continue;
- }
- }
- } catch (\Throwable $e) {
- echo "Error in mongodb: {$e->getMessage()}\n";
- }
-
- try {
- $mysqls = StandaloneMysql::all();
- foreach ($mysqls as $mysql) {
- if (! data_get($mysql, 'environment')) {
- echo 'Mysql without environment: '.$mysql->name.'\n';
- $mysql->forceDelete();
-
- continue;
- }
- if (! $mysql->destination()) {
- echo 'Mysql without destination: '.$mysql->name.'\n';
- $mysql->forceDelete();
-
- continue;
- }
- if (! data_get($mysql, 'destination.server')) {
- echo 'Mysql without server: '.$mysql->name.'\n';
- $mysql->forceDelete();
-
- continue;
- }
- }
- } catch (\Throwable $e) {
- echo "Error in mysql: {$e->getMessage()}\n";
- }
-
- try {
- $mariadbs = StandaloneMariadb::all();
- foreach ($mariadbs as $mariadb) {
- if (! data_get($mariadb, 'environment')) {
- echo 'Mariadb without environment: '.$mariadb->name.'\n';
- $mariadb->forceDelete();
-
- continue;
- }
- if (! $mariadb->destination()) {
- echo 'Mariadb without destination: '.$mariadb->name.'\n';
- $mariadb->forceDelete();
-
- continue;
- }
- if (! data_get($mariadb, 'destination.server')) {
- echo 'Mariadb without server: '.$mariadb->name.'\n';
- $mariadb->forceDelete();
-
- continue;
- }
- }
- } catch (\Throwable $e) {
- echo "Error in mariadb: {$e->getMessage()}\n";
- }
-
- try {
- $services = Service::all();
- foreach ($services as $service) {
- if (! data_get($service, 'environment')) {
- echo 'Service without environment: '.$service->name.'\n';
- $service->forceDelete();
-
- continue;
- }
- if (! $service->destination()) {
- echo 'Service without destination: '.$service->name.'\n';
- $service->forceDelete();
-
- continue;
- }
- if (! data_get($service, 'server')) {
- echo 'Service without server: '.$service->name.'\n';
- $service->forceDelete();
-
- continue;
- }
- }
- } catch (\Throwable $e) {
- echo "Error in service: {$e->getMessage()}\n";
- }
- try {
- $serviceApplications = ServiceApplication::all();
- foreach ($serviceApplications as $service) {
- if (! data_get($service, 'service')) {
- echo 'ServiceApplication without service: '.$service->name.'\n';
- $service->forceDelete();
-
- continue;
- }
- }
- } catch (\Throwable $e) {
- echo "Error in serviceApplications: {$e->getMessage()}\n";
- }
- try {
- $serviceDatabases = ServiceDatabase::all();
- foreach ($serviceDatabases as $service) {
- if (! data_get($service, 'service')) {
- echo 'ServiceDatabase without service: '.$service->name.'\n';
- $service->forceDelete();
-
- continue;
- }
- }
- } catch (\Throwable $e) {
- echo "Error in ServiceDatabases: {$e->getMessage()}\n";
- }
- }
-}
diff --git a/app/Console/Commands/CleanupUnreachableServers.php b/app/Console/Commands/CleanupUnreachableServers.php
deleted file mode 100644
index def01b2651..0000000000
--- a/app/Console/Commands/CleanupUnreachableServers.php
+++ /dev/null
@@ -1,27 +0,0 @@
-where('unreachable_notification_sent', true)->where('updated_at', '<', now()->subDays(7))->get();
- if ($servers->count() > 0) {
- foreach ($servers as $server) {
- echo "Cleanup unreachable server ($server->id) with name $server->name";
- $server->update([
- 'ip' => '1.2.3.4',
- ]);
- }
- }
- }
-}
diff --git a/app/Console/Commands/CloudCheckSubscription.php b/app/Console/Commands/CloudCheckSubscription.php
deleted file mode 100644
index 6e237e84b2..0000000000
--- a/app/Console/Commands/CloudCheckSubscription.php
+++ /dev/null
@@ -1,49 +0,0 @@
-get();
- foreach ($activeSubscribers as $team) {
- $stripeSubscriptionId = $team->subscription->stripe_subscription_id;
- $stripeInvoicePaid = $team->subscription->stripe_invoice_paid;
- $stripeCustomerId = $team->subscription->stripe_customer_id;
- if (! $stripeSubscriptionId) {
- echo "Team {$team->id} has no subscription, but invoice status is: {$stripeInvoicePaid}\n";
- echo "Link on Stripe: https://dashboard.stripe.com/customers/{$stripeCustomerId}\n";
-
- continue;
- }
- $subscription = $stripe->subscriptions->retrieve($stripeSubscriptionId);
- if ($subscription->status === 'active') {
- continue;
- }
- echo "Subscription {$stripeSubscriptionId} is not active ({$subscription->status})\n";
- echo "Link on Stripe: https://dashboard.stripe.com/subscriptions/{$stripeSubscriptionId}\n";
- }
- }
-}
diff --git a/app/Console/Commands/CloudCleanupSubscriptions.php b/app/Console/Commands/CloudCleanupSubscriptions.php
deleted file mode 100644
index ab676c9278..0000000000
--- a/app/Console/Commands/CloudCleanupSubscriptions.php
+++ /dev/null
@@ -1,101 +0,0 @@
-error('This command can only be run on cloud');
-
- return;
- }
- $this->info('Cleaning up subcriptions teams');
- $stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key'));
-
- $teams = Team::all()->filter(function ($team) {
- return $team->id !== 0;
- })->sortBy('id');
- foreach ($teams as $team) {
- if ($team) {
- $this->info("Checking team {$team->id}");
- }
- if (! data_get($team, 'subscription')) {
- $this->disableServers($team);
-
- continue;
- }
- // If the team has no subscription id and the invoice is paid, we need to reset the invoice paid status
- if (! (data_get($team, 'subscription.stripe_subscription_id'))) {
- $this->info("Resetting invoice paid status for team {$team->id}");
-
- $team->subscription->update([
- 'stripe_invoice_paid' => false,
- 'stripe_trial_already_ended' => false,
- 'stripe_subscription_id' => null,
- ]);
- $this->disableServers($team);
-
- continue;
- } else {
- $subscription = $stripe->subscriptions->retrieve(data_get($team, 'subscription.stripe_subscription_id'), []);
- $status = data_get($subscription, 'status');
- if ($status === 'active') {
- $team->subscription->update([
- 'stripe_invoice_paid' => true,
- 'stripe_trial_already_ended' => false,
- ]);
-
- continue;
- }
- $this->info('Subscription status: '.$status);
- $this->info('Subscription id: '.data_get($team, 'subscription.stripe_subscription_id'));
- $confirm = $this->confirm('Do you want to cancel the subscription?', true);
- if (! $confirm) {
- $this->info("Skipping team {$team->id}");
- } else {
- $this->info("Cancelling subscription for team {$team->id}");
- $team->subscription->update([
- 'stripe_invoice_paid' => false,
- 'stripe_trial_already_ended' => false,
- 'stripe_subscription_id' => null,
- ]);
- $this->disableServers($team);
- }
- }
- }
- } catch (\Exception $e) {
- $this->error($e->getMessage());
-
- return;
- }
- }
-
- private function disableServers(Team $team)
- {
- foreach ($team->servers as $server) {
- if ($server->settings->is_usable === true || $server->settings->is_reachable === true || $server->ip !== '1.2.3.4') {
- $this->info("Disabling server {$server->id} {$server->name}");
- $server->settings()->update([
- 'is_usable' => false,
- 'is_reachable' => false,
- ]);
- $server->update([
- 'ip' => '1.2.3.4',
- ]);
-
- ServerReachabilityChanged::dispatch($server);
- }
- }
- }
-}
diff --git a/app/Console/Commands/Dev.php b/app/Console/Commands/Dev.php
deleted file mode 100644
index 257de0a927..0000000000
--- a/app/Console/Commands/Dev.php
+++ /dev/null
@@ -1,80 +0,0 @@
-option('init')) {
- $this->init();
-
- return;
- }
- if ($this->option('generate-openapi')) {
- $this->generateOpenApi();
-
- return;
- }
- }
-
- public function generateOpenApi()
- {
- // Generate OpenAPI documentation
- echo "Generating OpenAPI documentation.\n";
- // https://github.com/OAI/OpenAPI-Specification/releases
- $process = Process::run([
- '/var/www/html/vendor/bin/openapi',
- 'app',
- '-o',
- 'openapi.yaml',
- '--version',
- '3.1.0',
- ]);
- $error = $process->errorOutput();
- $error = preg_replace('/^.*an object literal,.*$/m', '', $error);
- $error = preg_replace('/^\h*\v+/m', '', $error);
- echo $error;
- echo $process->output();
- // Convert YAML to JSON
- $yaml = file_get_contents('openapi.yaml');
- $json = json_encode(Yaml::parse($yaml), JSON_PRETTY_PRINT);
- file_put_contents('openapi.json', $json);
- echo "Converted OpenAPI YAML to JSON.\n";
- }
-
- public function init()
- {
- // Generate APP_KEY if not exists
-
- if (empty(config('app.key'))) {
- echo "Generating APP_KEY.\n";
- Artisan::call('key:generate');
- }
-
- // Generate STORAGE link if not exists
- if (! file_exists(public_path('storage'))) {
- echo "Generating STORAGE link.\n";
- Artisan::call('storage:link');
- }
-
- // Seed database if it's empty
- $settings = InstanceSettings::find(0);
- if (! $settings) {
- echo "Initializing instance, seeding database.\n";
- Artisan::call('migrate --seed');
- } else {
- echo "Instance already initialized.\n";
- }
- }
-}
diff --git a/app/Console/Commands/Emails.php b/app/Console/Commands/Emails.php
deleted file mode 100644
index a022d54dc6..0000000000
--- a/app/Console/Commands/Emails.php
+++ /dev/null
@@ -1,277 +0,0 @@
- 'Send Update Email to all users',
- 'emails-test' => 'Test',
- 'database-backup-statuses-daily' => 'Database - Backup Statuses (Daily)',
- 'application-deployment-success-daily' => 'Application - Deployment Success (Daily)',
- 'application-deployment-success' => 'Application - Deployment Success',
- 'application-deployment-failed' => 'Application - Deployment Failed',
- 'application-status-changed' => 'Application - Status Changed',
- 'backup-success' => 'Database - Backup Success',
- 'backup-failed' => 'Database - Backup Failed',
- // 'invitation-link' => 'Invitation Link',
- 'realusers-before-trial' => 'REAL - Registered Users Before Trial without Subscription',
- 'realusers-server-lost-connection' => 'REAL - Server Lost Connection',
- ],
- );
- $emailsGathered = ['realusers-before-trial', 'realusers-server-lost-connection'];
- if (isDev()) {
- $this->email = 'test@example.com';
- } else {
- if (! in_array($type, $emailsGathered)) {
- $this->email = text('Email Address to send to:');
- }
- }
- set_transanctional_email_settings();
-
- $this->mail = new MailMessage;
- $this->mail->subject('Test Email');
- switch ($type) {
- case 'updates':
- $teams = Team::all();
- if (! $teams || $teams->isEmpty()) {
- echo 'No teams found.'.PHP_EOL;
-
- return;
- }
- $emails = [];
- foreach ($teams as $team) {
- foreach ($team->members as $member) {
- if ($member->email && $member->marketing_emails) {
- $emails[] = $member->email;
- }
- }
- }
- $emails = array_unique($emails);
- $this->info('Sending to '.count($emails).' emails.');
- foreach ($emails as $email) {
- $this->info($email);
- }
- $confirmed = confirm('Are you sure?');
- if ($confirmed) {
- foreach ($emails as $email) {
- $this->mail = new MailMessage;
- $this->mail->subject('One-click Services, Docker Compose support');
- $unsubscribeUrl = route('unsubscribe.marketing.emails', [
- 'token' => encrypt($email),
- ]);
- $this->mail->view('emails.updates', ['unsubscribeUrl' => $unsubscribeUrl]);
- $this->sendEmail($email);
- }
- }
- break;
- case 'emails-test':
- $this->mail = (new Test)->toMail();
- $this->sendEmail();
- break;
- case 'application-deployment-success-daily':
- $applications = Application::all();
- foreach ($applications as $application) {
- $deployments = $application->get_last_days_deployments();
- if ($deployments->isEmpty()) {
- continue;
- }
- $this->mail = (new DeploymentSuccess($application, 'test'))->toMail();
- $this->sendEmail();
- }
- break;
- case 'application-deployment-success':
- $application = Application::all()->first();
- $this->mail = (new DeploymentSuccess($application, 'test'))->toMail();
- $this->sendEmail();
- break;
- case 'application-deployment-failed':
- $application = Application::all()->first();
- $preview = ApplicationPreview::all()->first();
- if (! $preview) {
- $preview = ApplicationPreview::create([
- 'application_id' => $application->id,
- 'pull_request_id' => 1,
- 'pull_request_html_url' => 'http://example.com',
- 'fqdn' => $application->fqdn,
- ]);
- }
- $this->mail = (new DeploymentFailed($application, 'test'))->toMail();
- $this->sendEmail();
- $this->mail = (new DeploymentFailed($application, 'test', $preview))->toMail();
- $this->sendEmail();
- break;
- case 'application-status-changed':
- $application = Application::all()->first();
- $this->mail = (new StatusChanged($application))->toMail();
- $this->sendEmail();
- break;
- case 'backup-failed':
- $backup = ScheduledDatabaseBackup::all()->first();
- $db = StandalonePostgresql::all()->first();
- if (! $backup) {
- $backup = ScheduledDatabaseBackup::create([
- 'enabled' => true,
- 'frequency' => 'daily',
- 'save_s3' => false,
- 'database_id' => $db->id,
- 'database_type' => $db->getMorphClass(),
- 'team_id' => 0,
- ]);
- }
- $output = 'Because of an error, the backup of the database '.$db->name.' failed.';
- $this->mail = (new BackupFailed($backup, $db, $output))->toMail();
- $this->sendEmail();
- break;
- case 'backup-success':
- $backup = ScheduledDatabaseBackup::all()->first();
- $db = StandalonePostgresql::all()->first();
- if (! $backup) {
- $backup = ScheduledDatabaseBackup::create([
- 'enabled' => true,
- 'frequency' => 'daily',
- 'save_s3' => false,
- 'database_id' => $db->id,
- 'database_type' => $db->getMorphClass(),
- 'team_id' => 0,
- ]);
- }
- // $this->mail = (new BackupSuccess($backup->frequency, $db->name))->toMail();
- $this->sendEmail();
- break;
- // case 'invitation-link':
- // $user = User::all()->first();
- // $invitation = TeamInvitation::whereEmail($user->email)->first();
- // if (!$invitation) {
- // $invitation = TeamInvitation::create([
- // 'uuid' => Str::uuid(),
- // 'email' => $user->email,
- // 'team_id' => 1,
- // 'link' => 'http://example.com',
- // ]);
- // }
- // $this->mail = (new InvitationLink($user))->toMail();
- // $this->sendEmail();
- // break;
- case 'realusers-before-trial':
- $this->mail = new MailMessage;
- $this->mail->view('emails.before-trial-conversion');
- $this->mail->subject('Trial period has been added for all subscription plans.');
- $teams = Team::doesntHave('subscription')->where('id', '!=', 0)->get();
- if (! $teams || $teams->isEmpty()) {
- echo 'No teams found.'.PHP_EOL;
-
- return;
- }
- $emails = [];
- foreach ($teams as $team) {
- foreach ($team->members as $member) {
- if ($member->email) {
- $emails[] = $member->email;
- }
- }
- }
- $emails = array_unique($emails);
- $this->info('Sending to '.count($emails).' emails.');
- foreach ($emails as $email) {
- $this->info($email);
- }
- $confirmed = confirm('Are you sure?');
- if ($confirmed) {
- foreach ($emails as $email) {
- $this->sendEmail($email);
- }
- }
- break;
- case 'realusers-server-lost-connection':
- $serverId = text('Server Id');
- $server = Server::find($serverId);
- if (! $server) {
- throw new Exception('Server not found');
- }
- $admins = [];
- $members = $server->team->members;
- foreach ($members as $member) {
- if ($member->isAdmin()) {
- $admins[] = $member->email;
- }
- }
- $this->info('Sending to '.count($admins).' admins.');
- foreach ($admins as $admin) {
- $this->info($admin);
- }
- $this->mail = new MailMessage;
- $this->mail->view('emails.server-lost-connection', [
- 'name' => $server->name,
- ]);
- $this->mail->subject('Action required: Server '.$server->name.' lost connection.');
- foreach ($admins as $email) {
- $this->sendEmail($email);
- }
- break;
- }
- }
-
- private function sendEmail(?string $email = null)
- {
- if ($email) {
- $this->email = $email;
- }
- Mail::send(
- [],
- [],
- fn (Message $message) => $message
- ->to($this->email)
- ->subject($this->mail->subject)
- ->html((string) $this->mail->render())
- );
- $this->info("Email sent to $this->email successfully. 📧");
- }
-}
diff --git a/app/Console/Commands/Horizon.php b/app/Console/Commands/Horizon.php
deleted file mode 100644
index d3e35ca5a1..0000000000
--- a/app/Console/Commands/Horizon.php
+++ /dev/null
@@ -1,23 +0,0 @@
-info('Horizon is enabled on this server.');
- $this->call('horizon');
- exit(0);
- } else {
- exit(0);
- }
- }
-}
diff --git a/app/Console/Commands/HorizonManage.php b/app/Console/Commands/HorizonManage.php
deleted file mode 100644
index ca2da147c4..0000000000
--- a/app/Console/Commands/HorizonManage.php
+++ /dev/null
@@ -1,178 +0,0 @@
-option('can-i-restart-this-worker')) {
- return $this->isThereAJobInProgress();
- }
-
- if ($this->option('job-status')) {
- return $this->getJobStatus($this->option('job-status'));
- }
-
- $action = select(
- label: 'What to do?',
- options: [
- 'pending' => 'Pending Jobs',
- 'running' => 'Running Jobs',
- 'can-i-restart-this-worker' => 'Can I restart this worker?',
- 'job-status' => 'Job Status',
- 'workers' => 'Workers',
- 'failed' => 'Failed Jobs',
- 'failed-delete' => 'Failed Jobs - Delete',
- 'purge-queues' => 'Purge Queues',
- ]
- );
-
- if ($action === 'can-i-restart-this-worker') {
- $this->isThereAJobInProgress();
- }
-
- if ($action === 'job-status') {
- $jobId = text('Which job to check?');
- $jobStatus = $this->getJobStatus($jobId);
- $this->info('Job Status: '.$jobStatus);
- }
-
- if ($action === 'pending') {
- $pendingJobs = app(JobRepository::class)->getPending();
- $pendingJobsTable = [];
- if (count($pendingJobs) === 0) {
- $this->info('No pending jobs found.');
-
- return;
- }
- foreach ($pendingJobs as $pendingJob) {
- $pendingJobsTable[] = [
- 'id' => $pendingJob->id,
- 'name' => $pendingJob->name,
- 'status' => $pendingJob->status,
- 'reserved_at' => $pendingJob->reserved_at ? now()->parse($pendingJob->reserved_at)->format('Y-m-d H:i:s') : null,
- ];
- }
- table($pendingJobsTable);
- }
-
- if ($action === 'failed') {
- $failedJobs = app(JobRepository::class)->getFailed();
- $failedJobsTable = [];
- if (count($failedJobs) === 0) {
- $this->info('No failed jobs found.');
-
- return;
- }
- foreach ($failedJobs as $failedJob) {
- $failedJobsTable[] = [
- 'id' => $failedJob->id,
- 'name' => $failedJob->name,
- 'failed_at' => $failedJob->failed_at ? now()->parse($failedJob->failed_at)->format('Y-m-d H:i:s') : null,
- ];
- }
- table($failedJobsTable);
- }
-
- if ($action === 'failed-delete') {
- $failedJobs = app(JobRepository::class)->getFailed();
- $failedJobsTable = [];
- foreach ($failedJobs as $failedJob) {
- $failedJobsTable[] = [
- 'id' => $failedJob->id,
- 'name' => $failedJob->name,
- 'failed_at' => $failedJob->failed_at ? now()->parse($failedJob->failed_at)->format('Y-m-d H:i:s') : null,
- ];
- }
- app(MetricsRepository::class)->clear();
- if (count($failedJobsTable) === 0) {
- $this->info('No failed jobs found.');
-
- return;
- }
- $jobIds = multiselect(
- label: 'Which job to delete?',
- options: collect($failedJobsTable)->mapWithKeys(fn ($job) => [$job['id'] => $job['id'].' - '.$job['name']])->toArray(),
- );
- foreach ($jobIds as $jobId) {
- Artisan::queue('horizon:forget', ['id' => $jobId]);
- }
- }
-
- if ($action === 'running') {
- $redisJobRepository = app(CustomJobRepository::class);
- $runningJobs = $redisJobRepository->getReservedJobs();
- $runningJobsTable = [];
- if (count($runningJobs) === 0) {
- $this->info('No running jobs found.');
-
- return;
- }
- foreach ($runningJobs as $runningJob) {
- $runningJobsTable[] = [
- 'id' => $runningJob->id,
- 'name' => $runningJob->name,
- 'reserved_at' => $runningJob->reserved_at ? now()->parse($runningJob->reserved_at)->format('Y-m-d H:i:s') : null,
- ];
- }
- table($runningJobsTable);
- }
-
- if ($action === 'workers') {
- $redisJobRepository = app(CustomJobRepository::class);
- $workers = $redisJobRepository->getHorizonWorkers();
- $workersTable = [];
- foreach ($workers as $worker) {
- $workersTable[] = [
- 'name' => $worker->name,
- ];
- }
- table($workersTable);
- }
-
- if ($action === 'purge-queues') {
- $getQueues = app(CustomJobRepository::class)->getQueues();
- $queueName = select(
- label: 'Which queue to purge?',
- options: $getQueues,
- );
- $redisJobRepository = app(RedisJobRepository::class);
- $redisJobRepository->purge($queueName);
- }
- }
-
- public function isThereAJobInProgress()
- {
- $runningJobs = ApplicationDeploymentQueue::where('horizon_job_worker', gethostname())->where('status', ApplicationDeploymentStatus::IN_PROGRESS->value)->get();
- $count = $runningJobs->count();
- if ($count === 0) {
- return false;
- }
-
- return true;
- }
-
- public function getJobStatus(string $jobId)
- {
- return getJobStatus($jobId);
- }
-}
diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php
deleted file mode 100644
index a954b10fdf..0000000000
--- a/app/Console/Commands/Init.php
+++ /dev/null
@@ -1,273 +0,0 @@
-optimize();
-
- if (isCloud() && ! $this->option('force-cloud')) {
- echo "Skipping init as we are on cloud and --force-cloud option is not set\n";
-
- return;
- }
-
- $this->servers = Server::all();
- if (! isCloud()) {
- $this->send_alive_signal();
- get_public_ips();
- }
-
- // Backward compatibility
- $this->replace_slash_in_environment_name();
- $this->restore_coolify_db_backup();
- $this->update_user_emails();
- //
- $this->update_traefik_labels();
- if (! isCloud() || $this->option('force-cloud')) {
- $this->cleanup_unused_network_from_coolify_proxy();
- }
- if (isCloud()) {
- $this->cleanup_unnecessary_dynamic_proxy_configuration();
- } else {
- $this->cleanup_in_progress_application_deployments();
- }
- $this->call('cleanup:redis');
-
- $this->call('cleanup:stucked-resources');
-
- try {
- $this->pullHelperImage();
- } catch (\Throwable $e) {
- //
- }
-
- if (isCloud()) {
- try {
- $this->pullTemplatesFromCDN();
- } catch (\Throwable $e) {
- echo "Could not pull templates from CDN: {$e->getMessage()}\n";
- }
- }
-
- if (! isCloud()) {
- try {
- $this->pullTemplatesFromCDN();
- } catch (\Throwable $e) {
- echo "Could not pull templates from CDN: {$e->getMessage()}\n";
- }
- try {
- $localhost = $this->servers->where('id', 0)->first();
- $localhost->setupDynamicProxyConfiguration();
- } catch (\Throwable $e) {
- echo "Could not setup dynamic configuration: {$e->getMessage()}\n";
- }
- $settings = instanceSettings();
- if (! is_null(config('constants.coolify.autoupdate', null))) {
- if (config('constants.coolify.autoupdate') == true) {
- echo "Enabling auto-update\n";
- $settings->update(['is_auto_update_enabled' => true]);
- } else {
- echo "Disabling auto-update\n";
- $settings->update(['is_auto_update_enabled' => false]);
- }
- }
- }
- }
-
- private function pullHelperImage()
- {
- CheckHelperImageJob::dispatch();
- }
-
- private function pullTemplatesFromCDN()
- {
- $response = Http::retry(3, 1000)->get(config('constants.services.official'));
- if ($response->successful()) {
- $services = $response->json();
- File::put(base_path('templates/service-templates.json'), json_encode($services));
- }
- }
-
- private function optimize()
- {
- Artisan::call('optimize:clear');
- Artisan::call('optimize');
- }
-
- private function update_user_emails()
- {
- try {
- User::whereRaw('email ~ \'[A-Z]\'')->get()->each(function (User $user) {
- $user->update(['email' => strtolower($user->email)]);
- });
- } catch (\Throwable $e) {
- echo "Error in updating user emails: {$e->getMessage()}\n";
- }
- }
-
- private function update_traefik_labels()
- {
- try {
- Server::where('proxy->type', 'TRAEFIK_V2')->update(['proxy->type' => 'TRAEFIK']);
- } catch (\Throwable $e) {
- echo "Error in updating traefik labels: {$e->getMessage()}\n";
- }
- }
-
- private function cleanup_unnecessary_dynamic_proxy_configuration()
- {
- foreach ($this->servers as $server) {
- try {
- if (! $server->isFunctional()) {
- continue;
- }
- if ($server->id === 0) {
- continue;
- }
- $file = $server->proxyPath().'/dynamic/coolify.yaml';
-
- return instant_remote_process([
- "rm -f $file",
- ], $server, false);
- } catch (\Throwable $e) {
- echo "Error in cleaning up unnecessary dynamic proxy configuration: {$e->getMessage()}\n";
- }
- }
- }
-
- private function cleanup_unused_network_from_coolify_proxy()
- {
- foreach ($this->servers as $server) {
- if (! $server->isFunctional()) {
- continue;
- }
- if (! $server->isProxyShouldRun()) {
- continue;
- }
- try {
- ['networks' => $networks, 'allNetworks' => $allNetworks] = collectDockerNetworksByServer($server);
- $removeNetworks = $allNetworks->diff($networks);
- $commands = collect();
- foreach ($removeNetworks as $network) {
- $out = instant_remote_process(["docker network inspect -f json $network | jq '.[].Containers | if . == {} then null else . end'"], $server, false);
- if (empty($out)) {
- $commands->push("docker network disconnect $network coolify-proxy >/dev/null 2>&1 || true");
- $commands->push("docker network rm $network >/dev/null 2>&1 || true");
- } else {
- $data = collect(json_decode($out, true));
- if ($data->count() === 1) {
- // If only coolify-proxy itself is connected to that network (it should not be possible, but who knows)
- $isCoolifyProxyItself = data_get($data->first(), 'Name') === 'coolify-proxy';
- if ($isCoolifyProxyItself) {
- $commands->push("docker network disconnect $network coolify-proxy >/dev/null 2>&1 || true");
- $commands->push("docker network rm $network >/dev/null 2>&1 || true");
- }
- }
- }
- }
- if ($commands->isNotEmpty()) {
- remote_process(command: $commands, type: ActivityTypes::INLINE->value, server: $server, ignore_errors: false);
- }
- } catch (\Throwable $e) {
- echo "Error in cleaning up unused networks from coolify proxy: {$e->getMessage()}\n";
- }
- }
- }
-
- private function restore_coolify_db_backup()
- {
- if (version_compare('4.0.0-beta.179', config('constants.coolify.version'), '<=')) {
- try {
- $database = StandalonePostgresql::withTrashed()->find(0);
- if ($database && $database->trashed()) {
- $database->restore();
- $scheduledBackup = ScheduledDatabaseBackup::find(0);
- if (! $scheduledBackup) {
- ScheduledDatabaseBackup::create([
- 'id' => 0,
- 'enabled' => true,
- 'save_s3' => false,
- 'frequency' => '0 0 * * *',
- 'database_id' => $database->id,
- 'database_type' => \App\Models\StandalonePostgresql::class,
- 'team_id' => 0,
- ]);
- }
- }
- } catch (\Throwable $e) {
- echo "Error in restoring coolify db backup: {$e->getMessage()}\n";
- }
- }
- }
-
- private function send_alive_signal()
- {
- $id = config('app.id');
- $version = config('constants.coolify.version');
- $settings = instanceSettings();
- $do_not_track = data_get($settings, 'do_not_track');
- if ($do_not_track == true) {
- echo "Do_not_track is enabled\n";
-
- return;
- }
- try {
- Http::get("https://undead.coolify.io/v4/alive?appId=$id&version=$version");
- } catch (\Throwable $e) {
- echo "Error in sending live signal: {$e->getMessage()}\n";
- }
- }
-
- private function cleanup_in_progress_application_deployments()
- {
- // Cleanup any failed deployments
- try {
- if (isCloud()) {
- return;
- }
- $queued_inprogress_deployments = ApplicationDeploymentQueue::whereIn('status', [ApplicationDeploymentStatus::IN_PROGRESS->value, ApplicationDeploymentStatus::QUEUED->value])->get();
- foreach ($queued_inprogress_deployments as $deployment) {
- $deployment->status = ApplicationDeploymentStatus::FAILED->value;
- $deployment->save();
- }
- } catch (\Throwable $e) {
- echo "Error: {$e->getMessage()}\n";
- }
- }
-
- private function replace_slash_in_environment_name()
- {
- if (version_compare('4.0.0-beta.298', config('constants.coolify.version'), '<=')) {
- $environments = Environment::all();
- foreach ($environments as $environment) {
- if (str_contains($environment->name, '/')) {
- $environment->name = str_replace('/', '-', $environment->name);
- $environment->save();
- }
- }
- }
- }
-}
diff --git a/app/Console/Commands/Migration.php b/app/Console/Commands/Migration.php
deleted file mode 100644
index 44c17203bf..0000000000
--- a/app/Console/Commands/Migration.php
+++ /dev/null
@@ -1,24 +0,0 @@
-info('Migration is enabled on this server.');
- $this->call('migrate', ['--force' => true, '--isolated' => true]);
- exit(0);
- } else {
- $this->info('Migration is disabled on this server.');
- exit(0);
- }
- }
-}
diff --git a/app/Console/Commands/NotifyDemo.php b/app/Console/Commands/NotifyDemo.php
deleted file mode 100644
index 990a03869c..0000000000
--- a/app/Console/Commands/NotifyDemo.php
+++ /dev/null
@@ -1,78 +0,0 @@
-argument('channel');
-
- if (blank($channel)) {
- $this->showHelp();
-
- return;
- }
- }
-
- private function showHelp()
- {
- style('coolify')->color('#9333EA');
- style('title-box')->apply('mt-1 px-2 py-1 bg-coolify');
-
- render(
- <<<'HTML'
-
-
- Coolify
-
-
- Demo Notify => Send a demo notification to a given channel.
-
-
- php artisan app:demo-notify {channel}
-
-
-
Channels:
-
- email
- discord
- telegram
- slack
- pushover
-
-
-
- HTML
- );
-
- ask(<<<'HTML'
-
- In which manner you wish a coolified notification?
-
- HTML, ['email', 'discord', 'telegram', 'slack', 'pushover']);
- }
-}
diff --git a/app/Console/Commands/OpenApi.php b/app/Console/Commands/OpenApi.php
deleted file mode 100644
index 6cbcb310c3..0000000000
--- a/app/Console/Commands/OpenApi.php
+++ /dev/null
@@ -1,33 +0,0 @@
-errorOutput();
- $error = preg_replace('/^.*an object literal,.*$/m', '', $error);
- $error = preg_replace('/^\h*\v+/m', '', $error);
- echo $error;
- echo $process->output();
- }
-}
diff --git a/app/Console/Commands/RootChangeEmail.php b/app/Console/Commands/RootChangeEmail.php
deleted file mode 100644
index c87a545c5b..0000000000
--- a/app/Console/Commands/RootChangeEmail.php
+++ /dev/null
@@ -1,42 +0,0 @@
-info('You are about to change the root user\'s email.');
- $email = $this->ask('Give me a new email for root user');
- $this->info('Updating root email...');
- try {
- User::find(0)->update(['email' => $email]);
- $this->info('Root user\'s email updated successfully.');
- } catch (\Exception $e) {
- $this->error('Failed to update root user\'s email.');
-
- return;
- }
- }
-}
diff --git a/app/Console/Commands/RootResetPassword.php b/app/Console/Commands/RootResetPassword.php
deleted file mode 100644
index f36c11a4f1..0000000000
--- a/app/Console/Commands/RootResetPassword.php
+++ /dev/null
@@ -1,50 +0,0 @@
-info('You are about to reset the root password.');
- $password = password('Give me a new password for root user: ');
- $passwordAgain = password('Again');
- if ($password != $passwordAgain) {
- $this->error('Passwords do not match.');
-
- return;
- }
- $this->info('Updating root password...');
- try {
- User::find(0)->update(['password' => Hash::make($password)]);
- $this->info('Root password updated successfully.');
- } catch (\Exception $e) {
- $this->error('Failed to update root password.');
-
- return;
- }
- }
-}
diff --git a/app/Console/Commands/Scheduler.php b/app/Console/Commands/Scheduler.php
deleted file mode 100644
index ee64368c3d..0000000000
--- a/app/Console/Commands/Scheduler.php
+++ /dev/null
@@ -1,23 +0,0 @@
-info('Scheduler is enabled on this server.');
- $this->call('schedule:work');
- exit(0);
- } else {
- exit(0);
- }
- }
-}
diff --git a/app/Console/Commands/Seeder.php b/app/Console/Commands/Seeder.php
deleted file mode 100644
index e37b6a9d27..0000000000
--- a/app/Console/Commands/Seeder.php
+++ /dev/null
@@ -1,24 +0,0 @@
-info('Seeder is enabled on this server.');
- $this->call('db:seed', ['--class' => 'ProductionSeeder', '--force' => true]);
- exit(0);
- } else {
- $this->info('Seeder is disabled on this server.');
- exit(0);
- }
- }
-}
diff --git a/app/Console/Commands/ServicesDelete.php b/app/Console/Commands/ServicesDelete.php
deleted file mode 100644
index b5a74166a5..0000000000
--- a/app/Console/Commands/ServicesDelete.php
+++ /dev/null
@@ -1,155 +0,0 @@
-deleteApplication();
- } elseif ($resource === 'Database') {
- $this->deleteDatabase();
- } elseif ($resource === 'Service') {
- $this->deleteService();
- } elseif ($resource === 'Server') {
- $this->deleteServer();
- }
- }
-
- private function deleteServer()
- {
- $servers = Server::all();
- if ($servers->count() === 0) {
- $this->error('There are no applications to delete.');
-
- return;
- }
- $serversToDelete = multiselect(
- label: 'What server do you want to delete?',
- options: $servers->pluck('name', 'id')->sortKeys(),
- );
-
- foreach ($serversToDelete as $server) {
- $toDelete = $servers->where('id', $server)->first();
- if ($toDelete) {
- $this->info($toDelete);
- $confirmed = confirm('Are you sure you want to delete all selected resources?');
- if (! $confirmed) {
- break;
- }
- $toDelete->delete();
- }
- }
- }
-
- private function deleteApplication()
- {
- $applications = Application::all();
- if ($applications->count() === 0) {
- $this->error('There are no applications to delete.');
-
- return;
- }
- $applicationsToDelete = multiselect(
- 'What application do you want to delete?',
- $applications->pluck('name', 'id')->sortKeys(),
- );
-
- foreach ($applicationsToDelete as $application) {
- $toDelete = $applications->where('id', $application)->first();
- if ($toDelete) {
- $this->info($toDelete);
- $confirmed = confirm('Are you sure you want to delete all selected resources? ');
- if (! $confirmed) {
- break;
- }
- DeleteResourceJob::dispatch($toDelete);
- }
- }
- }
-
- private function deleteDatabase()
- {
- $databases = StandalonePostgresql::all();
- if ($databases->count() === 0) {
- $this->error('There are no databases to delete.');
-
- return;
- }
- $databasesToDelete = multiselect(
- 'What database do you want to delete?',
- $databases->pluck('name', 'id')->sortKeys(),
- );
-
- foreach ($databasesToDelete as $database) {
- $toDelete = $databases->where('id', $database)->first();
- if ($toDelete) {
- $this->info($toDelete);
- $confirmed = confirm('Are you sure you want to delete all selected resources?');
- if (! $confirmed) {
- return;
- }
- DeleteResourceJob::dispatch($toDelete);
- }
- }
- }
-
- private function deleteService()
- {
- $services = Service::all();
- if ($services->count() === 0) {
- $this->error('There are no services to delete.');
-
- return;
- }
- $servicesToDelete = multiselect(
- 'What service do you want to delete?',
- $services->pluck('name', 'id')->sortKeys(),
- );
-
- foreach ($servicesToDelete as $service) {
- $toDelete = $services->where('id', $service)->first();
- if ($toDelete) {
- $this->info($toDelete);
- $confirmed = confirm('Are you sure you want to delete all selected resources?');
- if (! $confirmed) {
- return;
- }
- DeleteResourceJob::dispatch($toDelete);
- }
- }
- }
-}
diff --git a/app/Console/Commands/ServicesGenerate.php b/app/Console/Commands/ServicesGenerate.php
deleted file mode 100644
index b45707c5c0..0000000000
--- a/app/Console/Commands/ServicesGenerate.php
+++ /dev/null
@@ -1,89 +0,0 @@
-mapWithKeys(function ($file): array {
- $file = basename($file);
- $parsed = $this->processFile($file);
-
- return $parsed === false ? [] : [
- Arr::pull($parsed, 'name') => $parsed,
- ];
- })->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
-
- file_put_contents(base_path('templates/service-templates.json'), $serviceTemplatesJson.PHP_EOL);
-
- return self::SUCCESS;
- }
-
- private function processFile(string $file): false|array
- {
- $content = file_get_contents(base_path("templates/compose/$file"));
-
- $data = collect(explode(PHP_EOL, $content))->mapWithKeys(function ($line): array {
- preg_match('/^#(?.*):(?.*)$/U', $line, $m);
-
- return $m ? [trim($m['key']) => trim($m['value'])] : [];
- });
-
- if (str($data->get('ignore'))->toBoolean()) {
- $this->info("Ignoring $file");
-
- return false;
- }
-
- $this->info("Processing $file");
-
- $documentation = $data->get('documentation');
- $documentation = $documentation ? $documentation.'?utm_source=coolify.io' : 'https://coolify.io/docs';
-
- $json = Yaml::parse($content);
- $compose = base64_encode(Yaml::dump($json, 10, 2));
-
- $tags = str($data->get('tags'))->lower()->explode(',')->map(fn ($tag) => trim($tag))->filter();
- $tags = $tags->isEmpty() ? null : $tags->all();
-
- $payload = [
- 'name' => pathinfo($file, PATHINFO_FILENAME),
- 'documentation' => $documentation,
- 'slogan' => $data->get('slogan', str($file)->headline()),
- 'compose' => $compose,
- 'tags' => $tags,
- 'logo' => $data->get('logo', 'svgs/default.webp'),
- 'minversion' => $data->get('minversion', '0.0.0'),
- ];
-
- if ($port = $data->get('port')) {
- $payload['port'] = $port;
- }
-
- if ($envFile = $data->get('env_file')) {
- $envFileContent = file_get_contents(base_path("templates/compose/$envFile"));
- $payload['envs'] = base64_encode($envFileContent);
- }
-
- return $payload;
- }
-}
diff --git a/app/Console/Commands/SyncBunny.php b/app/Console/Commands/SyncBunny.php
deleted file mode 100644
index df19038286..0000000000
--- a/app/Console/Commands/SyncBunny.php
+++ /dev/null
@@ -1,159 +0,0 @@
-option('templates');
- $only_version = $this->option('release');
- $nightly = $this->option('nightly');
- $bunny_cdn = 'https://cdn.coollabs.io';
- $bunny_cdn_path = 'coolify';
- $bunny_cdn_storage_name = 'coolcdn';
-
- $parent_dir = realpath(dirname(__FILE__).'/../../..');
-
- $compose_file = 'docker-compose.yml';
- $compose_file_prod = 'docker-compose.prod.yml';
- $install_script = 'install.sh';
- $upgrade_script = 'upgrade.sh';
- $production_env = '.env.production';
- $service_template = 'service-templates.json';
- $versions = 'versions.json';
-
- $compose_file_location = "$parent_dir/$compose_file";
- $compose_file_prod_location = "$parent_dir/$compose_file_prod";
- $install_script_location = "$parent_dir/scripts/install.sh";
- $upgrade_script_location = "$parent_dir/scripts/upgrade.sh";
- $production_env_location = "$parent_dir/.env.production";
- $versions_location = "$parent_dir/$versions";
-
- PendingRequest::macro('storage', function ($fileName) use ($that) {
- $headers = [
- 'AccessKey' => config('constants.bunny.storage_api_key'),
- 'Accept' => 'application/json',
- 'Content-Type' => 'application/octet-stream',
- ];
- $fileStream = fopen($fileName, 'r');
- $file = fread($fileStream, filesize($fileName));
- $that->info('Uploading: '.$fileName);
-
- return PendingRequest::baseUrl('https://storage.bunnycdn.com')->withHeaders($headers)->withBody($file)->throw();
- });
- PendingRequest::macro('purge', function ($url) use ($that) {
- $headers = [
- 'AccessKey' => config('constants.bunny.api_key'),
- 'Accept' => 'application/json',
- ];
- $that->info('Purging: '.$url);
-
- return PendingRequest::withHeaders($headers)->get('https://api.bunny.net/purge', [
- 'url' => $url,
- 'async' => false,
- ]);
- });
- try {
- if ($nightly) {
- $bunny_cdn_path = 'coolify-nightly';
-
- $compose_file_location = "$parent_dir/other/nightly/$compose_file";
- $compose_file_prod_location = "$parent_dir/other/nightly/$compose_file_prod";
- $production_env_location = "$parent_dir/other/nightly/$production_env";
- $upgrade_script_location = "$parent_dir/other/nightly/$upgrade_script";
- $install_script_location = "$parent_dir/other/nightly/$install_script";
- $versions_location = "$parent_dir/other/nightly/$versions";
- }
- if (! $only_template && ! $only_version) {
- if ($nightly) {
- $this->info('About to sync files NIGHTLY (docker-compose.prod.yaml, upgrade.sh, install.sh, etc) to BunnyCDN.');
- } else {
- $this->info('About to sync files PRODUCTION (docker-compose.yml, docker-compose.prod.yml, upgrade.sh, install.sh, etc) to BunnyCDN.');
- }
- $confirmed = confirm('Are you sure you want to sync?');
- if (! $confirmed) {
- return;
- }
- }
- if ($only_template) {
- $this->info('About to sync service-templates.json to BunnyCDN.');
- $confirmed = confirm('Are you sure you want to sync?');
- if (! $confirmed) {
- return;
- }
- Http::pool(fn (Pool $pool) => [
- $pool->storage(fileName: "$parent_dir/templates/$service_template")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$service_template"),
- $pool->purge("$bunny_cdn/$bunny_cdn_path/$service_template"),
- ]);
- $this->info('Service template uploaded & purged...');
-
- return;
- } elseif ($only_version) {
- if ($nightly) {
- $this->info('About to sync NIGHLTY versions.json to BunnyCDN.');
- } else {
- $this->info('About to sync PRODUCTION versions.json to BunnyCDN.');
- }
- $file = file_get_contents($versions_location);
- $json = json_decode($file, true);
- $actual_version = data_get($json, 'coolify.v4.version');
-
- $confirmed = confirm("Are you sure you want to sync to {$actual_version}?");
- if (! $confirmed) {
- return;
- }
- Http::pool(fn (Pool $pool) => [
- $pool->storage(fileName: $versions_location)->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$versions"),
- $pool->purge("$bunny_cdn/$bunny_cdn_path/$versions"),
- ]);
- $this->info('versions.json uploaded & purged...');
-
- return;
- }
-
- Http::pool(fn (Pool $pool) => [
- $pool->storage(fileName: "$compose_file_location")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file"),
- $pool->storage(fileName: "$compose_file_prod_location")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file_prod"),
- $pool->storage(fileName: "$production_env_location")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$production_env"),
- $pool->storage(fileName: "$upgrade_script_location")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$upgrade_script"),
- $pool->storage(fileName: "$install_script_location")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$install_script"),
- ]);
- Http::pool(fn (Pool $pool) => [
- $pool->purge("$bunny_cdn/$bunny_cdn_path/$compose_file"),
- $pool->purge("$bunny_cdn/$bunny_cdn_path/$compose_file_prod"),
- $pool->purge("$bunny_cdn/$bunny_cdn_path/$production_env"),
- $pool->purge("$bunny_cdn/$bunny_cdn_path/$upgrade_script"),
- $pool->purge("$bunny_cdn/$bunny_cdn_path/$install_script"),
- ]);
- $this->info('All files uploaded & purged...');
- } catch (\Throwable $e) {
- $this->error('Error: '.$e->getMessage());
- }
- }
-}
diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php
deleted file mode 100644
index 122d72c396..0000000000
--- a/app/Console/Kernel.php
+++ /dev/null
@@ -1,312 +0,0 @@
-scheduleInstance = $schedule;
- $this->allServers = Server::where('ip', '!=', '1.2.3.4');
-
- $this->settings = instanceSettings();
- $this->updateCheckFrequency = $this->settings->update_check_frequency ?: '0 * * * *';
-
- $this->instanceTimezone = $this->settings->instance_timezone ?: config('app.timezone');
-
- if (validate_timezone($this->instanceTimezone) === false) {
- $this->instanceTimezone = config('app.timezone');
- }
-
- // $this->scheduleInstance->job(new CleanupStaleMultiplexedConnections)->hourly();
-
- if (isDev()) {
- // Instance Jobs
- $this->scheduleInstance->command('horizon:snapshot')->everyMinute();
- $this->scheduleInstance->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
- $this->scheduleInstance->job(new CheckHelperImageJob)->everyTenMinutes()->onOneServer();
-
- // Server Jobs
- $this->checkResources();
-
- $this->checkScheduledBackups();
- $this->checkScheduledTasks();
-
- $this->scheduleInstance->command('uploads:clear')->everyTwoMinutes();
-
- } else {
- // Instance Jobs
- $this->scheduleInstance->command('horizon:snapshot')->everyFiveMinutes();
- $this->scheduleInstance->command('cleanup:unreachable-servers')->daily()->onOneServer();
-
- $this->scheduleInstance->job(new PullTemplatesFromCDN)->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer();
-
- $this->scheduleInstance->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
- $this->scheduleUpdates();
-
- // Server Jobs
- $this->checkResources();
-
- $this->pullImages();
-
- $this->checkScheduledBackups();
- $this->checkScheduledTasks();
-
- $this->scheduleInstance->command('cleanup:database --yes')->daily();
- $this->scheduleInstance->command('uploads:clear')->everyTwoMinutes();
- }
- }
-
- private function pullImages(): void
- {
- if (isCloud()) {
- $servers = $this->allServers->whereRelation('team.subscription', 'stripe_invoice_paid', true)->whereRelation('settings', 'is_usable', true)->whereRelation('settings', 'is_reachable', true)->get();
- $own = Team::find(0)->servers;
- $servers = $servers->merge($own);
- } else {
- $servers = $this->allServers->whereRelation('settings', 'is_usable', true)->whereRelation('settings', 'is_reachable', true)->get();
- }
- foreach ($servers as $server) {
- try {
- if ($server->isSentinelEnabled()) {
- $this->scheduleInstance->job(function () use ($server) {
- CheckAndStartSentinelJob::dispatch($server);
- })->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer();
- }
- } catch (\Exception $e) {
- Log::error('Error pulling images: '.$e->getMessage());
- }
- }
- $this->scheduleInstance->job(new CheckHelperImageJob)
- ->cron($this->updateCheckFrequency)
- ->timezone($this->instanceTimezone)
- ->onOneServer();
- }
-
- private function scheduleUpdates(): void
- {
- $this->scheduleInstance->job(new CheckForUpdatesJob)
- ->cron($this->updateCheckFrequency)
- ->timezone($this->instanceTimezone)
- ->onOneServer();
-
- if ($this->settings->is_auto_update_enabled) {
- $autoUpdateFrequency = $this->settings->auto_update_frequency;
- $this->scheduleInstance->job(new UpdateCoolifyJob)
- ->cron($autoUpdateFrequency)
- ->timezone($this->instanceTimezone)
- ->onOneServer();
- }
- }
-
- private function checkResources(): void
- {
- if (isCloud()) {
- $servers = $this->allServers->whereRelation('team.subscription', 'stripe_invoice_paid', true)->get();
- $own = Team::find(0)->servers;
- $servers = $servers->merge($own);
- } else {
- $servers = $this->allServers->get();
- }
-
- foreach ($servers as $server) {
- try {
- $serverTimezone = data_get($server->settings, 'server_timezone', $this->instanceTimezone);
- if (validate_timezone($serverTimezone) === false) {
- $serverTimezone = config('app.timezone');
- }
-
- // Sentinel check
- $lastSentinelUpdate = $server->sentinel_updated_at;
- if (Carbon::parse($lastSentinelUpdate)->isBefore(now()->subSeconds($server->waitBeforeDoingSshCheck()))) {
- // Check container status every minute if Sentinel does not activated
- if (isCloud()) {
- $this->scheduleInstance->job(new ServerCheckJob($server))->timezone($serverTimezone)->everyFiveMinutes()->onOneServer();
- } else {
- $this->scheduleInstance->job(new ServerCheckJob($server))->timezone($serverTimezone)->everyMinute()->onOneServer();
- }
- // $this->scheduleInstance->job(new \App\Jobs\ServerCheckNewJob($server))->everyFiveMinutes()->onOneServer();
-
- $serverDiskUsageCheckFrequency = data_get($server->settings, 'server_disk_usage_check_frequency', '0 * * * *');
- if (isset(VALID_CRON_STRINGS[$serverDiskUsageCheckFrequency])) {
- $serverDiskUsageCheckFrequency = VALID_CRON_STRINGS[$serverDiskUsageCheckFrequency];
- }
- $this->scheduleInstance->job(new ServerStorageCheckJob($server))->cron($serverDiskUsageCheckFrequency)->timezone($serverTimezone)->onOneServer();
- }
-
- $dockerCleanupFrequency = data_get($server->settings, 'docker_cleanup_frequency', '0 * * * *');
- if (isset(VALID_CRON_STRINGS[$dockerCleanupFrequency])) {
- $dockerCleanupFrequency = VALID_CRON_STRINGS[$dockerCleanupFrequency];
- }
- $this->scheduleInstance->job(new DockerCleanupJob($server))->cron($dockerCleanupFrequency)->timezone($serverTimezone)->onOneServer();
-
- // Cleanup multiplexed connections every hour
- // $this->scheduleInstance->job(new ServerCleanupMux($server))->hourly()->onOneServer();
-
- // Temporary solution until we have better memory management for Sentinel
- if ($server->isSentinelEnabled()) {
- $this->scheduleInstance->job(function () use ($server) {
- $server->restartContainer('coolify-sentinel');
- })->daily()->onOneServer();
- }
- } catch (\Exception $e) {
- Log::error('Error checking resources: '.$e->getMessage());
- }
- }
- }
-
- private function checkScheduledBackups(): void
- {
- $scheduled_backups = ScheduledDatabaseBackup::where('enabled', true)->get();
- if ($scheduled_backups->isEmpty()) {
- return;
- }
- $finalScheduledBackups = collect();
- foreach ($scheduled_backups as $scheduled_backup) {
- if (blank(data_get($scheduled_backup, 'database'))) {
- $scheduled_backup->delete();
-
- continue;
- }
- $server = $scheduled_backup->server();
- if (blank($server)) {
- $scheduled_backup->delete();
-
- continue;
- }
- if ($server->isFunctional() === false) {
- continue;
- }
- if (isCloud() && data_get($server->team->subscription, 'stripe_invoice_paid', false) === false && $server->team->id !== 0) {
- continue;
- }
- $finalScheduledBackups->push($scheduled_backup);
- }
-
- foreach ($finalScheduledBackups as $scheduled_backup) {
- try {
- if (isset(VALID_CRON_STRINGS[$scheduled_backup->frequency])) {
- $scheduled_backup->frequency = VALID_CRON_STRINGS[$scheduled_backup->frequency];
- }
- $server = $scheduled_backup->server();
- $serverTimezone = data_get($server->settings, 'server_timezone', $this->instanceTimezone);
-
- if (validate_timezone($serverTimezone) === false) {
- $serverTimezone = config('app.timezone');
- }
-
- if (isset(VALID_CRON_STRINGS[$scheduled_backup->frequency])) {
- $scheduled_backup->frequency = VALID_CRON_STRINGS[$scheduled_backup->frequency];
- }
- $serverTimezone = data_get($server->settings, 'server_timezone', $this->instanceTimezone);
- $this->scheduleInstance->job(new DatabaseBackupJob(
- backup: $scheduled_backup
- ))->cron($scheduled_backup->frequency)->timezone($serverTimezone)->onOneServer();
- } catch (\Exception $e) {
- Log::error('Error scheduling backup: '.$e->getMessage());
- Log::error($e->getTraceAsString());
- }
- }
- }
-
- private function checkScheduledTasks(): void
- {
- $scheduled_tasks = ScheduledTask::where('enabled', true)->get();
- if ($scheduled_tasks->isEmpty()) {
- return;
- }
- $finalScheduledTasks = collect();
- foreach ($scheduled_tasks as $scheduled_task) {
- $service = $scheduled_task->service;
- $application = $scheduled_task->application;
-
- $server = $scheduled_task->server();
- if (blank($server)) {
- $scheduled_task->delete();
-
- continue;
- }
-
- if ($server->isFunctional() === false) {
- continue;
- }
-
- if (isCloud() && data_get($server->team->subscription, 'stripe_invoice_paid', false) === false && $server->team->id !== 0) {
- continue;
- }
-
- if (! $service && ! $application) {
- $scheduled_task->delete();
-
- continue;
- }
-
- if ($application && str($application->status)->contains('running') === false) {
- continue;
- }
- if ($service && str($service->status)->contains('running') === false) {
- continue;
- }
-
- $finalScheduledTasks->push($scheduled_task);
- }
-
- foreach ($finalScheduledTasks as $scheduled_task) {
- try {
- $server = $scheduled_task->server();
- if (isset(VALID_CRON_STRINGS[$scheduled_task->frequency])) {
- $scheduled_task->frequency = VALID_CRON_STRINGS[$scheduled_task->frequency];
- }
- $serverTimezone = data_get($server->settings, 'server_timezone', $this->instanceTimezone);
-
- if (validate_timezone($serverTimezone) === false) {
- $serverTimezone = config('app.timezone');
- }
- $this->scheduleInstance->job(new ScheduledTaskJob(
- task: $scheduled_task
- ))->cron($scheduled_task->frequency)->timezone($serverTimezone)->onOneServer();
- } catch (\Exception $e) {
- Log::error('Error scheduling task: '.$e->getMessage());
- Log::error($e->getTraceAsString());
- }
- }
- }
-
- protected function commands(): void
- {
- $this->load(__DIR__.'/Commands');
-
- require base_path('routes/console.php');
- }
-}
diff --git a/app/Contracts/CustomJobRepositoryInterface.php b/app/Contracts/CustomJobRepositoryInterface.php
deleted file mode 100644
index 1fbd71f464..0000000000
--- a/app/Contracts/CustomJobRepositoryInterface.php
+++ /dev/null
@@ -1,19 +0,0 @@
-status = ProcessStatus::QUEUED->value;
- }
- }
-}
diff --git a/app/Data/ServerMetadata.php b/app/Data/ServerMetadata.php
deleted file mode 100644
index d95944b15a..0000000000
--- a/app/Data/ServerMetadata.php
+++ /dev/null
@@ -1,15 +0,0 @@
- 1,
- self::ADMIN => 2,
- self::OWNER => 3,
- };
- }
-
- public function lt(Role|string $role): bool
- {
- if (is_string($role)) {
- $role = Role::from($role);
- }
-
- return $this->rank() < $role->rank();
- }
-
- public function gt(Role|string $role): bool
- {
- if (is_string($role)) {
- $role = Role::from($role);
- }
-
- return $this->rank() > $role->rank();
- }
-}
diff --git a/app/Enums/StaticImageTypes.php b/app/Enums/StaticImageTypes.php
deleted file mode 100644
index 5f5304bf87..0000000000
--- a/app/Enums/StaticImageTypes.php
+++ /dev/null
@@ -1,8 +0,0 @@
-user()->currentTeam()->id ?? null;
- }
- if (is_null($teamId)) {
- throw new \Exception('Team id is null');
- }
- $this->teamId = $teamId;
- }
-
- public function broadcastOn(): array
- {
- return [
- new PrivateChannel("team.{$this->teamId}"),
- ];
- }
-}
diff --git a/app/Events/BackupCreated.php b/app/Events/BackupCreated.php
deleted file mode 100644
index 45b2aacb7a..0000000000
--- a/app/Events/BackupCreated.php
+++ /dev/null
@@ -1,34 +0,0 @@
-user()->currentTeam()->id ?? null;
- }
- if (is_null($teamId)) {
- throw new \Exception('Team id is null');
- }
- $this->teamId = $teamId;
- }
-
- public function broadcastOn(): array
- {
- return [
- new PrivateChannel("team.{$this->teamId}"),
- ];
- }
-}
diff --git a/app/Events/CloudflareTunnelConfigured.php b/app/Events/CloudflareTunnelConfigured.php
deleted file mode 100644
index 3d7076d0da..0000000000
--- a/app/Events/CloudflareTunnelConfigured.php
+++ /dev/null
@@ -1,34 +0,0 @@
-user()->currentTeam()->id ?? null;
- }
- if (is_null($teamId)) {
- throw new \Exception('Team id is null');
- }
- $this->teamId = $teamId;
- }
-
- public function broadcastOn(): array
- {
- return [
- new PrivateChannel("team.{$this->teamId}"),
- ];
- }
-}
diff --git a/app/Events/DatabaseProxyStopped.php b/app/Events/DatabaseProxyStopped.php
deleted file mode 100644
index 96b35a5cac..0000000000
--- a/app/Events/DatabaseProxyStopped.php
+++ /dev/null
@@ -1,35 +0,0 @@
-currentTeam()?->id ?? null;
- }
- if (is_null($teamId)) {
- throw new \Exception('Team id is null');
- }
- $this->teamId = $teamId;
- }
-
- public function broadcastOn(): array
- {
- return [
- new PrivateChannel("team.{$this->teamId}"),
- ];
- }
-}
diff --git a/app/Events/DatabaseStatusChanged.php b/app/Events/DatabaseStatusChanged.php
deleted file mode 100644
index 913b21bc22..0000000000
--- a/app/Events/DatabaseStatusChanged.php
+++ /dev/null
@@ -1,40 +0,0 @@
-userId = $userId;
- }
-
- public function broadcastOn(): ?array
- {
- if (! is_null($this->userId)) {
- return [
- new PrivateChannel("user.{$this->userId}"),
- ];
- }
-
- return null;
- }
-}
diff --git a/app/Events/DockerCleanupDone.php b/app/Events/DockerCleanupDone.php
deleted file mode 100644
index 2bd7fee198..0000000000
--- a/app/Events/DockerCleanupDone.php
+++ /dev/null
@@ -1,24 +0,0 @@
-execution->server->team->id),
- ];
- }
-}
diff --git a/app/Events/FileStorageChanged.php b/app/Events/FileStorageChanged.php
deleted file mode 100644
index 57004cf4c3..0000000000
--- a/app/Events/FileStorageChanged.php
+++ /dev/null
@@ -1,31 +0,0 @@
-teamId = $teamId;
- }
-
- public function broadcastOn(): array
- {
- return [
- new PrivateChannel("team.{$this->teamId}"),
- ];
- }
-}
diff --git a/app/Events/ProxyStarted.php b/app/Events/ProxyStarted.php
deleted file mode 100644
index 64d562e0a6..0000000000
--- a/app/Events/ProxyStarted.php
+++ /dev/null
@@ -1,14 +0,0 @@
-user()->currentTeam()->id ?? null;
- }
- if (is_null($teamId)) {
- throw new \Exception('Team id is null');
- }
- $this->teamId = $teamId;
- }
-
- public function broadcastOn(): array
- {
- return [
- new PrivateChannel("team.{$this->teamId}"),
- ];
- }
-}
diff --git a/app/Events/RestoreJobFinished.php b/app/Events/RestoreJobFinished.php
deleted file mode 100644
index d3adb77984..0000000000
--- a/app/Events/RestoreJobFinished.php
+++ /dev/null
@@ -1,34 +0,0 @@
-startsWith('/tmp/')
- && str($scriptPath)->startsWith('/tmp/')
- && ! str($tmpPath)->contains('..')
- && ! str($scriptPath)->contains('..')
- && strlen($tmpPath) > 5 // longer than just "/tmp/"
- && strlen($scriptPath) > 5
- ) {
- $commands[] = "docker exec {$container} sh -c 'rm {$scriptPath}'";
- $commands[] = "docker exec {$container} sh -c 'rm {$tmpPath}'";
- instant_remote_process($commands, Server::find($serverId), throwError: true);
- }
- }
- }
-}
diff --git a/app/Events/ScheduledTaskDone.php b/app/Events/ScheduledTaskDone.php
deleted file mode 100644
index c8b5547f61..0000000000
--- a/app/Events/ScheduledTaskDone.php
+++ /dev/null
@@ -1,34 +0,0 @@
-user()->currentTeam()->id ?? null;
- }
- if (is_null($teamId)) {
- throw new \Exception('Team id is null');
- }
- $this->teamId = $teamId;
- }
-
- public function broadcastOn(): array
- {
- return [
- new PrivateChannel("team.{$this->teamId}"),
- ];
- }
-}
diff --git a/app/Events/ServerReachabilityChanged.php b/app/Events/ServerReachabilityChanged.php
deleted file mode 100644
index fb4680146c..0000000000
--- a/app/Events/ServerReachabilityChanged.php
+++ /dev/null
@@ -1,17 +0,0 @@
-server->isReachableChanged();
- }
-}
diff --git a/app/Events/ServiceStatusChanged.php b/app/Events/ServiceStatusChanged.php
deleted file mode 100644
index 3950022e10..0000000000
--- a/app/Events/ServiceStatusChanged.php
+++ /dev/null
@@ -1,39 +0,0 @@
-userId = $userId;
- }
-
- public function broadcastOn(): ?array
- {
- if (! is_null($this->userId)) {
- return [
- new PrivateChannel("user.{$this->userId}"),
- ];
- }
-
- return null;
- }
-}
diff --git a/app/Events/TestEvent.php b/app/Events/TestEvent.php
deleted file mode 100644
index 2cc6683dc2..0000000000
--- a/app/Events/TestEvent.php
+++ /dev/null
@@ -1,28 +0,0 @@
-teamId = auth()->user()->currentTeam()->id;
- }
-
- public function broadcastOn(): array
- {
- return [
- new PrivateChannel("team.{$this->teamId}"),
- ];
- }
-}
diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php
deleted file mode 100644
index 8c89bb07f9..0000000000
--- a/app/Exceptions/Handler.php
+++ /dev/null
@@ -1,90 +0,0 @@
-, \Psr\Log\LogLevel::*>
- */
- protected $levels = [
- //
- ];
-
- /**
- * A list of the exception types that are not reported.
- *
- * @var array>
- */
- protected $dontReport = [
- ProcessException::class,
- ];
-
- /**
- * A list of the inputs that are never flashed to the session on validation exceptions.
- *
- * @var array
- */
- protected $dontFlash = [
- 'current_password',
- 'password',
- 'password_confirmation',
- ];
-
- private InstanceSettings $settings;
-
- protected function unauthenticated($request, AuthenticationException $exception)
- {
- if ($request->is('api/*') || $request->expectsJson() || $this->shouldReturnJson($request, $exception)) {
- return response()->json(['message' => $exception->getMessage()], 401);
- }
-
- return redirect()->guest($exception->redirectTo($request) ?? route('login'));
- }
-
- /**
- * Register the exception handling callbacks for the application.
- */
- public function register(): void
- {
- $this->reportable(function (Throwable $e) {
- if (isDev()) {
- return;
- }
- if ($e instanceof RuntimeException) {
- return;
- }
- $this->settings = instanceSettings();
- if ($this->settings->do_not_track) {
- return;
- }
- app('sentry')->configureScope(
- function (Scope $scope) {
- $email = auth()?->user() ? auth()->user()->email : 'guest';
- $instanceAdmin = User::find(0)->email ?? 'admin@localhost';
- $scope->setUser(
- [
- 'email' => $email,
- 'instanceAdmin' => $instanceAdmin,
- ]
- );
- }
- );
- if (str($e->getMessage())->contains('No space left on device')) {
- return;
- }
- Integration::captureUnhandledException($e);
- });
- }
-}
diff --git a/app/Exceptions/ProcessException.php b/app/Exceptions/ProcessException.php
deleted file mode 100644
index 47eaa6fd81..0000000000
--- a/app/Exceptions/ProcessException.php
+++ /dev/null
@@ -1,7 +0,0 @@
-private_key_id);
- $sshKeyLocation = $privateKey->getKeyLocation();
- $muxFilename = '/var/www/html/storage/app/ssh/mux/mux_'.$server->uuid;
-
- return [
- 'sshKeyLocation' => $sshKeyLocation,
- 'muxFilename' => $muxFilename,
- ];
- }
-
- public static function ensureMultiplexedConnection(Server $server): bool
- {
- if (! self::isMultiplexingEnabled()) {
- return false;
- }
-
- $sshConfig = self::serverSshConfiguration($server);
- $muxSocket = $sshConfig['muxFilename'];
-
- $checkCommand = "ssh -O check -o ControlPath=$muxSocket ";
- if (data_get($server, 'settings.is_cloudflare_tunnel')) {
- $checkCommand .= '-o ProxyCommand="cloudflared access ssh --hostname %h" ';
- }
- $checkCommand .= "{$server->user}@{$server->ip}";
- $process = Process::run($checkCommand);
-
- if ($process->exitCode() !== 0) {
- return self::establishNewMultiplexedConnection($server);
- }
-
- return true;
- }
-
- public static function establishNewMultiplexedConnection(Server $server): bool
- {
- $sshConfig = self::serverSshConfiguration($server);
- $sshKeyLocation = $sshConfig['sshKeyLocation'];
- $muxSocket = $sshConfig['muxFilename'];
- $connectionTimeout = config('constants.ssh.connection_timeout');
- $serverInterval = config('constants.ssh.server_interval');
- $muxPersistTime = config('constants.ssh.mux_persist_time');
-
- $establishCommand = "ssh -fNM -o ControlMaster=auto -o ControlPath=$muxSocket -o ControlPersist={$muxPersistTime} ";
-
- if (data_get($server, 'settings.is_cloudflare_tunnel')) {
- $establishCommand .= ' -o ProxyCommand="cloudflared access ssh --hostname %h" ';
- }
- $establishCommand .= self::getCommonSshOptions($server, $sshKeyLocation, $connectionTimeout, $serverInterval);
- $establishCommand .= "{$server->user}@{$server->ip}";
- $establishProcess = Process::run($establishCommand);
- if ($establishProcess->exitCode() !== 0) {
- return false;
- }
-
- return true;
- }
-
- public static function removeMuxFile(Server $server)
- {
- $sshConfig = self::serverSshConfiguration($server);
- $muxSocket = $sshConfig['muxFilename'];
-
- $closeCommand = "ssh -O exit -o ControlPath=$muxSocket ";
- if (data_get($server, 'settings.is_cloudflare_tunnel')) {
- $closeCommand .= '-o ProxyCommand="cloudflared access ssh --hostname %h" ';
- }
- $closeCommand .= "{$server->user}@{$server->ip}";
- Process::run($closeCommand);
- }
-
- public static function generateScpCommand(Server $server, string $source, string $dest)
- {
- $sshConfig = self::serverSshConfiguration($server);
- $sshKeyLocation = $sshConfig['sshKeyLocation'];
- $muxSocket = $sshConfig['muxFilename'];
-
- $timeout = config('constants.ssh.command_timeout');
- $muxPersistTime = config('constants.ssh.mux_persist_time');
-
- $scp_command = "timeout $timeout scp ";
- if ($server->isIpv6()) {
- $scp_command .= '-6 ';
- }
- if (self::isMultiplexingEnabled() && self::ensureMultiplexedConnection($server)) {
- $scp_command .= "-o ControlMaster=auto -o ControlPath=$muxSocket -o ControlPersist={$muxPersistTime} ";
- }
-
- if (data_get($server, 'settings.is_cloudflare_tunnel')) {
- $scp_command .= '-o ProxyCommand="cloudflared access ssh --hostname %h" ';
- }
-
- $scp_command .= self::getCommonSshOptions($server, $sshKeyLocation, config('constants.ssh.connection_timeout'), config('constants.ssh.server_interval'), isScp: true);
- $scp_command .= "{$source} {$server->user}@{$server->ip}:{$dest}";
-
- return $scp_command;
- }
-
- public static function generateSshCommand(Server $server, string $command)
- {
- if ($server->settings->force_disabled) {
- throw new \RuntimeException('Server is disabled.');
- }
-
- $sshConfig = self::serverSshConfiguration($server);
- $sshKeyLocation = $sshConfig['sshKeyLocation'];
-
- self::validateSshKey($server->privateKey);
-
- $muxSocket = $sshConfig['muxFilename'];
-
- $timeout = config('constants.ssh.command_timeout');
- $muxPersistTime = config('constants.ssh.mux_persist_time');
-
- $ssh_command = "timeout $timeout ssh ";
-
- if (self::isMultiplexingEnabled() && self::ensureMultiplexedConnection($server)) {
- $ssh_command .= "-o ControlMaster=auto -o ControlPath=$muxSocket -o ControlPersist={$muxPersistTime} ";
- }
-
- if (data_get($server, 'settings.is_cloudflare_tunnel')) {
- $ssh_command .= "-o ProxyCommand='cloudflared access ssh --hostname %h' ";
- }
-
- $ssh_command .= self::getCommonSshOptions($server, $sshKeyLocation, config('constants.ssh.connection_timeout'), config('constants.ssh.server_interval'));
-
- $delimiter = Hash::make($command);
- $delimiter = base64_encode($delimiter);
- $command = str_replace($delimiter, '', $command);
-
- $ssh_command .= "{$server->user}@{$server->ip} 'bash -se' << \\$delimiter".PHP_EOL
- .$command.PHP_EOL
- .$delimiter;
-
- return $ssh_command;
- }
-
- private static function isMultiplexingEnabled(): bool
- {
- return config('constants.ssh.mux_enabled') && ! config('constants.coolify.is_windows_docker_desktop');
- }
-
- private static function validateSshKey(PrivateKey $privateKey): void
- {
- $keyLocation = $privateKey->getKeyLocation();
- $checkKeyCommand = "ls $keyLocation 2>/dev/null";
- $keyCheckProcess = Process::run($checkKeyCommand);
-
- if ($keyCheckProcess->exitCode() !== 0) {
- $privateKey->storeInFileSystem();
- }
- }
-
- private static function getCommonSshOptions(Server $server, string $sshKeyLocation, int $connectionTimeout, int $serverInterval, bool $isScp = false): string
- {
- $options = "-i {$sshKeyLocation} "
- .'-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null '
- .'-o PasswordAuthentication=no '
- ."-o ConnectTimeout=$connectionTimeout "
- ."-o ServerAliveInterval=$serverInterval "
- .'-o RequestTTY=no '
- .'-o LogLevel=ERROR ';
-
- // Bruh
- if ($isScp) {
- $options .= "-P {$server->port} ";
- } else {
- $options .= "-p {$server->port} ";
- }
-
- return $options;
- }
-}
diff --git a/app/Http/Controllers/Api/ApplicationsController.php b/app/Http/Controllers/Api/ApplicationsController.php
deleted file mode 100644
index aef19af23c..0000000000
--- a/app/Http/Controllers/Api/ApplicationsController.php
+++ /dev/null
@@ -1,3056 +0,0 @@
-makeHidden([
- 'id',
- 'resourceable',
- 'resourceable_id',
- 'resourceable_type',
- ]);
- if (request()->attributes->get('can_read_sensitive', false) === false) {
- $application->makeHidden([
- 'custom_labels',
- 'dockerfile',
- 'docker_compose',
- 'docker_compose_raw',
- 'manual_webhook_secret_bitbucket',
- 'manual_webhook_secret_gitea',
- 'manual_webhook_secret_github',
- 'manual_webhook_secret_gitlab',
- 'private_key_id',
- 'value',
- 'real_value',
- ]);
- }
-
- return serializeApiResponse($application);
- }
-
- #[OA\Get(
- summary: 'List',
- description: 'List all applications.',
- path: '/applications',
- operationId: 'list-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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $projects = Project::where('team_id', $teamId)->get();
- $applications = collect();
- $applications->push($projects->pluck('applications')->flatten());
- $applications = $applications->flatten();
- $applications = $applications->map(function ($application) {
- return $this->removeSensitiveData($application);
- });
-
- return response()->json($applications);
- }
-
- #[OA\Post(
- summary: 'Create (Public)',
- description: 'Create new application based on a public git repository.',
- path: '/applications/public',
- operationId: 'create-public-application',
- 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: ['project_uuid', 'server_uuid', 'environment_name', 'environment_uuid', 'git_repository', 'git_branch', 'build_pack', 'ports_exposes'],
- properties: [
- 'project_uuid' => ['type' => 'string', 'description' => 'The project UUID.'],
- 'server_uuid' => ['type' => 'string', 'description' => 'The server UUID.'],
- 'environment_name' => ['type' => 'string', 'description' => 'The environment name. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'],
- 'git_repository' => ['type' => 'string', 'description' => 'The git repository URL.'],
- 'git_branch' => ['type' => 'string', 'description' => 'The git branch.'],
- 'build_pack' => ['type' => 'string', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose'], 'description' => 'The build pack type.'],
- 'ports_exposes' => ['type' => 'string', 'description' => 'The ports to expose.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
- 'name' => ['type' => 'string', 'description' => 'The application name.'],
- 'description' => ['type' => 'string', 'description' => 'The application description.'],
- 'domains' => ['type' => 'string', 'description' => 'The application domains.'],
- '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_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
- 'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
- 'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
- 'install_command' => ['type' => 'string', 'description' => 'The install command.'],
- 'build_command' => ['type' => 'string', 'description' => 'The build command.'],
- 'start_command' => ['type' => 'string', 'description' => 'The start command.'],
- 'ports_mappings' => ['type' => 'string', 'description' => 'The ports mappings.'],
- 'base_directory' => ['type' => 'string', 'description' => 'The base directory for all commands.'],
- 'publish_directory' => ['type' => 'string', 'description' => 'The publish directory.'],
- 'health_check_enabled' => ['type' => 'boolean', 'description' => 'Health check enabled.'],
- 'health_check_path' => ['type' => 'string', 'description' => 'Health check path.'],
- 'health_check_port' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check port.'],
- 'health_check_host' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check host.'],
- 'health_check_method' => ['type' => 'string', 'description' => 'Health check method.'],
- 'health_check_return_code' => ['type' => 'integer', 'description' => 'Health check return code.'],
- 'health_check_scheme' => ['type' => 'string', 'description' => 'Health check scheme.'],
- 'health_check_response_text' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check response text.'],
- 'health_check_interval' => ['type' => 'integer', 'description' => 'Health check interval in seconds.'],
- 'health_check_timeout' => ['type' => 'integer', 'description' => 'Health check timeout in seconds.'],
- 'health_check_retries' => ['type' => 'integer', 'description' => 'Health check retries count.'],
- 'health_check_start_period' => ['type' => 'integer', 'description' => 'Health check start period in seconds.'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit.'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit.'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness.'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation.'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit.'],
- 'limits_cpuset' => ['type' => 'string', 'nullable' => true, 'description' => 'CPU set.'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares.'],
- 'custom_labels' => ['type' => 'string', 'description' => 'Custom labels.'],
- 'custom_docker_run_options' => ['type' => 'string', 'description' => 'Custom docker run options.'],
- 'post_deployment_command' => ['type' => 'string', 'description' => 'Post deployment command.'],
- 'post_deployment_command_container' => ['type' => 'string', 'description' => 'Post deployment command container.'],
- 'pre_deployment_command' => ['type' => 'string', 'description' => 'Pre deployment command.'],
- 'pre_deployment_command_container' => ['type' => 'string', 'description' => 'Pre deployment command container.'],
- 'manual_webhook_secret_github' => ['type' => 'string', 'description' => 'Manual webhook secret for Github.'],
- 'manual_webhook_secret_gitlab' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitlab.'],
- 'manual_webhook_secret_bitbucket' => ['type' => 'string', 'description' => 'Manual webhook secret for Bitbucket.'],
- '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']],
- // '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.'],
- 'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
- 'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
- 'docker_compose_raw' => ['type' => 'string', 'description' => 'The Docker Compose raw content.'],
- '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_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
- 'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
- 'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
- ],
- )
- ),
- ]
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Application created successfully.',
- 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_public_application(Request $request)
- {
- return $this->create_application($request, 'public');
- }
-
- #[OA\Post(
- summary: 'Create (Private - GH App)',
- description: 'Create new application based on a private repository through a Github App.',
- path: '/applications/private-github-app',
- operationId: 'create-private-github-app-application',
- 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: ['project_uuid', 'server_uuid', 'environment_name', 'environment_uuid', 'github_app_uuid', 'git_repository', 'git_branch', 'build_pack', 'ports_exposes'],
- properties: [
- 'project_uuid' => ['type' => 'string', 'description' => 'The project UUID.'],
- 'server_uuid' => ['type' => 'string', 'description' => 'The server UUID.'],
- 'environment_name' => ['type' => 'string', 'description' => 'The environment name. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'],
- 'github_app_uuid' => ['type' => 'string', 'description' => 'The Github App UUID.'],
- 'git_repository' => ['type' => 'string', 'description' => 'The git repository URL.'],
- 'git_branch' => ['type' => 'string', 'description' => 'The git branch.'],
- 'ports_exposes' => ['type' => 'string', 'description' => 'The ports to expose.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
- 'build_pack' => ['type' => 'string', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose'], 'description' => 'The build pack type.'],
- 'name' => ['type' => 'string', 'description' => 'The application name.'],
- 'description' => ['type' => 'string', 'description' => 'The application description.'],
- 'domains' => ['type' => 'string', 'description' => 'The application domains.'],
- '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_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
- 'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
- 'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
- 'install_command' => ['type' => 'string', 'description' => 'The install command.'],
- 'build_command' => ['type' => 'string', 'description' => 'The build command.'],
- 'start_command' => ['type' => 'string', 'description' => 'The start command.'],
- 'ports_mappings' => ['type' => 'string', 'description' => 'The ports mappings.'],
- 'base_directory' => ['type' => 'string', 'description' => 'The base directory for all commands.'],
- 'publish_directory' => ['type' => 'string', 'description' => 'The publish directory.'],
- 'health_check_enabled' => ['type' => 'boolean', 'description' => 'Health check enabled.'],
- 'health_check_path' => ['type' => 'string', 'description' => 'Health check path.'],
- 'health_check_port' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check port.'],
- 'health_check_host' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check host.'],
- 'health_check_method' => ['type' => 'string', 'description' => 'Health check method.'],
- 'health_check_return_code' => ['type' => 'integer', 'description' => 'Health check return code.'],
- 'health_check_scheme' => ['type' => 'string', 'description' => 'Health check scheme.'],
- 'health_check_response_text' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check response text.'],
- 'health_check_interval' => ['type' => 'integer', 'description' => 'Health check interval in seconds.'],
- 'health_check_timeout' => ['type' => 'integer', 'description' => 'Health check timeout in seconds.'],
- 'health_check_retries' => ['type' => 'integer', 'description' => 'Health check retries count.'],
- 'health_check_start_period' => ['type' => 'integer', 'description' => 'Health check start period in seconds.'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit.'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit.'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness.'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation.'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit.'],
- 'limits_cpuset' => ['type' => 'string', 'nullable' => true, 'description' => 'CPU set.'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares.'],
- 'custom_labels' => ['type' => 'string', 'description' => 'Custom labels.'],
- 'custom_docker_run_options' => ['type' => 'string', 'description' => 'Custom docker run options.'],
- 'post_deployment_command' => ['type' => 'string', 'description' => 'Post deployment command.'],
- 'post_deployment_command_container' => ['type' => 'string', 'description' => 'Post deployment command container.'],
- 'pre_deployment_command' => ['type' => 'string', 'description' => 'Pre deployment command.'],
- 'pre_deployment_command_container' => ['type' => 'string', 'description' => 'Pre deployment command container.'],
- 'manual_webhook_secret_github' => ['type' => 'string', 'description' => 'Manual webhook secret for Github.'],
- 'manual_webhook_secret_gitlab' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitlab.'],
- 'manual_webhook_secret_bitbucket' => ['type' => 'string', 'description' => 'Manual webhook secret for Bitbucket.'],
- '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']],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
- 'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
- 'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
- 'docker_compose_raw' => ['type' => 'string', 'description' => 'The Docker Compose raw content.'],
- '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_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
- 'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
- 'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
- ],
- )
- ),
- ]
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Application created successfully.',
- 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_private_gh_app_application(Request $request)
- {
- return $this->create_application($request, 'private-gh-app');
- }
-
- #[OA\Post(
- summary: 'Create (Private - Deploy Key)',
- description: 'Create new application based on a private repository through a Deploy Key.',
- path: '/applications/private-deploy-key',
- operationId: 'create-private-deploy-key-application',
- 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: ['project_uuid', 'server_uuid', 'environment_name', 'environment_uuid', 'private_key_uuid', 'git_repository', 'git_branch', 'build_pack', 'ports_exposes'],
- properties: [
- 'project_uuid' => ['type' => 'string', 'description' => 'The project UUID.'],
- 'server_uuid' => ['type' => 'string', 'description' => 'The server UUID.'],
- 'environment_name' => ['type' => 'string', 'description' => 'The environment name. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'],
- 'private_key_uuid' => ['type' => 'string', 'description' => 'The private key UUID.'],
- 'git_repository' => ['type' => 'string', 'description' => 'The git repository URL.'],
- 'git_branch' => ['type' => 'string', 'description' => 'The git branch.'],
- 'ports_exposes' => ['type' => 'string', 'description' => 'The ports to expose.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
- 'build_pack' => ['type' => 'string', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose'], 'description' => 'The build pack type.'],
- 'name' => ['type' => 'string', 'description' => 'The application name.'],
- 'description' => ['type' => 'string', 'description' => 'The application description.'],
- 'domains' => ['type' => 'string', 'description' => 'The application domains.'],
- '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_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
- 'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
- 'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
- 'install_command' => ['type' => 'string', 'description' => 'The install command.'],
- 'build_command' => ['type' => 'string', 'description' => 'The build command.'],
- 'start_command' => ['type' => 'string', 'description' => 'The start command.'],
- 'ports_mappings' => ['type' => 'string', 'description' => 'The ports mappings.'],
- 'base_directory' => ['type' => 'string', 'description' => 'The base directory for all commands.'],
- 'publish_directory' => ['type' => 'string', 'description' => 'The publish directory.'],
- 'health_check_enabled' => ['type' => 'boolean', 'description' => 'Health check enabled.'],
- 'health_check_path' => ['type' => 'string', 'description' => 'Health check path.'],
- 'health_check_port' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check port.'],
- 'health_check_host' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check host.'],
- 'health_check_method' => ['type' => 'string', 'description' => 'Health check method.'],
- 'health_check_return_code' => ['type' => 'integer', 'description' => 'Health check return code.'],
- 'health_check_scheme' => ['type' => 'string', 'description' => 'Health check scheme.'],
- 'health_check_response_text' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check response text.'],
- 'health_check_interval' => ['type' => 'integer', 'description' => 'Health check interval in seconds.'],
- 'health_check_timeout' => ['type' => 'integer', 'description' => 'Health check timeout in seconds.'],
- 'health_check_retries' => ['type' => 'integer', 'description' => 'Health check retries count.'],
- 'health_check_start_period' => ['type' => 'integer', 'description' => 'Health check start period in seconds.'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit.'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit.'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness.'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation.'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit.'],
- 'limits_cpuset' => ['type' => 'string', 'nullable' => true, 'description' => 'CPU set.'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares.'],
- 'custom_labels' => ['type' => 'string', 'description' => 'Custom labels.'],
- 'custom_docker_run_options' => ['type' => 'string', 'description' => 'Custom docker run options.'],
- 'post_deployment_command' => ['type' => 'string', 'description' => 'Post deployment command.'],
- 'post_deployment_command_container' => ['type' => 'string', 'description' => 'Post deployment command container.'],
- 'pre_deployment_command' => ['type' => 'string', 'description' => 'Pre deployment command.'],
- 'pre_deployment_command_container' => ['type' => 'string', 'description' => 'Pre deployment command container.'],
- 'manual_webhook_secret_github' => ['type' => 'string', 'description' => 'Manual webhook secret for Github.'],
- 'manual_webhook_secret_gitlab' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitlab.'],
- 'manual_webhook_secret_bitbucket' => ['type' => 'string', 'description' => 'Manual webhook secret for Bitbucket.'],
- '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']],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
- 'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
- 'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
- 'docker_compose_raw' => ['type' => 'string', 'description' => 'The Docker Compose raw content.'],
- '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_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
- 'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
- 'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
- ],
- )
- ),
- ]
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Application created successfully.',
- 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_private_deploy_key_application(Request $request)
- {
- return $this->create_application($request, 'private-deploy-key');
- }
-
- #[OA\Post(
- summary: 'Create (Dockerfile)',
- description: 'Create new application based on a simple Dockerfile.',
- path: '/applications/dockerfile',
- operationId: 'create-dockerfile-application',
- 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: ['project_uuid', 'server_uuid', 'environment_name', 'environment_uuid', 'dockerfile'],
- properties: [
- 'project_uuid' => ['type' => 'string', 'description' => 'The project UUID.'],
- 'server_uuid' => ['type' => 'string', 'description' => 'The server UUID.'],
- 'environment_name' => ['type' => 'string', 'description' => 'The environment name. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'],
- 'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
- 'build_pack' => ['type' => 'string', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose'], 'description' => 'The build pack type.'],
- 'ports_exposes' => ['type' => 'string', 'description' => 'The ports to expose.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
- 'name' => ['type' => 'string', 'description' => 'The application name.'],
- 'description' => ['type' => 'string', 'description' => 'The application description.'],
- 'domains' => ['type' => 'string', 'description' => 'The application domains.'],
- 'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
- 'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
- 'ports_mappings' => ['type' => 'string', 'description' => 'The ports mappings.'],
- 'base_directory' => ['type' => 'string', 'description' => 'The base directory for all commands.'],
- 'health_check_enabled' => ['type' => 'boolean', 'description' => 'Health check enabled.'],
- 'health_check_path' => ['type' => 'string', 'description' => 'Health check path.'],
- 'health_check_port' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check port.'],
- 'health_check_host' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check host.'],
- 'health_check_method' => ['type' => 'string', 'description' => 'Health check method.'],
- 'health_check_return_code' => ['type' => 'integer', 'description' => 'Health check return code.'],
- 'health_check_scheme' => ['type' => 'string', 'description' => 'Health check scheme.'],
- 'health_check_response_text' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check response text.'],
- 'health_check_interval' => ['type' => 'integer', 'description' => 'Health check interval in seconds.'],
- 'health_check_timeout' => ['type' => 'integer', 'description' => 'Health check timeout in seconds.'],
- 'health_check_retries' => ['type' => 'integer', 'description' => 'Health check retries count.'],
- 'health_check_start_period' => ['type' => 'integer', 'description' => 'Health check start period in seconds.'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit.'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit.'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness.'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation.'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit.'],
- 'limits_cpuset' => ['type' => 'string', 'nullable' => true, 'description' => 'CPU set.'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares.'],
- 'custom_labels' => ['type' => 'string', 'description' => 'Custom labels.'],
- 'custom_docker_run_options' => ['type' => 'string', 'description' => 'Custom docker run options.'],
- 'post_deployment_command' => ['type' => 'string', 'description' => 'Post deployment command.'],
- 'post_deployment_command_container' => ['type' => 'string', 'description' => 'Post deployment command container.'],
- 'pre_deployment_command' => ['type' => 'string', 'description' => 'Pre deployment command.'],
- 'pre_deployment_command_container' => ['type' => 'string', 'description' => 'Pre deployment command container.'],
- 'manual_webhook_secret_github' => ['type' => 'string', 'description' => 'Manual webhook secret for Github.'],
- 'manual_webhook_secret_gitlab' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitlab.'],
- 'manual_webhook_secret_bitbucket' => ['type' => 'string', 'description' => 'Manual webhook secret for Bitbucket.'],
- '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']],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
- 'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
- ],
- )
- ),
- ]
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Application created successfully.',
- 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_dockerfile_application(Request $request)
- {
- return $this->create_application($request, 'dockerfile');
- }
-
- #[OA\Post(
- summary: 'Create (Docker Image)',
- description: 'Create new application based on a prebuilt docker image',
- path: '/applications/dockerimage',
- operationId: 'create-dockerimage-application',
- 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: ['project_uuid', 'server_uuid', 'environment_name', 'environment_uuid', 'docker_registry_image_name', 'ports_exposes'],
- properties: [
- 'project_uuid' => ['type' => 'string', 'description' => 'The project UUID.'],
- 'server_uuid' => ['type' => 'string', 'description' => 'The server UUID.'],
- 'environment_name' => ['type' => 'string', 'description' => 'The environment name. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'],
- 'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
- 'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
- 'ports_exposes' => ['type' => 'string', 'description' => 'The ports to expose.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
- 'name' => ['type' => 'string', 'description' => 'The application name.'],
- 'description' => ['type' => 'string', 'description' => 'The application description.'],
- 'domains' => ['type' => 'string', 'description' => 'The application domains.'],
- 'ports_mappings' => ['type' => 'string', 'description' => 'The ports mappings.'],
- 'health_check_enabled' => ['type' => 'boolean', 'description' => 'Health check enabled.'],
- 'health_check_path' => ['type' => 'string', 'description' => 'Health check path.'],
- 'health_check_port' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check port.'],
- 'health_check_host' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check host.'],
- 'health_check_method' => ['type' => 'string', 'description' => 'Health check method.'],
- 'health_check_return_code' => ['type' => 'integer', 'description' => 'Health check return code.'],
- 'health_check_scheme' => ['type' => 'string', 'description' => 'Health check scheme.'],
- 'health_check_response_text' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check response text.'],
- 'health_check_interval' => ['type' => 'integer', 'description' => 'Health check interval in seconds.'],
- 'health_check_timeout' => ['type' => 'integer', 'description' => 'Health check timeout in seconds.'],
- 'health_check_retries' => ['type' => 'integer', 'description' => 'Health check retries count.'],
- 'health_check_start_period' => ['type' => 'integer', 'description' => 'Health check start period in seconds.'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit.'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit.'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness.'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation.'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit.'],
- 'limits_cpuset' => ['type' => 'string', 'nullable' => true, 'description' => 'CPU set.'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares.'],
- 'custom_labels' => ['type' => 'string', 'description' => 'Custom labels.'],
- 'custom_docker_run_options' => ['type' => 'string', 'description' => 'Custom docker run options.'],
- 'post_deployment_command' => ['type' => 'string', 'description' => 'Post deployment command.'],
- 'post_deployment_command_container' => ['type' => 'string', 'description' => 'Post deployment command container.'],
- 'pre_deployment_command' => ['type' => 'string', 'description' => 'Pre deployment command.'],
- 'pre_deployment_command_container' => ['type' => 'string', 'description' => 'Pre deployment command container.'],
- 'manual_webhook_secret_github' => ['type' => 'string', 'description' => 'Manual webhook secret for Github.'],
- 'manual_webhook_secret_gitlab' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitlab.'],
- 'manual_webhook_secret_bitbucket' => ['type' => 'string', 'description' => 'Manual webhook secret for Bitbucket.'],
- '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']],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
- 'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
- ],
- )
- ),
- ]
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Application created successfully.',
- 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_dockerimage_application(Request $request)
- {
- return $this->create_application($request, 'dockerimage');
- }
-
- #[OA\Post(
- summary: 'Create (Docker Compose)',
- description: 'Create new application based on a docker-compose file.',
- path: '/applications/dockercompose',
- operationId: 'create-dockercompose-application',
- 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: ['project_uuid', 'server_uuid', 'environment_name', 'environment_uuid', 'docker_compose_raw'],
- properties: [
- 'project_uuid' => ['type' => 'string', 'description' => 'The project UUID.'],
- 'server_uuid' => ['type' => 'string', 'description' => 'The server UUID.'],
- 'environment_name' => ['type' => 'string', 'description' => 'The environment name. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'],
- 'docker_compose_raw' => ['type' => 'string', 'description' => 'The Docker Compose raw content.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID if the server has more than one destinations.'],
- 'name' => ['type' => 'string', 'description' => 'The application name.'],
- 'description' => ['type' => 'string', 'description' => 'The application description.'],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
- 'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
- ],
- )
- ),
- ]
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Application created successfully.',
- 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_dockercompose_application(Request $request)
- {
- return $this->create_application($request, 'dockercompose');
- }
-
- private function create_application(Request $request, $type)
- {
- $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', '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'];
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $validator = customApiValidator($request->all(), [
- 'name' => 'string|max:255',
- 'description' => 'string|nullable',
- 'project_uuid' => 'string|required',
- 'environment_name' => 'string|nullable',
- 'environment_uuid' => 'string|nullable',
- 'server_uuid' => 'string|required',
- 'destination_uuid' => 'string',
- ]);
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
-
- $environmentUuid = $request->environment_uuid;
- $environmentName = $request->environment_name;
- if (blank($environmentUuid) && blank($environmentName)) {
- return response()->json(['message' => 'You need to provide at least one of environment_name or environment_uuid.'], 422);
- }
- $serverUuid = $request->server_uuid;
- $fqdn = $request->domains;
- $instantDeploy = $request->instant_deploy;
- $githubAppUuid = $request->github_app_uuid;
- $useBuildServer = $request->use_build_server;
- $isStatic = $request->is_static;
- $customNginxConfiguration = $request->custom_nginx_configuration;
-
- if (! is_null($customNginxConfiguration)) {
- if (! isBase64Encoded($customNginxConfiguration)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'custom_nginx_configuration' => 'The custom_nginx_configuration should be base64 encoded.',
- ],
- ], 422);
- }
- $customNginxConfiguration = base64_decode($customNginxConfiguration);
- if (mb_detect_encoding($customNginxConfiguration, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'custom_nginx_configuration' => 'The custom_nginx_configuration should be base64 encoded.',
- ],
- ], 422);
- }
- }
-
- $project = Project::whereTeamId($teamId)->whereUuid($request->project_uuid)->first();
- if (! $project) {
- return response()->json(['message' => 'Project not found.'], 404);
- }
- $environment = $project->environments()->where('name', $environmentName)->first();
- if (! $environment) {
- $environment = $project->environments()->where('uuid', $environmentUuid)->first();
- }
- if (! $environment) {
- return response()->json(['message' => 'Environment not found.'], 404);
- }
- $server = Server::whereTeamId($teamId)->whereUuid($serverUuid)->first();
- if (! $server) {
- return response()->json(['message' => 'Server not found.'], 404);
- }
- $destinations = $server->destinations();
- if ($destinations->count() == 0) {
- return response()->json(['message' => 'Server has no destinations.'], 400);
- }
- if ($destinations->count() > 1 && ! $request->has('destination_uuid')) {
- return response()->json(['message' => 'Server has multiple destinations and you do not set destination_uuid.'], 400);
- }
- $destination = $destinations->first();
- if ($type === 'public') {
- $validationRules = [
- 'git_repository' => 'string|required',
- 'git_branch' => 'string|required',
- 'build_pack' => ['required', Rule::enum(BuildPackTypes::class)],
- 'ports_exposes' => 'string|regex:/^(\d+)(,\d+)*$/|required',
- 'docker_compose_location' => 'string',
- 'docker_compose_raw' => 'string|nullable',
- 'docker_compose_domains' => 'array|nullable',
- ];
- // ports_exposes is not required for dockercompose
- if ($request->build_pack === 'dockercompose') {
- $validationRules['ports_exposes'] = 'string';
- $request->offsetSet('ports_exposes', '80');
- }
- $validationRules = array_merge(sharedDataApplications(), $validationRules);
- $validator = customApiValidator($request->all(), $validationRules);
- if ($validator->fails()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
- if (! $request->has('name')) {
- $request->offsetSet('name', generate_application_name($request->git_repository, $request->git_branch));
- }
- $return = $this->validateDataApplications($request, $server);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
-
- $application = new Application;
- removeUnnecessaryFieldsFromRequest($request);
-
- $application->fill($request->all());
- $dockerComposeDomainsJson = collect();
- if ($request->has('docker_compose_domains')) {
- $dockerComposeDomains = collect($request->docker_compose_domains);
- if ($dockerComposeDomains->count() > 0) {
- $dockerComposeDomains->each(function ($domain, $key) use ($dockerComposeDomainsJson) {
- $dockerComposeDomainsJson->put(data_get($domain, 'name'), ['domain' => data_get($domain, 'domain')]);
- });
- }
- $request->offsetUnset('docker_compose_domains');
- }
- if ($dockerComposeDomainsJson->count() > 0) {
- $application->docker_compose_domains = $dockerComposeDomainsJson;
- }
- $repository_url_parsed = Url::fromString($request->git_repository);
- $git_host = $repository_url_parsed->getHost();
- if ($git_host === 'github.com') {
- $application->source_type = GithubApp::class;
- $application->source_id = GithubApp::find(0)->id;
- }
- $application->git_repository = $repository_url_parsed->getSegment(1).'/'.$repository_url_parsed->getSegment(2);
- $application->fqdn = $fqdn;
- $application->destination_id = $destination->id;
- $application->destination_type = $destination->getMorphClass();
- $application->environment_id = $environment->id;
- $application->save();
- if (isset($isStatic)) {
- $application->settings->is_static = $isStatic;
- $application->settings->save();
- }
- if (isset($useBuildServer)) {
- $application->settings->is_build_server_enabled = $useBuildServer;
- $application->settings->save();
- }
- $application->refresh();
- if ($application->settings->is_container_label_readonly_enabled) {
- $application->custom_labels = str(implode('|coolify|', generateLabelsApplication($application)))->replace('|coolify|', "\n");
- $application->save();
- }
- $application->isConfigurationChanged(true);
-
- if ($instantDeploy) {
- $deployment_uuid = new Cuid2;
-
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- no_questions_asked: true,
- is_api: true,
- );
- } else {
- if ($application->build_pack === 'dockercompose') {
- LoadComposeFile::dispatch($application);
- }
- }
-
- return response()->json(serializeApiResponse([
- 'uuid' => data_get($application, 'uuid'),
- 'domains' => data_get($application, 'domains'),
- ]))->setStatusCode(201);
- } elseif ($type === 'private-gh-app') {
- $validationRules = [
- 'git_repository' => 'string|required',
- 'git_branch' => 'string|required',
- 'build_pack' => ['required', Rule::enum(BuildPackTypes::class)],
- 'ports_exposes' => 'string|regex:/^(\d+)(,\d+)*$/|required',
- 'github_app_uuid' => 'string|required',
- 'watch_paths' => 'string|nullable',
- 'docker_compose_location' => 'string',
- 'docker_compose_raw' => 'string|nullable',
- ];
- $validationRules = array_merge(sharedDataApplications(), $validationRules);
-
- $validator = customApiValidator($request->all(), $validationRules);
- if ($validator->fails()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
-
- if (! $request->has('name')) {
- $request->offsetSet('name', generate_application_name($request->git_repository, $request->git_branch));
- }
- if ($request->build_pack === 'dockercompose') {
- $request->offsetSet('ports_exposes', '80');
- }
-
- $return = $this->validateDataApplications($request, $server);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $githubApp = GithubApp::whereTeamId($teamId)->where('uuid', $githubAppUuid)->first();
- if (! $githubApp) {
- return response()->json(['message' => 'Github App not found.'], 404);
- }
- $gitRepository = $request->git_repository;
- if (str($gitRepository)->startsWith('http') || str($gitRepository)->contains('github.com')) {
- $gitRepository = str($gitRepository)->replace('https://', '')->replace('http://', '')->replace('github.com/', '');
- }
- $application = new Application;
- removeUnnecessaryFieldsFromRequest($request);
-
- $application->fill($request->all());
-
- $dockerComposeDomainsJson = collect();
- if ($request->has('docker_compose_domains')) {
- $yaml = Yaml::parse($application->docker_compose_raw);
- $services = data_get($yaml, 'services');
- $dockerComposeDomains = collect($request->docker_compose_domains);
- if ($dockerComposeDomains->count() > 0) {
- $dockerComposeDomains->each(function ($domain, $key) use ($services, $dockerComposeDomainsJson) {
- $name = data_get($domain, 'name');
- if (data_get($services, $name)) {
- $dockerComposeDomainsJson->put($name, ['domain' => data_get($domain, 'domain')]);
- }
- });
- }
- $request->offsetUnset('docker_compose_domains');
- }
- if ($dockerComposeDomainsJson->count() > 0) {
- $application->docker_compose_domains = $dockerComposeDomainsJson;
- }
- $application->fqdn = $fqdn;
- $application->git_repository = $gitRepository;
- $application->destination_id = $destination->id;
- $application->destination_type = $destination->getMorphClass();
- $application->environment_id = $environment->id;
- $application->source_type = $githubApp->getMorphClass();
- $application->source_id = $githubApp->id;
- $application->save();
- $application->refresh();
- if (isset($useBuildServer)) {
- $application->settings->is_build_server_enabled = $useBuildServer;
- $application->settings->save();
- }
- if ($application->settings->is_container_label_readonly_enabled) {
- $application->custom_labels = str(implode('|coolify|', generateLabelsApplication($application)))->replace('|coolify|', "\n");
- $application->save();
- }
- $application->isConfigurationChanged(true);
-
- if ($instantDeploy) {
- $deployment_uuid = new Cuid2;
-
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- no_questions_asked: true,
- is_api: true,
- );
- } else {
- if ($application->build_pack === 'dockercompose') {
- LoadComposeFile::dispatch($application);
- }
- }
-
- return response()->json(serializeApiResponse([
- 'uuid' => data_get($application, 'uuid'),
- 'domains' => data_get($application, 'domains'),
- ]))->setStatusCode(201);
- } elseif ($type === 'private-deploy-key') {
-
- $validationRules = [
- 'git_repository' => 'string|required',
- 'git_branch' => 'string|required',
- 'build_pack' => ['required', Rule::enum(BuildPackTypes::class)],
- 'ports_exposes' => 'string|regex:/^(\d+)(,\d+)*$/|required',
- 'private_key_uuid' => 'string|required',
- 'watch_paths' => 'string|nullable',
- 'docker_compose_location' => 'string',
- 'docker_compose_raw' => 'string|nullable',
- ];
-
- $validationRules = array_merge(sharedDataApplications(), $validationRules);
- $validator = customApiValidator($request->all(), $validationRules);
-
- if ($validator->fails()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
- if (! $request->has('name')) {
- $request->offsetSet('name', generate_application_name($request->git_repository, $request->git_branch));
- }
- if ($request->build_pack === 'dockercompose') {
- $request->offsetSet('ports_exposes', '80');
- }
-
- $return = $this->validateDataApplications($request, $server);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $privateKey = PrivateKey::whereTeamId($teamId)->where('uuid', $request->private_key_uuid)->first();
- if (! $privateKey) {
- return response()->json(['message' => 'Private Key not found.'], 404);
- }
-
- $application = new Application;
- removeUnnecessaryFieldsFromRequest($request);
-
- $application->fill($request->all());
-
- $dockerComposeDomainsJson = collect();
- if ($request->has('docker_compose_domains')) {
- $yaml = Yaml::parse($application->docker_compose_raw);
- $services = data_get($yaml, 'services');
- $dockerComposeDomains = collect($request->docker_compose_domains);
- if ($dockerComposeDomains->count() > 0) {
- $dockerComposeDomains->each(function ($domain, $key) use ($services, $dockerComposeDomainsJson) {
- $name = data_get($domain, 'name');
- if (data_get($services, $name)) {
- $dockerComposeDomainsJson->put($name, ['domain' => data_get($domain, 'domain')]);
- }
- });
- }
- $request->offsetUnset('docker_compose_domains');
- }
- if ($dockerComposeDomainsJson->count() > 0) {
- $application->docker_compose_domains = $dockerComposeDomainsJson;
- }
- $application->fqdn = $fqdn;
- $application->private_key_id = $privateKey->id;
- $application->destination_id = $destination->id;
- $application->destination_type = $destination->getMorphClass();
- $application->environment_id = $environment->id;
- $application->save();
- $application->refresh();
- if (isset($useBuildServer)) {
- $application->settings->is_build_server_enabled = $useBuildServer;
- $application->settings->save();
- }
- if ($application->settings->is_container_label_readonly_enabled) {
- $application->custom_labels = str(implode('|coolify|', generateLabelsApplication($application)))->replace('|coolify|', "\n");
- $application->save();
- }
- $application->isConfigurationChanged(true);
-
- if ($instantDeploy) {
- $deployment_uuid = new Cuid2;
-
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- no_questions_asked: true,
- is_api: true,
- );
- } else {
- if ($application->build_pack === 'dockercompose') {
- LoadComposeFile::dispatch($application);
- }
- }
-
- return response()->json(serializeApiResponse([
- 'uuid' => data_get($application, 'uuid'),
- 'domains' => data_get($application, 'domains'),
- ]))->setStatusCode(201);
- } elseif ($type === 'dockerfile') {
- $validationRules = [
- 'dockerfile' => 'string|required',
- ];
- $validationRules = array_merge(sharedDataApplications(), $validationRules);
- $validator = customApiValidator($request->all(), $validationRules);
-
- if ($validator->fails()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
- if (! $request->has('name')) {
- $request->offsetSet('name', 'dockerfile-'.new Cuid2);
- }
-
- $return = $this->validateDataApplications($request, $server);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- if (! isBase64Encoded($request->dockerfile)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'dockerfile' => 'The dockerfile should be base64 encoded.',
- ],
- ], 422);
- }
- $dockerFile = base64_decode($request->dockerfile);
- if (mb_detect_encoding($dockerFile, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'dockerfile' => 'The dockerfile should be base64 encoded.',
- ],
- ], 422);
- }
- $dockerFile = base64_decode($request->dockerfile);
- removeUnnecessaryFieldsFromRequest($request);
-
- $port = get_port_from_dockerfile($request->dockerfile);
- if (! $port) {
- $port = 80;
- }
-
- $application = new Application;
- $application->fill($request->all());
- $application->fqdn = $fqdn;
- $application->ports_exposes = $port;
- $application->build_pack = 'dockerfile';
- $application->dockerfile = $dockerFile;
- $application->destination_id = $destination->id;
- $application->destination_type = $destination->getMorphClass();
- $application->environment_id = $environment->id;
-
- $application->git_repository = 'coollabsio/coolify';
- $application->git_branch = 'main';
- $application->save();
- $application->refresh();
- if (isset($useBuildServer)) {
- $application->settings->is_build_server_enabled = $useBuildServer;
- $application->settings->save();
- }
- if ($application->settings->is_container_label_readonly_enabled) {
- $application->custom_labels = str(implode('|coolify|', generateLabelsApplication($application)))->replace('|coolify|', "\n");
- $application->save();
- }
- $application->isConfigurationChanged(true);
-
- if ($instantDeploy) {
- $deployment_uuid = new Cuid2;
-
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- no_questions_asked: true,
- is_api: true,
- );
- }
-
- return response()->json(serializeApiResponse([
- 'uuid' => data_get($application, 'uuid'),
- 'domains' => data_get($application, 'domains'),
- ]))->setStatusCode(201);
- } elseif ($type === 'dockerimage') {
- $validationRules = [
- 'docker_registry_image_name' => 'string|required',
- 'docker_registry_image_tag' => 'string',
- 'ports_exposes' => 'string|regex:/^(\d+)(,\d+)*$/|required',
- ];
- $validationRules = array_merge(sharedDataApplications(), $validationRules);
- $validator = customApiValidator($request->all(), $validationRules);
-
- if ($validator->fails()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
- if (! $request->has('name')) {
- $request->offsetSet('name', 'docker-image-'.new Cuid2);
- }
- $return = $this->validateDataApplications($request, $server);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- if (! $request->docker_registry_image_tag) {
- $request->offsetSet('docker_registry_image_tag', 'latest');
- }
- $application = new Application;
- removeUnnecessaryFieldsFromRequest($request);
-
- $application->fill($request->all());
- $application->fqdn = $fqdn;
- $application->build_pack = 'dockerimage';
- $application->destination_id = $destination->id;
- $application->destination_type = $destination->getMorphClass();
- $application->environment_id = $environment->id;
-
- $application->git_repository = 'coollabsio/coolify';
- $application->git_branch = 'main';
- $application->save();
- $application->refresh();
- if (isset($useBuildServer)) {
- $application->settings->is_build_server_enabled = $useBuildServer;
- $application->settings->save();
- }
- if ($application->settings->is_container_label_readonly_enabled) {
- $application->custom_labels = str(implode('|coolify|', generateLabelsApplication($application)))->replace('|coolify|', "\n");
- $application->save();
- }
- $application->isConfigurationChanged(true);
-
- if ($instantDeploy) {
- $deployment_uuid = new Cuid2;
-
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- no_questions_asked: true,
- is_api: true,
- );
- }
-
- return response()->json(serializeApiResponse([
- 'uuid' => data_get($application, 'uuid'),
- 'domains' => data_get($application, 'domains'),
- ]))->setStatusCode(201);
- } elseif ($type === 'dockercompose') {
- $allowedFields = ['project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'instant_deploy', 'docker_compose_raw'];
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- if (! $request->has('name')) {
- $request->offsetSet('name', 'service'.new Cuid2);
- }
- $validationRules = [
- 'docker_compose_raw' => 'string|required',
- ];
- $validationRules = array_merge(sharedDataApplications(), $validationRules);
- $validator = customApiValidator($request->all(), $validationRules);
-
- if ($validator->fails()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
- $return = $this->validateDataApplications($request, $server);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- if (! isBase64Encoded($request->docker_compose_raw)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
- ],
- ], 422);
- }
- $dockerComposeRaw = base64_decode($request->docker_compose_raw);
- if (mb_detect_encoding($dockerComposeRaw, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'docker_compose_raw' => 'The docker_compose_raw should be base64 encoded.',
- ],
- ], 422);
- }
- $dockerCompose = base64_decode($request->docker_compose_raw);
- $dockerComposeRaw = Yaml::dump(Yaml::parse($dockerCompose), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
-
- $service = new Service;
- removeUnnecessaryFieldsFromRequest($request);
- $service->fill($request->all());
-
- $service->docker_compose_raw = $dockerComposeRaw;
- $service->environment_id = $environment->id;
- $service->server_id = $server->id;
- $service->destination_id = $destination->id;
- $service->destination_type = $destination->getMorphClass();
- $service->save();
-
- $service->name = "service-$service->uuid";
- $service->parse(isNew: true);
- if ($instantDeploy) {
- StartService::dispatch($service);
- }
-
- return response()->json(serializeApiResponse([
- 'uuid' => data_get($service, 'uuid'),
- 'domains' => data_get($service, 'domains'),
- ]))->setStatusCode(201);
- }
-
- return response()->json(['message' => 'Invalid type.'], 400);
- }
-
- #[OA\Get(
- summary: 'Get',
- description: 'Get application by UUID.',
- path: '/applications/{uuid}',
- operationId: 'get-application-by-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 application by UUID.',
- 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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
- if (! $application) {
- return response()->json(['message' => 'Application not found.'], 404);
- }
-
- return response()->json($this->removeSensitiveData($application));
- }
-
- #[OA\Get(
- summary: 'Get application logs.',
- description: 'Get application logs by UUID.',
- path: '/applications/{uuid}/logs',
- operationId: 'get-application-logs-by-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',
- )
- ),
- new OA\Parameter(
- name: 'lines',
- in: 'query',
- description: 'Number of lines to show from the end of the logs.',
- required: false,
- schema: new OA\Schema(
- type: 'integer',
- format: 'int32',
- default: 100,
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Get application logs by UUID.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'logs' => ['type' => 'string'],
- ]
- )
- ),
- ]
- ),
- 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 logs_by_uuid(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
- if (! $application) {
- return response()->json(['message' => 'Application not found.'], 404);
- }
-
- $containers = getCurrentApplicationContainerStatus($application->destination->server, $application->id);
-
- if ($containers->count() == 0) {
- return response()->json([
- 'message' => 'Application is not running.',
- ], 400);
- }
-
- $container = $containers->first();
-
- $status = getContainerStatus($application->destination->server, $container['Names']);
- if ($status !== 'running') {
- return response()->json([
- 'message' => 'Application is not running.',
- ], 400);
- }
-
- $lines = $request->query->get('lines', 100) ?: 100;
- $logs = getContainerLogs($application->destination->server, $container['ID'], $lines);
-
- return response()->json([
- 'logs' => $logs,
- ]);
- }
-
- #[OA\Delete(
- summary: 'Delete',
- description: 'Delete application by UUID.',
- path: '/applications/{uuid}',
- operationId: 'delete-application-by-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',
- )
- ),
- new OA\Parameter(name: 'delete_configurations', in: 'query', required: false, description: 'Delete configurations.', schema: new OA\Schema(type: 'boolean', default: true)),
- new OA\Parameter(name: 'delete_volumes', in: 'query', required: false, description: 'Delete volumes.', schema: new OA\Schema(type: 'boolean', default: true)),
- new OA\Parameter(name: 'docker_cleanup', in: 'query', required: false, description: 'Run docker cleanup.', schema: new OA\Schema(type: 'boolean', default: true)),
- new OA\Parameter(name: 'delete_connected_networks', in: 'query', required: false, description: 'Delete connected networks.', schema: new OA\Schema(type: 'boolean', default: true)),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Application deleted.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Application deleted.'],
- ]
- )
- ),
- ]
- ),
- 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 delete_by_uuid(Request $request)
- {
- $teamId = getTeamIdFromToken();
- $cleanup = filter_var($request->query->get('cleanup', true), FILTER_VALIDATE_BOOLEAN);
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- if (! $request->uuid) {
- return response()->json(['message' => 'UUID is required.'], 404);
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
-
- if (! $application) {
- return response()->json([
- 'message' => 'Application not found',
- ], 404);
- }
-
- DeleteResourceJob::dispatch(
- resource: $application,
- deleteConfigurations: $request->query->get('delete_configurations', true),
- deleteVolumes: $request->query->get('delete_volumes', true),
- dockerCleanup: $request->query->get('docker_cleanup', true),
- deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
- );
-
- return response()->json([
- 'message' => 'Application deletion request queued.',
- ]);
- }
-
- #[OA\Patch(
- summary: 'Update',
- description: 'Update application by UUID.',
- path: '/applications/{uuid}',
- operationId: 'update-application-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Applications'],
- requestBody: new OA\RequestBody(
- description: 'Application updated.',
- required: true,
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'project_uuid' => ['type' => 'string', 'description' => 'The project UUID.'],
- 'server_uuid' => ['type' => 'string', 'description' => 'The server UUID.'],
- 'environment_name' => ['type' => 'string', 'description' => 'The environment name.'],
- 'github_app_uuid' => ['type' => 'string', 'description' => 'The Github App UUID.'],
- 'git_repository' => ['type' => 'string', 'description' => 'The git repository URL.'],
- 'git_branch' => ['type' => 'string', 'description' => 'The git branch.'],
- 'ports_exposes' => ['type' => 'string', 'description' => 'The ports to expose.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'The destination UUID.'],
- 'build_pack' => ['type' => 'string', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose'], 'description' => 'The build pack type.'],
- 'name' => ['type' => 'string', 'description' => 'The application name.'],
- 'description' => ['type' => 'string', 'description' => 'The application description.'],
- 'domains' => ['type' => 'string', 'description' => 'The application domains.'],
- '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_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
- 'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
- 'install_command' => ['type' => 'string', 'description' => 'The install command.'],
- 'build_command' => ['type' => 'string', 'description' => 'The build command.'],
- 'start_command' => ['type' => 'string', 'description' => 'The start command.'],
- 'ports_mappings' => ['type' => 'string', 'description' => 'The ports mappings.'],
- 'base_directory' => ['type' => 'string', 'description' => 'The base directory for all commands.'],
- 'publish_directory' => ['type' => 'string', 'description' => 'The publish directory.'],
- 'health_check_enabled' => ['type' => 'boolean', 'description' => 'Health check enabled.'],
- 'health_check_path' => ['type' => 'string', 'description' => 'Health check path.'],
- 'health_check_port' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check port.'],
- 'health_check_host' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check host.'],
- 'health_check_method' => ['type' => 'string', 'description' => 'Health check method.'],
- 'health_check_return_code' => ['type' => 'integer', 'description' => 'Health check return code.'],
- 'health_check_scheme' => ['type' => 'string', 'description' => 'Health check scheme.'],
- 'health_check_response_text' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check response text.'],
- 'health_check_interval' => ['type' => 'integer', 'description' => 'Health check interval in seconds.'],
- 'health_check_timeout' => ['type' => 'integer', 'description' => 'Health check timeout in seconds.'],
- 'health_check_retries' => ['type' => 'integer', 'description' => 'Health check retries count.'],
- 'health_check_start_period' => ['type' => 'integer', 'description' => 'Health check start period in seconds.'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit.'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit.'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness.'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation.'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit.'],
- 'limits_cpuset' => ['type' => 'string', 'nullable' => true, 'description' => 'CPU set.'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares.'],
- 'custom_labels' => ['type' => 'string', 'description' => 'Custom labels.'],
- 'custom_docker_run_options' => ['type' => 'string', 'description' => 'Custom docker run options.'],
- 'post_deployment_command' => ['type' => 'string', 'description' => 'Post deployment command.'],
- 'post_deployment_command_container' => ['type' => 'string', 'description' => 'Post deployment command container.'],
- 'pre_deployment_command' => ['type' => 'string', 'description' => 'Pre deployment command.'],
- 'pre_deployment_command_container' => ['type' => 'string', 'description' => 'Pre deployment command container.'],
- 'manual_webhook_secret_github' => ['type' => 'string', 'description' => 'Manual webhook secret for Github.'],
- 'manual_webhook_secret_gitlab' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitlab.'],
- 'manual_webhook_secret_bitbucket' => ['type' => 'string', 'description' => 'Manual webhook secret for Bitbucket.'],
- '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']],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
- 'dockerfile' => ['type' => 'string', 'description' => 'The Dockerfile content.'],
- 'docker_compose_location' => ['type' => 'string', 'description' => 'The Docker Compose location.'],
- 'docker_compose_raw' => ['type' => 'string', 'description' => 'The Docker Compose raw content.'],
- '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_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
- 'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
- 'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
- ],
- )
- ),
- ]
- ),
- responses: [
- new OA\Response(
- response: 200,
- description: 'Application updated.',
- 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',
- ),
- new OA\Response(
- response: 404,
- ref: '#/components/responses/404',
- ),
- ]
- )]
- public function update_by_uuid(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- if ($request->collect()->count() == 0) {
- return response()->json([
- 'message' => 'Invalid request.',
- ], 400);
- }
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
-
- if (! $application) {
- return response()->json([
- 'message' => 'Application not found',
- ], 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_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect', 'instant_deploy', 'use_build_server', 'custom_nginx_configuration'];
-
- $validationRules = [
- 'name' => 'string|max:255',
- 'description' => 'string|nullable',
- 'static_image' => 'string',
- 'watch_paths' => 'string|nullable',
- 'docker_compose_location' => 'string',
- 'docker_compose_raw' => 'string|nullable',
- 'docker_compose_domains' => 'array|nullable',
- 'docker_compose_custom_start_command' => 'string|nullable',
- 'docker_compose_custom_build_command' => 'string|nullable',
- 'custom_nginx_configuration' => 'string|nullable',
- ];
- $validationRules = array_merge(sharedDataApplications(), $validationRules);
- $validator = customApiValidator($request->all(), $validationRules);
-
- // Validate ports_exposes
- if ($request->has('ports_exposes')) {
- $ports = explode(',', $request->ports_exposes);
- foreach ($ports as $port) {
- if (! is_numeric($port)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'ports_exposes' => 'The ports_exposes should be a comma separated list of numbers.',
- ],
- ], 422);
- }
- }
- }
- if ($request->has('custom_nginx_configuration')) {
- if (! isBase64Encoded($request->custom_nginx_configuration)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'custom_nginx_configuration' => 'The custom_nginx_configuration should be base64 encoded.',
- ],
- ], 422);
- }
- $customNginxConfiguration = base64_decode($request->custom_nginx_configuration);
- if (mb_detect_encoding($customNginxConfiguration, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'custom_nginx_configuration' => 'The custom_nginx_configuration should be base64 encoded.',
- ],
- ], 422);
- }
- }
- $return = $this->validateDataApplications($request, $server);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- $domains = $request->domains;
- $requestHasDomains = $request->has('domains');
- if ($requestHasDomains && $server->isProxyShouldRun()) {
- $uuid = $request->uuid;
- $fqdn = $request->domains;
- $fqdn = str($fqdn)->replaceEnd(',', '')->trim();
- $fqdn = str($fqdn)->replaceStart(',', '')->trim();
- $errors = [];
- $fqdn = str($fqdn)->trim()->explode(',')->map(function ($domain) use (&$errors) {
- $domain = trim($domain);
- if (filter_var($domain, FILTER_VALIDATE_URL) === false || ! preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,}/', $domain)) {
- $errors[] = 'Invalid domain: '.$domain;
- }
-
- return $domain;
- });
- if (count($errors) > 0) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- if (checkIfDomainIsAlreadyUsed($fqdn, $teamId, $uuid)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'domains' => 'One of the domain is already used.',
- ],
- ], 422);
- }
- }
-
- $dockerComposeDomainsJson = collect();
- if ($request->has('docker_compose_domains')) {
- $yaml = Yaml::parse($application->docker_compose_raw);
- $services = data_get($yaml, 'services');
- $dockerComposeDomains = collect($request->docker_compose_domains);
- if ($dockerComposeDomains->count() > 0) {
- $dockerComposeDomains->each(function ($domain, $key) use ($services, $dockerComposeDomainsJson) {
- $name = data_get($domain, 'name');
- if (data_get($services, $name)) {
- $dockerComposeDomainsJson->put($name, ['domain' => data_get($domain, 'domain')]);
- }
- });
- }
- $request->offsetUnset('docker_compose_domains');
- }
- $instantDeploy = $request->instant_deploy;
- $isStatic = $request->is_static;
- $useBuildServer = $request->use_build_server;
-
- if (isset($useBuildServer)) {
- $application->settings->is_build_server_enabled = $useBuildServer;
- $application->settings->save();
- }
-
- if (isset($isStatic)) {
- $application->settings->is_static = $isStatic;
- $application->settings->save();
- }
-
- removeUnnecessaryFieldsFromRequest($request);
-
- $data = $request->all();
- if ($requestHasDomains && $server->isProxyShouldRun()) {
- data_set($data, 'fqdn', $domains);
- }
-
- if ($dockerComposeDomainsJson->count() > 0) {
- data_set($data, 'docker_compose_domains', json_encode($dockerComposeDomainsJson));
- }
- $application->fill($data);
- $application->save();
-
- if ($instantDeploy) {
- $deployment_uuid = new Cuid2;
-
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- is_api: true,
- );
- }
-
- return response()->json([
- 'uuid' => $application->uuid,
- ]);
- }
-
- #[OA\Get(
- summary: 'List Envs',
- description: 'List all envs by application UUID.',
- path: '/applications/{uuid}/envs',
- operationId: 'list-envs-by-application-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: 'All environment variables by application UUID.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'array',
- items: new OA\Items(ref: '#/components/schemas/EnvironmentVariable')
- )
- ),
- ]
- ),
- 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 envs(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
-
- if (! $application) {
- return response()->json([
- 'message' => 'Application not found',
- ], 404);
- }
- $envs = $application->environment_variables->sortBy('id')->merge($application->environment_variables_preview->sortBy('id'));
-
- $envs = $envs->map(function ($env) {
- $env->makeHidden([
- 'service_id',
- 'standalone_clickhouse_id',
- 'standalone_dragonfly_id',
- 'standalone_keydb_id',
- 'standalone_mariadb_id',
- 'standalone_mongodb_id',
- 'standalone_mysql_id',
- 'standalone_postgresql_id',
- 'standalone_redis_id',
- ]);
-
- return $this->removeSensitiveData($env);
- });
-
- return response()->json($envs);
- }
-
- #[OA\Patch(
- summary: 'Update Env',
- description: 'Update env by application UUID.',
- path: '/applications/{uuid}/envs',
- operationId: 'update-env-by-application-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',
- )
- ),
- ],
- requestBody: new OA\RequestBody(
- description: 'Env updated.',
- required: true,
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['key', 'value'],
- properties: [
- 'key' => ['type' => 'string', 'description' => 'The key of the environment variable.'],
- 'value' => ['type' => 'string', 'description' => 'The value of the environment variable.'],
- 'is_preview' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in preview deployments.'],
- 'is_build_time' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in build time.'],
- 'is_literal' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is a literal, nothing espaced.'],
- 'is_multiline' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is multiline.'],
- 'is_shown_once' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable\'s value is shown on the UI.'],
- ],
- ),
- ),
- ],
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Environment variable updated.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Environment variable updated.'],
- ]
- )
- ),
- ]
- ),
- 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 update_env_by_uuid(Request $request)
- {
- $allowedFields = ['key', 'value', 'is_preview', 'is_build_time', 'is_literal'];
- $teamId = getTeamIdFromToken();
-
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
-
- if (! $application) {
- return response()->json([
- 'message' => 'Application not found',
- ], 404);
- }
- $validator = customApiValidator($request->all(), [
- 'key' => 'string|required',
- 'value' => 'string|nullable',
- 'is_preview' => 'boolean',
- 'is_build_time' => 'boolean',
- 'is_literal' => 'boolean',
- 'is_multiline' => 'boolean',
- 'is_shown_once' => 'boolean',
- ]);
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- $is_preview = $request->is_preview ?? false;
- $is_build_time = $request->is_build_time ?? false;
- $is_literal = $request->is_literal ?? false;
- $key = str($request->key)->trim()->replace(' ', '_')->value;
- if ($is_preview) {
- $env = $application->environment_variables_preview->where('key', $key)->first();
- if ($env) {
- $env->value = $request->value;
- if ($env->is_build_time != $is_build_time) {
- $env->is_build_time = $is_build_time;
- }
- if ($env->is_literal != $is_literal) {
- $env->is_literal = $is_literal;
- }
- if ($env->is_preview != $is_preview) {
- $env->is_preview = $is_preview;
- }
- if ($env->is_multiline != $request->is_multiline) {
- $env->is_multiline = $request->is_multiline;
- }
- if ($env->is_shown_once != $request->is_shown_once) {
- $env->is_shown_once = $request->is_shown_once;
- }
- $env->save();
-
- return response()->json($this->removeSensitiveData($env))->setStatusCode(201);
- } else {
- return response()->json([
- 'message' => 'Environment variable not found.',
- ], 404);
- }
- } else {
- $env = $application->environment_variables->where('key', $key)->first();
- if ($env) {
- $env->value = $request->value;
- if ($env->is_build_time != $is_build_time) {
- $env->is_build_time = $is_build_time;
- }
- if ($env->is_literal != $is_literal) {
- $env->is_literal = $is_literal;
- }
- if ($env->is_preview != $is_preview) {
- $env->is_preview = $is_preview;
- }
- if ($env->is_multiline != $request->is_multiline) {
- $env->is_multiline = $request->is_multiline;
- }
- if ($env->is_shown_once != $request->is_shown_once) {
- $env->is_shown_once = $request->is_shown_once;
- }
- $env->save();
-
- return response()->json($this->removeSensitiveData($env))->setStatusCode(201);
- } else {
- return response()->json([
- 'message' => 'Environment variable not found.',
- ], 404);
- }
- }
-
- return response()->json([
- 'message' => 'Something is not okay. Are you okay?',
- ], 500);
- }
-
- #[OA\Patch(
- summary: 'Update Envs (Bulk)',
- description: 'Update multiple envs by application UUID.',
- path: '/applications/{uuid}/envs/bulk',
- operationId: 'update-envs-by-application-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',
- )
- ),
- ],
- requestBody: new OA\RequestBody(
- description: 'Bulk envs updated.',
- required: true,
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['data'],
- properties: [
- 'data' => [
- 'type' => 'array',
- 'items' => new OA\Schema(
- type: 'object',
- properties: [
- 'key' => ['type' => 'string', 'description' => 'The key of the environment variable.'],
- 'value' => ['type' => 'string', 'description' => 'The value of the environment variable.'],
- 'is_preview' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in preview deployments.'],
- 'is_build_time' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in build time.'],
- 'is_literal' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is a literal, nothing espaced.'],
- 'is_multiline' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is multiline.'],
- 'is_shown_once' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable\'s value is shown on the UI.'],
- ],
- ),
- ],
- ],
- ),
- ),
- ],
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Environment variables updated.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Environment variables updated.'],
- ]
- )
- ),
- ]
- ),
- 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 create_bulk_envs(Request $request)
- {
- $teamId = getTeamIdFromToken();
-
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
-
- if (! $application) {
- return response()->json([
- 'message' => 'Application not found',
- ], 404);
- }
-
- $bulk_data = $request->get('data');
- if (! $bulk_data) {
- return response()->json([
- 'message' => 'Bulk data is required.',
- ], 400);
- }
- $bulk_data = collect($bulk_data)->map(function ($item) {
- return collect($item)->only(['key', 'value', 'is_preview', 'is_build_time', 'is_literal']);
- });
- $returnedEnvs = collect();
- foreach ($bulk_data as $item) {
- $validator = customApiValidator($item, [
- 'key' => 'string|required',
- 'value' => 'string|nullable',
- 'is_preview' => 'boolean',
- 'is_build_time' => 'boolean',
- 'is_literal' => 'boolean',
- 'is_multiline' => 'boolean',
- 'is_shown_once' => 'boolean',
- ]);
- if ($validator->fails()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
- $is_preview = $item->get('is_preview') ?? false;
- $is_build_time = $item->get('is_build_time') ?? false;
- $is_literal = $item->get('is_literal') ?? false;
- $is_multi_line = $item->get('is_multiline') ?? false;
- $is_shown_once = $item->get('is_shown_once') ?? false;
- $key = str($item->get('key'))->trim()->replace(' ', '_')->value;
- if ($is_preview) {
- $env = $application->environment_variables_preview->where('key', $key)->first();
- if ($env) {
- $env->value = $item->get('value');
- if ($env->is_build_time != $is_build_time) {
- $env->is_build_time = $is_build_time;
- }
- if ($env->is_literal != $is_literal) {
- $env->is_literal = $is_literal;
- }
- if ($env->is_multiline != $item->get('is_multiline')) {
- $env->is_multiline = $item->get('is_multiline');
- }
- if ($env->is_shown_once != $item->get('is_shown_once')) {
- $env->is_shown_once = $item->get('is_shown_once');
- }
- $env->save();
- } else {
- $env = $application->environment_variables()->create([
- 'key' => $item->get('key'),
- 'value' => $item->get('value'),
- 'is_preview' => $is_preview,
- 'is_build_time' => $is_build_time,
- 'is_literal' => $is_literal,
- 'is_multiline' => $is_multi_line,
- 'is_shown_once' => $is_shown_once,
- 'resourceable_type' => get_class($application),
- 'resourceable_id' => $application->id,
- ]);
- }
- } else {
- $env = $application->environment_variables->where('key', $key)->first();
- if ($env) {
- $env->value = $item->get('value');
- if ($env->is_build_time != $is_build_time) {
- $env->is_build_time = $is_build_time;
- }
- if ($env->is_literal != $is_literal) {
- $env->is_literal = $is_literal;
- }
- if ($env->is_multiline != $item->get('is_multiline')) {
- $env->is_multiline = $item->get('is_multiline');
- }
- if ($env->is_shown_once != $item->get('is_shown_once')) {
- $env->is_shown_once = $item->get('is_shown_once');
- }
- $env->save();
- } else {
- $env = $application->environment_variables()->create([
- 'key' => $item->get('key'),
- 'value' => $item->get('value'),
- 'is_preview' => $is_preview,
- 'is_build_time' => $is_build_time,
- 'is_literal' => $is_literal,
- 'is_multiline' => $is_multi_line,
- 'is_shown_once' => $is_shown_once,
- 'resourceable_type' => get_class($application),
- 'resourceable_id' => $application->id,
- ]);
- }
- }
- $returnedEnvs->push($this->removeSensitiveData($env));
- }
-
- return response()->json($returnedEnvs)->setStatusCode(201);
- }
-
- #[OA\Post(
- summary: 'Create Env',
- description: 'Create env by application UUID.',
- path: '/applications/{uuid}/envs',
- operationId: 'create-env-by-application-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',
- )
- ),
- ],
- requestBody: new OA\RequestBody(
- required: true,
- description: 'Env created.',
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'key' => ['type' => 'string', 'description' => 'The key of the environment variable.'],
- 'value' => ['type' => 'string', 'description' => 'The value of the environment variable.'],
- 'is_preview' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in preview deployments.'],
- 'is_build_time' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in build time.'],
- 'is_literal' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is a literal, nothing espaced.'],
- 'is_multiline' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is multiline.'],
- 'is_shown_once' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable\'s value is shown on the UI.'],
- ],
- ),
- ),
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Environment variable created.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'uuid' => ['type' => 'string', 'example' => 'nc0k04gk8g0cgsk440g0koko'],
- ]
- )
- ),
- ]
- ),
- 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 create_env(Request $request)
- {
- $allowedFields = ['key', 'value', 'is_preview', 'is_build_time', 'is_literal'];
- $teamId = getTeamIdFromToken();
-
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
-
- if (! $application) {
- return response()->json([
- 'message' => 'Application not found',
- ], 404);
- }
- $validator = customApiValidator($request->all(), [
- 'key' => 'string|required',
- 'value' => 'string|nullable',
- 'is_preview' => 'boolean',
- 'is_build_time' => 'boolean',
- 'is_literal' => 'boolean',
- 'is_multiline' => 'boolean',
- 'is_shown_once' => 'boolean',
- ]);
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- $is_preview = $request->is_preview ?? false;
- $key = str($request->key)->trim()->replace(' ', '_')->value;
-
- if ($is_preview) {
- $env = $application->environment_variables_preview->where('key', $key)->first();
- if ($env) {
- return response()->json([
- 'message' => 'Environment variable already exists. Use PATCH request to update it.',
- ], 409);
- } else {
- $env = $application->environment_variables()->create([
- 'key' => $request->key,
- 'value' => $request->value,
- 'is_preview' => $request->is_preview ?? false,
- 'is_build_time' => $request->is_build_time ?? false,
- 'is_literal' => $request->is_literal ?? false,
- 'is_multiline' => $request->is_multiline ?? false,
- 'is_shown_once' => $request->is_shown_once ?? false,
- 'resourceable_type' => get_class($application),
- 'resourceable_id' => $application->id,
- ]);
-
- return response()->json([
- 'uuid' => $env->uuid,
- ])->setStatusCode(201);
- }
- } else {
- $env = $application->environment_variables->where('key', $key)->first();
- if ($env) {
- return response()->json([
- 'message' => 'Environment variable already exists. Use PATCH request to update it.',
- ], 409);
- } else {
- $env = $application->environment_variables()->create([
- 'key' => $request->key,
- 'value' => $request->value,
- 'is_preview' => $request->is_preview ?? false,
- 'is_build_time' => $request->is_build_time ?? false,
- 'is_literal' => $request->is_literal ?? false,
- 'is_multiline' => $request->is_multiline ?? false,
- 'is_shown_once' => $request->is_shown_once ?? false,
- 'resourceable_type' => get_class($application),
- 'resourceable_id' => $application->id,
- ]);
-
- return response()->json([
- 'uuid' => $env->uuid,
- ])->setStatusCode(201);
- }
- }
-
- return response()->json([
- 'message' => 'Something went wrong.',
- ], 500);
- }
-
- #[OA\Delete(
- summary: 'Delete Env',
- description: 'Delete env by UUID.',
- path: '/applications/{uuid}/envs/{env_uuid}',
- operationId: 'delete-env-by-application-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',
- )
- ),
- new OA\Parameter(
- name: 'env_uuid',
- in: 'path',
- description: 'UUID of the environment variable.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Environment variable deleted.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Environment variable deleted.'],
- ]
- )
- ),
- ]
- ),
- 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 delete_env_by_uuid(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
-
- if (! $application) {
- return response()->json([
- 'message' => 'Application not found.',
- ], 404);
- }
- $found_env = EnvironmentVariable::where('uuid', $request->env_uuid)
- ->where('resourceable_type', Application::class)
- ->where('resourceable_id', $application->id)
- ->first();
- if (! $found_env) {
- return response()->json([
- 'message' => 'Environment variable not found.',
- ], 404);
- }
- $found_env->forceDelete();
-
- return response()->json([
- 'message' => 'Environment variable deleted.',
- ]);
- }
-
- #[OA\Get(
- summary: 'Start',
- description: 'Start application. `Post` request is also accepted.',
- path: '/applications/{uuid}/start',
- operationId: 'start-application-by-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',
- )
- ),
- new OA\Parameter(
- name: 'force',
- in: 'query',
- description: 'Force rebuild.',
- schema: new OA\Schema(
- type: 'boolean',
- default: false,
- )
- ),
- new OA\Parameter(
- name: 'instant_deploy',
- in: 'query',
- description: 'Instant deploy (skip queuing).',
- schema: new OA\Schema(
- type: 'boolean',
- default: false,
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Start application.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Deployment request queued.', 'description' => 'Message.'],
- 'deployment_uuid' => ['type' => 'string', 'example' => 'doogksw', 'description' => 'UUID of the deployment.'],
- ]
- )
- ),
- ]
- ),
- 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 action_deploy(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $force = $request->query->get('force') ?? false;
- $instant_deploy = $request->query->get('instant_deploy') ?? false;
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
- if (! $application) {
- return response()->json(['message' => 'Application not found.'], 404);
- }
-
- $deployment_uuid = new Cuid2;
-
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- force_rebuild: $force,
- is_api: true,
- no_questions_asked: $instant_deploy
- );
-
- return response()->json(
- [
- 'message' => 'Deployment request queued.',
- 'deployment_uuid' => $deployment_uuid->toString(),
- ],
- 200
- );
- }
-
- #[OA\Get(
- summary: 'Stop',
- description: 'Stop application. `Post` request is also accepted.',
- path: '/applications/{uuid}/stop',
- operationId: 'stop-application-by-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: 'Stop application.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Application stopping request queued.'],
- ]
- )
- ),
- ]
- ),
- 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 action_stop(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
- if (! $application) {
- return response()->json(['message' => 'Application not found.'], 404);
- }
- StopApplication::dispatch($application);
-
- return response()->json(
- [
- 'message' => 'Application stopping request queued.',
- ],
- );
- }
-
- #[OA\Get(
- summary: 'Restart',
- description: 'Restart application. `Post` request is also accepted.',
- path: '/applications/{uuid}/restart',
- operationId: 'restart-application-by-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: 'Restart application.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Restart request queued.'],
- 'deployment_uuid' => ['type' => 'string', 'example' => 'doogksw', 'description' => 'UUID of the deployment.'],
- ]
- )
- ),
- ]
- ),
-
- 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 action_restart(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
- if (! $application) {
- return response()->json(['message' => 'Application not found.'], 404);
- }
-
- $deployment_uuid = new Cuid2;
-
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- restart_only: true,
- is_api: true,
- );
-
- return response()->json(
- [
- 'message' => 'Restart request queued.',
- 'deployment_uuid' => $deployment_uuid->toString(),
- ],
- );
- }
-
- #[OA\Post(
- summary: 'Execute Command',
- description: "Execute a command on the application's current container.",
- path: '/applications/{uuid}/execute',
- operationId: 'execute-command-application',
- 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',
- )
- ),
- ],
- requestBody: new OA\RequestBody(
- required: true,
- description: 'Command to execute.',
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'command' => ['type' => 'string', 'description' => 'Command to execute.'],
- ],
- ),
- ),
- ),
- responses: [
- new OA\Response(
- response: 200,
- description: "Execute a command on the application's current container.",
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Command executed.'],
- 'response' => ['type' => 'string'],
- ]
- )
- ),
- ]
- ),
- 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 execute_command_by_uuid(Request $request)
- {
- // TODO: Need to review this from security perspective, to not allow arbitrary command execution
- $allowedFields = ['command'];
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
- if (! $application) {
- return response()->json(['message' => 'Application not found.'], 404);
- }
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $validator = customApiValidator($request->all(), [
- 'command' => 'string|required',
- ]);
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
-
- $container = getCurrentApplicationContainerStatus($application->destination->server, $application->id)->firstOrFail();
- $status = getContainerStatus($application->destination->server, $container['Names']);
-
- if ($status !== 'running') {
- return response()->json([
- 'message' => 'Application is not running.',
- ], 400);
- }
-
- $commands = collect([
- executeInDocker($container['Names'], $request->command),
- ]);
-
- $res = instant_remote_process(command: $commands, server: $application->destination->server);
-
- return response()->json([
- 'message' => 'Command executed.',
- 'response' => $res,
- ]);
- }
-
- private function validateDataApplications(Request $request, Server $server)
- {
- $teamId = getTeamIdFromToken();
-
- // Validate ports_mappings
- if ($request->has('ports_mappings')) {
- $ports = [];
- foreach (explode(',', $request->ports_mappings) as $portMapping) {
- $port = explode(':', $portMapping);
- if (in_array($port[0], $ports)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'ports_mappings' => 'The first number before : should be unique between mappings.',
- ],
- ], 422);
- }
- $ports[] = $port[0];
- }
- }
- // Validate custom_labels
- if ($request->has('custom_labels')) {
- if (! isBase64Encoded($request->custom_labels)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'custom_labels' => 'The custom_labels should be base64 encoded.',
- ],
- ], 422);
- }
- $customLabels = base64_decode($request->custom_labels);
- if (mb_detect_encoding($customLabels, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'custom_labels' => 'The custom_labels should be base64 encoded.',
- ],
- ], 422);
- }
- }
- if ($request->has('domains') && $server->isProxyShouldRun()) {
- $uuid = $request->uuid;
- $fqdn = $request->domains;
- $fqdn = str($fqdn)->replaceEnd(',', '')->trim();
- $fqdn = str($fqdn)->replaceStart(',', '')->trim();
- $errors = [];
- $fqdn = str($fqdn)->trim()->explode(',')->map(function ($domain) use (&$errors) {
- if (filter_var($domain, FILTER_VALIDATE_URL) === false) {
- $errors[] = 'Invalid domain: '.$domain;
- }
-
- return str($domain)->trim()->lower();
- });
- if (count($errors) > 0) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- if (checkIfDomainIsAlreadyUsed($fqdn, $teamId, $uuid)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'domains' => 'One of the domain is already used.',
- ],
- ], 422);
- }
- }
- }
-}
diff --git a/app/Http/Controllers/Api/DatabasesController.php b/app/Http/Controllers/Api/DatabasesController.php
deleted file mode 100644
index 504665f6a8..0000000000
--- a/app/Http/Controllers/Api/DatabasesController.php
+++ /dev/null
@@ -1,1852 +0,0 @@
-makeHidden([
- 'id',
- 'laravel_through_key',
- ]);
- if (request()->attributes->get('can_read_sensitive', false) === false) {
- $database->makeHidden([
- 'internal_db_url',
- 'external_db_url',
- 'postgres_password',
- 'dragonfly_password',
- 'redis_password',
- 'mongo_initdb_root_password',
- 'keydb_password',
- 'clickhouse_admin_password',
- ]);
- }
-
- return serializeApiResponse($database);
- }
-
- #[OA\Get(
- summary: 'List',
- description: 'List all databases.',
- path: '/databases',
- operationId: 'list-databases',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Get all databases',
- 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 databases(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $projects = Project::where('team_id', $teamId)->get();
- $databases = collect();
- foreach ($projects as $project) {
- $databases = $databases->merge($project->databases());
- }
- $databases = $databases->map(function ($database) {
- return $this->removeSensitiveData($database);
- });
-
- return response()->json($databases);
- }
-
- #[OA\Get(
- summary: 'Get',
- description: 'Get database by UUID.',
- path: '/databases/{uuid}',
- operationId: 'get-database-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the database.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Get all databases',
- 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',
- ),
- new OA\Response(
- response: 404,
- ref: '#/components/responses/404',
- ),
- ]
- )]
- public function database_by_uuid(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- if (! $request->uuid) {
- return response()->json(['message' => 'UUID is required.'], 404);
- }
- $database = queryDatabaseByUuidWithinTeam($request->uuid, $teamId);
- if (! $database) {
- return response()->json(['message' => 'Database not found.'], 404);
- }
-
- return response()->json($this->removeSensitiveData($database));
- }
-
- #[OA\Patch(
- summary: 'Update',
- description: 'Update database by UUID.',
- path: '/databases/{uuid}',
- operationId: 'update-database-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the database.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- requestBody: new OA\RequestBody(
- description: 'Database data',
- required: true,
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'name' => ['type' => 'string', 'description' => 'Name of the database'],
- 'description' => ['type' => 'string', 'description' => 'Description of the database'],
- 'image' => ['type' => 'string', 'description' => 'Docker Image of the database'],
- 'is_public' => ['type' => 'boolean', 'description' => 'Is the database public?'],
- 'public_port' => ['type' => 'integer', 'description' => 'Public port of the database'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit of the database'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit of the database'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness of the database'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation of the database'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit of the database'],
- 'limits_cpuset' => ['type' => 'string', 'description' => 'CPU set of the database'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares of the database'],
- 'postgres_user' => ['type' => 'string', 'description' => 'PostgreSQL user'],
- 'postgres_password' => ['type' => 'string', 'description' => 'PostgreSQL password'],
- 'postgres_db' => ['type' => 'string', 'description' => 'PostgreSQL database'],
- 'postgres_initdb_args' => ['type' => 'string', 'description' => 'PostgreSQL initdb args'],
- 'postgres_host_auth_method' => ['type' => 'string', 'description' => 'PostgreSQL host auth method'],
- 'postgres_conf' => ['type' => 'string', 'description' => 'PostgreSQL conf'],
- 'clickhouse_admin_user' => ['type' => 'string', 'description' => 'Clickhouse admin user'],
- 'clickhouse_admin_password' => ['type' => 'string', 'description' => 'Clickhouse admin password'],
- 'dragonfly_password' => ['type' => 'string', 'description' => 'DragonFly password'],
- 'redis_password' => ['type' => 'string', 'description' => 'Redis password'],
- 'redis_conf' => ['type' => 'string', 'description' => 'Redis conf'],
- 'keydb_password' => ['type' => 'string', 'description' => 'KeyDB password'],
- 'keydb_conf' => ['type' => 'string', 'description' => 'KeyDB conf'],
- 'mariadb_conf' => ['type' => 'string', 'description' => 'MariaDB conf'],
- 'mariadb_root_password' => ['type' => 'string', 'description' => 'MariaDB root password'],
- 'mariadb_user' => ['type' => 'string', 'description' => 'MariaDB user'],
- 'mariadb_password' => ['type' => 'string', 'description' => 'MariaDB password'],
- 'mariadb_database' => ['type' => 'string', 'description' => 'MariaDB database'],
- 'mongo_conf' => ['type' => 'string', 'description' => 'Mongo conf'],
- 'mongo_initdb_root_username' => ['type' => 'string', 'description' => 'Mongo initdb root username'],
- 'mongo_initdb_root_password' => ['type' => 'string', 'description' => 'Mongo initdb root password'],
- 'mongo_initdb_database' => ['type' => 'string', 'description' => 'Mongo initdb init database'],
- 'mysql_root_password' => ['type' => 'string', 'description' => 'MySQL root password'],
- 'mysql_password' => ['type' => 'string', 'description' => 'MySQL password'],
- 'mysql_user' => ['type' => 'string', 'description' => 'MySQL user'],
- 'mysql_database' => ['type' => 'string', 'description' => 'MySQL database'],
- 'mysql_conf' => ['type' => 'string', 'description' => 'MySQL conf'],
- ],
- ),
- )
- ),
- responses: [
- new OA\Response(
- response: 200,
- description: 'Database updated',
- ),
- 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 update_by_uuid(Request $request)
- {
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'postgres_user', 'postgres_password', 'postgres_db', 'postgres_initdb_args', 'postgres_host_auth_method', 'postgres_conf', 'clickhouse_admin_user', 'clickhouse_admin_password', 'dragonfly_password', 'redis_password', 'redis_conf', 'keydb_password', 'keydb_conf', 'mariadb_conf', 'mariadb_root_password', 'mariadb_user', 'mariadb_password', 'mariadb_database', 'mongo_conf', 'mongo_initdb_root_username', 'mongo_initdb_root_password', 'mongo_initdb_database', 'mysql_root_password', 'mysql_password', 'mysql_user', 'mysql_database', 'mysql_conf'];
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $validator = customApiValidator($request->all(), [
- 'name' => 'string|max:255',
- 'description' => 'string|nullable',
- 'image' => 'string',
- 'is_public' => 'boolean',
- 'public_port' => 'numeric|nullable',
- 'limits_memory' => 'string',
- 'limits_memory_swap' => 'string',
- 'limits_memory_swappiness' => 'numeric',
- 'limits_memory_reservation' => 'string',
- 'limits_cpus' => 'string',
- 'limits_cpuset' => 'string|nullable',
- 'limits_cpu_shares' => 'numeric',
- ]);
-
- if ($validator->fails()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
- $uuid = $request->uuid;
- removeUnnecessaryFieldsFromRequest($request);
- $database = queryDatabaseByUuidWithinTeam($uuid, $teamId);
- if (! $database) {
- return response()->json(['message' => 'Database not found.'], 404);
- }
- if ($request->is_public && $request->public_port) {
- if (isPublicPortAlreadyUsed($database->destination->server, $request->public_port, $database->id)) {
- return response()->json(['message' => 'Public port already used by another database.'], 400);
- }
- }
- switch ($database->type()) {
- case 'standalone-postgresql':
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'postgres_user', 'postgres_password', 'postgres_db', 'postgres_initdb_args', 'postgres_host_auth_method', 'postgres_conf'];
- $validator = customApiValidator($request->all(), [
- 'postgres_user' => 'string',
- 'postgres_password' => 'string',
- 'postgres_db' => 'string',
- 'postgres_initdb_args' => 'string',
- 'postgres_host_auth_method' => 'string',
- 'postgres_conf' => 'string',
- ]);
- if ($request->has('postgres_conf')) {
- if (! isBase64Encoded($request->postgres_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'postgres_conf' => 'The postgres_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $postgresConf = base64_decode($request->postgres_conf);
- if (mb_detect_encoding($postgresConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'postgres_conf' => 'The postgres_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('postgres_conf', $postgresConf);
- }
- break;
- case 'standalone-clickhouse':
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'clickhouse_admin_user', 'clickhouse_admin_password'];
- $validator = customApiValidator($request->all(), [
- 'clickhouse_admin_user' => 'string',
- 'clickhouse_admin_password' => 'string',
- ]);
- break;
- case 'standalone-dragonfly':
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'dragonfly_password'];
- $validator = customApiValidator($request->all(), [
- 'dragonfly_password' => 'string',
- ]);
- break;
- case 'standalone-redis':
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'redis_password', 'redis_conf'];
- $validator = customApiValidator($request->all(), [
- 'redis_password' => 'string',
- 'redis_conf' => 'string',
- ]);
- if ($request->has('redis_conf')) {
- if (! isBase64Encoded($request->redis_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'redis_conf' => 'The redis_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $redisConf = base64_decode($request->redis_conf);
- if (mb_detect_encoding($redisConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'redis_conf' => 'The redis_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('redis_conf', $redisConf);
- }
- break;
- case 'standalone-keydb':
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'keydb_password', 'keydb_conf'];
- $validator = customApiValidator($request->all(), [
- 'keydb_password' => 'string',
- 'keydb_conf' => 'string',
- ]);
- if ($request->has('keydb_conf')) {
- if (! isBase64Encoded($request->keydb_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'keydb_conf' => 'The keydb_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $keydbConf = base64_decode($request->keydb_conf);
- if (mb_detect_encoding($keydbConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'keydb_conf' => 'The keydb_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('keydb_conf', $keydbConf);
- }
- break;
- case 'standalone-mariadb':
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mariadb_conf', 'mariadb_root_password', 'mariadb_user', 'mariadb_password', 'mariadb_database'];
- $validator = customApiValidator($request->all(), [
- 'mariadb_conf' => 'string',
- 'mariadb_root_password' => 'string',
- 'mariadb_user' => 'string',
- 'mariadb_password' => 'string',
- 'mariadb_database' => 'string',
- ]);
- if ($request->has('mariadb_conf')) {
- if (! isBase64Encoded($request->mariadb_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mariadb_conf' => 'The mariadb_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $mariadbConf = base64_decode($request->mariadb_conf);
- if (mb_detect_encoding($mariadbConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mariadb_conf' => 'The mariadb_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('mariadb_conf', $mariadbConf);
- }
- break;
- case 'standalone-mongodb':
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mongo_conf', 'mongo_initdb_root_username', 'mongo_initdb_root_password', 'mongo_initdb_database'];
- $validator = customApiValidator($request->all(), [
- 'mongo_conf' => 'string',
- 'mongo_initdb_root_username' => 'string',
- 'mongo_initdb_root_password' => 'string',
- 'mongo_initdb_database' => 'string',
- ]);
- if ($request->has('mongo_conf')) {
- if (! isBase64Encoded($request->mongo_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mongo_conf' => 'The mongo_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $mongoConf = base64_decode($request->mongo_conf);
- if (mb_detect_encoding($mongoConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mongo_conf' => 'The mongo_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('mongo_conf', $mongoConf);
- }
-
- break;
- case 'standalone-mysql':
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mysql_root_password', 'mysql_password', 'mysql_user', 'mysql_database', 'mysql_conf'];
- $validator = customApiValidator($request->all(), [
- 'mysql_root_password' => 'string',
- 'mysql_password' => 'string',
- 'mysql_user' => 'string',
- 'mysql_database' => 'string',
- 'mysql_conf' => 'string',
- ]);
- if ($request->has('mysql_conf')) {
- if (! isBase64Encoded($request->mysql_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mysql_conf' => 'The mysql_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $mysqlConf = base64_decode($request->mysql_conf);
- if (mb_detect_encoding($mysqlConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mysql_conf' => 'The mysql_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('mysql_conf', $mysqlConf);
- }
- break;
- }
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- $whatToDoWithDatabaseProxy = null;
- if ($request->is_public === false && $database->is_public === true) {
- $whatToDoWithDatabaseProxy = 'stop';
- }
- if ($request->is_public === true && $request->public_port && $database->is_public === false) {
- $whatToDoWithDatabaseProxy = 'start';
- }
-
- $database->update($request->all());
-
- if ($whatToDoWithDatabaseProxy === 'start') {
- StartDatabaseProxy::dispatch($database);
- } elseif ($whatToDoWithDatabaseProxy === 'stop') {
- StopDatabaseProxy::dispatch($database);
- }
-
- return response()->json([
- 'message' => 'Database updated.',
- ]);
- }
-
- #[OA\Post(
- summary: 'Create (PostgreSQL)',
- description: 'Create a new PostgreSQL database.',
- path: '/databases/postgresql',
- operationId: 'create-database-postgresql',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
-
- requestBody: new OA\RequestBody(
- description: 'Database data',
- required: true,
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['server_uuid', 'project_uuid', 'environment_name', 'environment_uuid'],
- properties: [
- 'server_uuid' => ['type' => 'string', 'description' => 'UUID of the server'],
- 'project_uuid' => ['type' => 'string', 'description' => 'UUID of the project'],
- 'environment_name' => ['type' => 'string', 'description' => 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'postgres_user' => ['type' => 'string', 'description' => 'PostgreSQL user'],
- 'postgres_password' => ['type' => 'string', 'description' => 'PostgreSQL password'],
- 'postgres_db' => ['type' => 'string', 'description' => 'PostgreSQL database'],
- 'postgres_initdb_args' => ['type' => 'string', 'description' => 'PostgreSQL initdb args'],
- 'postgres_host_auth_method' => ['type' => 'string', 'description' => 'PostgreSQL host auth method'],
- 'postgres_conf' => ['type' => 'string', 'description' => 'PostgreSQL conf'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'UUID of the destination if the server has multiple destinations'],
- 'name' => ['type' => 'string', 'description' => 'Name of the database'],
- 'description' => ['type' => 'string', 'description' => 'Description of the database'],
- 'image' => ['type' => 'string', 'description' => 'Docker Image of the database'],
- 'is_public' => ['type' => 'boolean', 'description' => 'Is the database public?'],
- 'public_port' => ['type' => 'integer', 'description' => 'Public port of the database'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit of the database'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit of the database'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness of the database'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation of the database'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit of the database'],
- 'limits_cpuset' => ['type' => 'string', 'description' => 'CPU set of the database'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares of the database'],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'Instant deploy the database'],
- ],
- ),
- )
- ),
- responses: [
- new OA\Response(
- response: 200,
- description: 'Database updated',
- ),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function create_database_postgresql(Request $request)
- {
- return $this->create_database($request, NewDatabaseTypes::POSTGRESQL);
- }
-
- #[OA\Post(
- summary: 'Create (Clickhouse)',
- description: 'Create a new Clickhouse database.',
- path: '/databases/clickhouse',
- operationId: 'create-database-clickhouse',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
-
- requestBody: new OA\RequestBody(
- description: 'Database data',
- required: true,
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['server_uuid', 'project_uuid', 'environment_name', 'environment_uuid'],
- properties: [
- 'server_uuid' => ['type' => 'string', 'description' => 'UUID of the server'],
- 'project_uuid' => ['type' => 'string', 'description' => 'UUID of the project'],
- 'environment_name' => ['type' => 'string', 'description' => 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'UUID of the destination if the server has multiple destinations'],
- 'clickhouse_admin_user' => ['type' => 'string', 'description' => 'Clickhouse admin user'],
- 'clickhouse_admin_password' => ['type' => 'string', 'description' => 'Clickhouse admin password'],
- 'name' => ['type' => 'string', 'description' => 'Name of the database'],
- 'description' => ['type' => 'string', 'description' => 'Description of the database'],
- 'image' => ['type' => 'string', 'description' => 'Docker Image of the database'],
- 'is_public' => ['type' => 'boolean', 'description' => 'Is the database public?'],
- 'public_port' => ['type' => 'integer', 'description' => 'Public port of the database'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit of the database'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit of the database'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness of the database'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation of the database'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit of the database'],
- 'limits_cpuset' => ['type' => 'string', 'description' => 'CPU set of the database'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares of the database'],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'Instant deploy the database'],
- ],
- ),
- )
- ),
- responses: [
- new OA\Response(
- response: 200,
- description: 'Database updated',
- ),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function create_database_clickhouse(Request $request)
- {
- return $this->create_database($request, NewDatabaseTypes::CLICKHOUSE);
- }
-
- #[OA\Post(
- summary: 'Create (DragonFly)',
- description: 'Create a new DragonFly database.',
- path: '/databases/dragonfly',
- operationId: 'create-database-dragonfly',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
-
- requestBody: new OA\RequestBody(
- description: 'Database data',
- required: true,
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['server_uuid', 'project_uuid', 'environment_name', 'environment_uuid'],
- properties: [
- 'server_uuid' => ['type' => 'string', 'description' => 'UUID of the server'],
- 'project_uuid' => ['type' => 'string', 'description' => 'UUID of the project'],
- 'environment_name' => ['type' => 'string', 'description' => 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'UUID of the destination if the server has multiple destinations'],
- 'dragonfly_password' => ['type' => 'string', 'description' => 'DragonFly password'],
- 'name' => ['type' => 'string', 'description' => 'Name of the database'],
- 'description' => ['type' => 'string', 'description' => 'Description of the database'],
- 'image' => ['type' => 'string', 'description' => 'Docker Image of the database'],
- 'is_public' => ['type' => 'boolean', 'description' => 'Is the database public?'],
- 'public_port' => ['type' => 'integer', 'description' => 'Public port of the database'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit of the database'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit of the database'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness of the database'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation of the database'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit of the database'],
- 'limits_cpuset' => ['type' => 'string', 'description' => 'CPU set of the database'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares of the database'],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'Instant deploy the database'],
- ],
- ),
- )
- ),
- responses: [
- new OA\Response(
- response: 200,
- description: 'Database updated',
- ),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function create_database_dragonfly(Request $request)
- {
- return $this->create_database($request, NewDatabaseTypes::DRAGONFLY);
- }
-
- #[OA\Post(
- summary: 'Create (Redis)',
- description: 'Create a new Redis database.',
- path: '/databases/redis',
- operationId: 'create-database-redis',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
-
- requestBody: new OA\RequestBody(
- description: 'Database data',
- required: true,
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['server_uuid', 'project_uuid', 'environment_name', 'environment_uuid'],
- properties: [
- 'server_uuid' => ['type' => 'string', 'description' => 'UUID of the server'],
- 'project_uuid' => ['type' => 'string', 'description' => 'UUID of the project'],
- 'environment_name' => ['type' => 'string', 'description' => 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'UUID of the destination if the server has multiple destinations'],
- 'redis_password' => ['type' => 'string', 'description' => 'Redis password'],
- 'redis_conf' => ['type' => 'string', 'description' => 'Redis conf'],
- 'name' => ['type' => 'string', 'description' => 'Name of the database'],
- 'description' => ['type' => 'string', 'description' => 'Description of the database'],
- 'image' => ['type' => 'string', 'description' => 'Docker Image of the database'],
- 'is_public' => ['type' => 'boolean', 'description' => 'Is the database public?'],
- 'public_port' => ['type' => 'integer', 'description' => 'Public port of the database'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit of the database'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit of the database'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness of the database'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation of the database'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit of the database'],
- 'limits_cpuset' => ['type' => 'string', 'description' => 'CPU set of the database'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares of the database'],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'Instant deploy the database'],
- ],
- ),
- )
- ),
- responses: [
- new OA\Response(
- response: 200,
- description: 'Database updated',
- ),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function create_database_redis(Request $request)
- {
- return $this->create_database($request, NewDatabaseTypes::REDIS);
- }
-
- #[OA\Post(
- summary: 'Create (KeyDB)',
- description: 'Create a new KeyDB database.',
- path: '/databases/keydb',
- operationId: 'create-database-keydb',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
-
- requestBody: new OA\RequestBody(
- description: 'Database data',
- required: true,
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['server_uuid', 'project_uuid', 'environment_name', 'environment_uuid'],
- properties: [
- 'server_uuid' => ['type' => 'string', 'description' => 'UUID of the server'],
- 'project_uuid' => ['type' => 'string', 'description' => 'UUID of the project'],
- 'environment_name' => ['type' => 'string', 'description' => 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'UUID of the destination if the server has multiple destinations'],
- 'keydb_password' => ['type' => 'string', 'description' => 'KeyDB password'],
- 'keydb_conf' => ['type' => 'string', 'description' => 'KeyDB conf'],
- 'name' => ['type' => 'string', 'description' => 'Name of the database'],
- 'description' => ['type' => 'string', 'description' => 'Description of the database'],
- 'image' => ['type' => 'string', 'description' => 'Docker Image of the database'],
- 'is_public' => ['type' => 'boolean', 'description' => 'Is the database public?'],
- 'public_port' => ['type' => 'integer', 'description' => 'Public port of the database'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit of the database'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit of the database'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness of the database'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation of the database'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit of the database'],
- 'limits_cpuset' => ['type' => 'string', 'description' => 'CPU set of the database'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares of the database'],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'Instant deploy the database'],
- ],
- ),
- )
- ),
- responses: [
- new OA\Response(
- response: 200,
- description: 'Database updated',
- ),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function create_database_keydb(Request $request)
- {
- return $this->create_database($request, NewDatabaseTypes::KEYDB);
- }
-
- #[OA\Post(
- summary: 'Create (MariaDB)',
- description: 'Create a new MariaDB database.',
- path: '/databases/mariadb',
- operationId: 'create-database-mariadb',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
-
- requestBody: new OA\RequestBody(
- description: 'Database data',
- required: true,
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['server_uuid', 'project_uuid', 'environment_name', 'environment_uuid'],
- properties: [
- 'server_uuid' => ['type' => 'string', 'description' => 'UUID of the server'],
- 'project_uuid' => ['type' => 'string', 'description' => 'UUID of the project'],
- 'environment_name' => ['type' => 'string', 'description' => 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'UUID of the destination if the server has multiple destinations'],
- 'mariadb_conf' => ['type' => 'string', 'description' => 'MariaDB conf'],
- 'mariadb_root_password' => ['type' => 'string', 'description' => 'MariaDB root password'],
- 'mariadb_user' => ['type' => 'string', 'description' => 'MariaDB user'],
- 'mariadb_password' => ['type' => 'string', 'description' => 'MariaDB password'],
- 'mariadb_database' => ['type' => 'string', 'description' => 'MariaDB database'],
- 'name' => ['type' => 'string', 'description' => 'Name of the database'],
- 'description' => ['type' => 'string', 'description' => 'Description of the database'],
- 'image' => ['type' => 'string', 'description' => 'Docker Image of the database'],
- 'is_public' => ['type' => 'boolean', 'description' => 'Is the database public?'],
- 'public_port' => ['type' => 'integer', 'description' => 'Public port of the database'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit of the database'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit of the database'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness of the database'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation of the database'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit of the database'],
- 'limits_cpuset' => ['type' => 'string', 'description' => 'CPU set of the database'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares of the database'],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'Instant deploy the database'],
- ],
- ),
- )
- ),
- responses: [
- new OA\Response(
- response: 200,
- description: 'Database updated',
- ),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function create_database_mariadb(Request $request)
- {
- return $this->create_database($request, NewDatabaseTypes::MARIADB);
- }
-
- #[OA\Post(
- summary: 'Create (MySQL)',
- description: 'Create a new MySQL database.',
- path: '/databases/mysql',
- operationId: 'create-database-mysql',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
-
- requestBody: new OA\RequestBody(
- description: 'Database data',
- required: true,
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['server_uuid', 'project_uuid', 'environment_name', 'environment_uuid'],
- properties: [
- 'server_uuid' => ['type' => 'string', 'description' => 'UUID of the server'],
- 'project_uuid' => ['type' => 'string', 'description' => 'UUID of the project'],
- 'environment_name' => ['type' => 'string', 'description' => 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'UUID of the destination if the server has multiple destinations'],
- 'mysql_root_password' => ['type' => 'string', 'description' => 'MySQL root password'],
- 'mysql_password' => ['type' => 'string', 'description' => 'MySQL password'],
- 'mysql_user' => ['type' => 'string', 'description' => 'MySQL user'],
- 'mysql_database' => ['type' => 'string', 'description' => 'MySQL database'],
- 'mysql_conf' => ['type' => 'string', 'description' => 'MySQL conf'],
- 'name' => ['type' => 'string', 'description' => 'Name of the database'],
- 'description' => ['type' => 'string', 'description' => 'Description of the database'],
- 'image' => ['type' => 'string', 'description' => 'Docker Image of the database'],
- 'is_public' => ['type' => 'boolean', 'description' => 'Is the database public?'],
- 'public_port' => ['type' => 'integer', 'description' => 'Public port of the database'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit of the database'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit of the database'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness of the database'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation of the database'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit of the database'],
- 'limits_cpuset' => ['type' => 'string', 'description' => 'CPU set of the database'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares of the database'],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'Instant deploy the database'],
- ],
- ),
- )
- ),
- responses: [
- new OA\Response(
- response: 200,
- description: 'Database updated',
- ),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function create_database_mysql(Request $request)
- {
- return $this->create_database($request, NewDatabaseTypes::MYSQL);
- }
-
- #[OA\Post(
- summary: 'Create (MongoDB)',
- description: 'Create a new MongoDB database.',
- path: '/databases/mongodb',
- operationId: 'create-database-mongodb',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
-
- requestBody: new OA\RequestBody(
- description: 'Database data',
- required: true,
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['server_uuid', 'project_uuid', 'environment_name', 'environment_uuid'],
- properties: [
- 'server_uuid' => ['type' => 'string', 'description' => 'UUID of the server'],
- 'project_uuid' => ['type' => 'string', 'description' => 'UUID of the project'],
- 'environment_name' => ['type' => 'string', 'description' => 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'UUID of the destination if the server has multiple destinations'],
- 'mongo_conf' => ['type' => 'string', 'description' => 'MongoDB conf'],
- 'mongo_initdb_root_username' => ['type' => 'string', 'description' => 'MongoDB initdb root username'],
- 'name' => ['type' => 'string', 'description' => 'Name of the database'],
- 'description' => ['type' => 'string', 'description' => 'Description of the database'],
- 'image' => ['type' => 'string', 'description' => 'Docker Image of the database'],
- 'is_public' => ['type' => 'boolean', 'description' => 'Is the database public?'],
- 'public_port' => ['type' => 'integer', 'description' => 'Public port of the database'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit of the database'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit of the database'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness of the database'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation of the database'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit of the database'],
- 'limits_cpuset' => ['type' => 'string', 'description' => 'CPU set of the database'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares of the database'],
- 'instant_deploy' => ['type' => 'boolean', 'description' => 'Instant deploy the database'],
- ],
- ),
- )
- ),
- responses: [
- new OA\Response(
- response: 200,
- description: 'Database updated',
- ),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function create_database_mongodb(Request $request)
- {
- return $this->create_database($request, NewDatabaseTypes::MONGODB);
- }
-
- public function create_database(Request $request, NewDatabaseTypes $type)
- {
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'postgres_user', 'postgres_password', 'postgres_db', 'postgres_initdb_args', 'postgres_host_auth_method', 'postgres_conf', 'clickhouse_admin_user', 'clickhouse_admin_password', 'dragonfly_password', 'redis_password', 'redis_conf', 'keydb_password', 'keydb_conf', 'mariadb_conf', 'mariadb_root_password', 'mariadb_user', 'mariadb_password', 'mariadb_database', 'mongo_conf', 'mongo_initdb_root_username', 'mongo_initdb_root_password', 'mongo_initdb_database', 'mysql_root_password', 'mysql_password', 'mysql_user', 'mysql_database', 'mysql_conf'];
-
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if (! empty($extraFields)) {
- $errors = collect([]);
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- $environmentUuid = $request->environment_uuid;
- $environmentName = $request->environment_name;
- if (blank($environmentUuid) && blank($environmentName)) {
- return response()->json(['message' => 'You need to provide at least one of environment_name or environment_uuid.'], 422);
- }
- $serverUuid = $request->server_uuid;
- $instantDeploy = $request->instant_deploy ?? false;
- if ($request->is_public && ! $request->public_port) {
- $request->offsetSet('is_public', false);
- }
- $project = Project::whereTeamId($teamId)->whereUuid($request->project_uuid)->first();
- if (! $project) {
- return response()->json(['message' => 'Project not found.'], 404);
- }
- $environment = $project->environments()->where('name', $environmentName)->first();
- if (! $environment) {
- $environment = $project->environments()->where('uuid', $environmentUuid)->first();
- }
- if (! $environment) {
- return response()->json(['message' => 'You need to provide a valid environment_name or environment_uuid.'], 422);
- }
- $server = Server::whereTeamId($teamId)->whereUuid($serverUuid)->first();
- if (! $server) {
- return response()->json(['message' => 'Server not found.'], 404);
- }
- $destinations = $server->destinations();
- if ($destinations->count() == 0) {
- return response()->json(['message' => 'Server has no destinations.'], 400);
- }
- if ($destinations->count() > 1 && ! $request->has('destination_uuid')) {
- return response()->json(['message' => 'Server has multiple destinations and you do not set destination_uuid.'], 400);
- }
- $destination = $destinations->first();
- if ($request->has('public_port') && $request->is_public) {
- if (isPublicPortAlreadyUsed($server, $request->public_port)) {
- return response()->json(['message' => 'Public port already used by another database.'], 400);
- }
- }
- $validator = customApiValidator($request->all(), [
- 'name' => 'string|max:255',
- 'description' => 'string|nullable',
- 'image' => 'string',
- 'project_uuid' => 'string|required',
- 'environment_name' => 'string|nullable',
- 'environment_uuid' => 'string|nullable',
- 'server_uuid' => 'string|required',
- 'destination_uuid' => 'string',
- 'is_public' => 'boolean',
- 'public_port' => 'numeric|nullable',
- 'limits_memory' => 'string',
- 'limits_memory_swap' => 'string',
- 'limits_memory_swappiness' => 'numeric',
- 'limits_memory_reservation' => 'string',
- 'limits_cpus' => 'string',
- 'limits_cpuset' => 'string|nullable',
- 'limits_cpu_shares' => 'numeric',
- 'instant_deploy' => 'boolean',
- ]);
- if ($validator->failed()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
- if ($request->public_port) {
- if ($request->public_port < 1024 || $request->public_port > 65535) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'public_port' => 'The public port should be between 1024 and 65535.',
- ],
- ], 422);
- }
- }
- if ($type === NewDatabaseTypes::POSTGRESQL) {
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'postgres_user', 'postgres_password', 'postgres_db', 'postgres_initdb_args', 'postgres_host_auth_method', 'postgres_conf'];
- $validator = customApiValidator($request->all(), [
- 'postgres_user' => 'string',
- 'postgres_password' => 'string',
- 'postgres_db' => 'string',
- 'postgres_initdb_args' => 'string',
- 'postgres_host_auth_method' => 'string',
- 'postgres_conf' => 'string',
- ]);
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- removeUnnecessaryFieldsFromRequest($request);
- if ($request->has('postgres_conf')) {
- if (! isBase64Encoded($request->postgres_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'postgres_conf' => 'The postgres_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $postgresConf = base64_decode($request->postgres_conf);
- if (mb_detect_encoding($postgresConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'postgres_conf' => 'The postgres_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('postgres_conf', $postgresConf);
- }
- $database = create_standalone_postgresql($environment->id, $destination->uuid, $request->all());
- if ($instantDeploy) {
- StartDatabase::dispatch($database);
- }
- $database->refresh();
- $payload = [
- 'uuid' => $database->uuid,
- 'internal_db_url' => $database->internal_db_url,
- ];
- if ($database->is_public && $database->public_port) {
- $payload['external_db_url'] = $database->external_db_url;
- }
-
- return response()->json(serializeApiResponse($payload))->setStatusCode(201);
- } elseif ($type === NewDatabaseTypes::MARIADB) {
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mariadb_conf', 'mariadb_root_password', 'mariadb_user', 'mariadb_password', 'mariadb_database'];
- $validator = customApiValidator($request->all(), [
- 'clickhouse_admin_user' => 'string',
- 'clickhouse_admin_password' => 'string',
- ]);
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- removeUnnecessaryFieldsFromRequest($request);
- if ($request->has('mariadb_conf')) {
- if (! isBase64Encoded($request->mariadb_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mariadb_conf' => 'The mariadb_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $mariadbConf = base64_decode($request->mariadb_conf);
- if (mb_detect_encoding($mariadbConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mariadb_conf' => 'The mariadb_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('mariadb_conf', $mariadbConf);
- }
- $database = create_standalone_mariadb($environment->id, $destination->uuid, $request->all());
- if ($instantDeploy) {
- StartDatabase::dispatch($database);
- }
-
- $database->refresh();
- $payload = [
- 'uuid' => $database->uuid,
- 'internal_db_url' => $database->internal_db_url,
- ];
- if ($database->is_public && $database->public_port) {
- $payload['external_db_url'] = $database->external_db_url;
- }
-
- return response()->json(serializeApiResponse($payload))->setStatusCode(201);
- } elseif ($type === NewDatabaseTypes::MYSQL) {
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mysql_root_password', 'mysql_password', 'mysql_user', 'mysql_database', 'mysql_conf'];
- $validator = customApiValidator($request->all(), [
- 'mysql_root_password' => 'string',
- 'mysql_password' => 'string',
- 'mysql_user' => 'string',
- 'mysql_database' => 'string',
- 'mysql_conf' => 'string',
- ]);
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- removeUnnecessaryFieldsFromRequest($request);
- if ($request->has('mysql_conf')) {
- if (! isBase64Encoded($request->mysql_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mysql_conf' => 'The mysql_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $mysqlConf = base64_decode($request->mysql_conf);
- if (mb_detect_encoding($mysqlConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mysql_conf' => 'The mysql_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('mysql_conf', $mysqlConf);
- }
- $database = create_standalone_mysql($environment->id, $destination->uuid, $request->all());
- if ($instantDeploy) {
- StartDatabase::dispatch($database);
- }
-
- $database->refresh();
- $payload = [
- 'uuid' => $database->uuid,
- 'internal_db_url' => $database->internal_db_url,
- ];
- if ($database->is_public && $database->public_port) {
- $payload['external_db_url'] = $database->external_db_url;
- }
-
- return response()->json(serializeApiResponse($payload))->setStatusCode(201);
- } elseif ($type === NewDatabaseTypes::REDIS) {
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'redis_password', 'redis_conf'];
- $validator = customApiValidator($request->all(), [
- 'redis_password' => 'string',
- 'redis_conf' => 'string',
- ]);
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- removeUnnecessaryFieldsFromRequest($request);
- if ($request->has('redis_conf')) {
- if (! isBase64Encoded($request->redis_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'redis_conf' => 'The redis_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $redisConf = base64_decode($request->redis_conf);
- if (mb_detect_encoding($redisConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'redis_conf' => 'The redis_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('redis_conf', $redisConf);
- }
- $database = create_standalone_redis($environment->id, $destination->uuid, $request->all());
- if ($instantDeploy) {
- StartDatabase::dispatch($database);
- }
-
- $database->refresh();
- $payload = [
- 'uuid' => $database->uuid,
- 'internal_db_url' => $database->internal_db_url,
- ];
- if ($database->is_public && $database->public_port) {
- $payload['external_db_url'] = $database->external_db_url;
- }
-
- return response()->json(serializeApiResponse($payload))->setStatusCode(201);
- } elseif ($type === NewDatabaseTypes::DRAGONFLY) {
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'dragonfly_password'];
- $validator = customApiValidator($request->all(), [
- 'dragonfly_password' => 'string',
- ]);
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
-
- removeUnnecessaryFieldsFromRequest($request);
- $database = create_standalone_dragonfly($environment->id, $destination->uuid, $request->all());
- if ($instantDeploy) {
- StartDatabase::dispatch($database);
- }
-
- return response()->json(serializeApiResponse([
- 'uuid' => $database->uuid,
- ]))->setStatusCode(201);
- } elseif ($type === NewDatabaseTypes::KEYDB) {
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'keydb_password', 'keydb_conf'];
- $validator = customApiValidator($request->all(), [
- 'keydb_password' => 'string',
- 'keydb_conf' => 'string',
- ]);
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- removeUnnecessaryFieldsFromRequest($request);
- if ($request->has('keydb_conf')) {
- if (! isBase64Encoded($request->keydb_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'keydb_conf' => 'The keydb_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $keydbConf = base64_decode($request->keydb_conf);
- if (mb_detect_encoding($keydbConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'keydb_conf' => 'The keydb_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('keydb_conf', $keydbConf);
- }
- $database = create_standalone_keydb($environment->id, $destination->uuid, $request->all());
- if ($instantDeploy) {
- StartDatabase::dispatch($database);
- }
-
- $database->refresh();
- $payload = [
- 'uuid' => $database->uuid,
- 'internal_db_url' => $database->internal_db_url,
- ];
- if ($database->is_public && $database->public_port) {
- $payload['external_db_url'] = $database->external_db_url;
- }
-
- return response()->json(serializeApiResponse($payload))->setStatusCode(201);
- } elseif ($type === NewDatabaseTypes::CLICKHOUSE) {
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'clickhouse_admin_user', 'clickhouse_admin_password'];
- $validator = customApiValidator($request->all(), [
- 'clickhouse_admin_user' => 'string',
- 'clickhouse_admin_password' => 'string',
- ]);
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- removeUnnecessaryFieldsFromRequest($request);
- $database = create_standalone_clickhouse($environment->id, $destination->uuid, $request->all());
- if ($instantDeploy) {
- StartDatabase::dispatch($database);
- }
-
- $database->refresh();
- $payload = [
- 'uuid' => $database->uuid,
- 'internal_db_url' => $database->internal_db_url,
- ];
- if ($database->is_public && $database->public_port) {
- $payload['external_db_url'] = $database->external_db_url;
- }
-
- return response()->json(serializeApiResponse($payload))->setStatusCode(201);
- } elseif ($type === NewDatabaseTypes::MONGODB) {
- $allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mongo_conf', 'mongo_initdb_root_username', 'mongo_initdb_root_password', 'mongo_initdb_database'];
- $validator = customApiValidator($request->all(), [
- 'mongo_conf' => 'string',
- 'mongo_initdb_root_username' => 'string',
- 'mongo_initdb_root_password' => 'string',
- 'mongo_initdb_database' => 'string',
- ]);
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- removeUnnecessaryFieldsFromRequest($request);
- if ($request->has('mongo_conf')) {
- if (! isBase64Encoded($request->mongo_conf)) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mongo_conf' => 'The mongo_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $mongoConf = base64_decode($request->mongo_conf);
- if (mb_detect_encoding($mongoConf, 'ASCII', true) === false) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => [
- 'mongo_conf' => 'The mongo_conf should be base64 encoded.',
- ],
- ], 422);
- }
- $request->offsetSet('mongo_conf', $mongoConf);
- }
- $database = create_standalone_mongodb($environment->id, $destination->uuid, $request->all());
- if ($instantDeploy) {
- StartDatabase::dispatch($database);
- }
-
- $database->refresh();
- $payload = [
- 'uuid' => $database->uuid,
- 'internal_db_url' => $database->internal_db_url,
- ];
- if ($database->is_public && $database->public_port) {
- $payload['external_db_url'] = $database->external_db_url;
- }
-
- return response()->json(serializeApiResponse($payload))->setStatusCode(201);
- }
-
- return response()->json(['message' => 'Invalid database type requested.'], 400);
- }
-
- #[OA\Delete(
- summary: 'Delete',
- description: 'Delete database by UUID.',
- path: '/databases/{uuid}',
- operationId: 'delete-database-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the database.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- new OA\Parameter(name: 'delete_configurations', in: 'query', required: false, description: 'Delete configurations.', schema: new OA\Schema(type: 'boolean', default: true)),
- new OA\Parameter(name: 'delete_volumes', in: 'query', required: false, description: 'Delete volumes.', schema: new OA\Schema(type: 'boolean', default: true)),
- new OA\Parameter(name: 'docker_cleanup', in: 'query', required: false, description: 'Run docker cleanup.', schema: new OA\Schema(type: 'boolean', default: true)),
- new OA\Parameter(name: 'delete_connected_networks', in: 'query', required: false, description: 'Delete connected networks.', schema: new OA\Schema(type: 'boolean', default: true)),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Database deleted.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Database deleted.'],
- ]
- )
- ),
- ]
- ),
- 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 delete_by_uuid(Request $request)
- {
- $teamId = getTeamIdFromToken();
- $cleanup = filter_var($request->query->get('cleanup', true), FILTER_VALIDATE_BOOLEAN);
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- if (! $request->uuid) {
- return response()->json(['message' => 'UUID is required.'], 404);
- }
- $database = queryDatabaseByUuidWithinTeam($request->uuid, $teamId);
- if (! $database) {
- return response()->json(['message' => 'Database not found.'], 404);
- }
-
- DeleteResourceJob::dispatch(
- resource: $database,
- deleteConfigurations: $request->query->get('delete_configurations', true),
- deleteVolumes: $request->query->get('delete_volumes', true),
- dockerCleanup: $request->query->get('docker_cleanup', true),
- deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
- );
-
- return response()->json([
- 'message' => 'Database deletion request queued.',
- ]);
- }
-
- #[OA\Get(
- summary: 'Start',
- description: 'Start database. `Post` request is also accepted.',
- path: '/databases/{uuid}/start',
- operationId: 'start-database-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the database.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Start database.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Database starting request queued.'],
- ]
- )
- ),
- ]
- ),
- 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 action_deploy(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $database = queryDatabaseByUuidWithinTeam($request->uuid, $teamId);
- if (! $database) {
- return response()->json(['message' => 'Database not found.'], 404);
- }
- if (str($database->status)->contains('running')) {
- return response()->json(['message' => 'Database is already running.'], 400);
- }
- StartDatabase::dispatch($database);
-
- return response()->json(
- [
- 'message' => 'Database starting request queued.',
- ],
- 200
- );
- }
-
- #[OA\Get(
- summary: 'Stop',
- description: 'Stop database. `Post` request is also accepted.',
- path: '/databases/{uuid}/stop',
- operationId: 'stop-database-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the database.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Stop database.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Database stopping request queued.'],
- ]
- )
- ),
- ]
- ),
- 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 action_stop(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $database = queryDatabaseByUuidWithinTeam($request->uuid, $teamId);
- if (! $database) {
- return response()->json(['message' => 'Database not found.'], 404);
- }
- if (str($database->status)->contains('stopped') || str($database->status)->contains('exited')) {
- return response()->json(['message' => 'Database is already stopped.'], 400);
- }
- StopDatabase::dispatch($database);
-
- return response()->json(
- [
- 'message' => 'Database stopping request queued.',
- ],
- 200
- );
- }
-
- #[OA\Get(
- summary: 'Restart',
- description: 'Restart database. `Post` request is also accepted.',
- path: '/databases/{uuid}/restart',
- operationId: 'restart-database-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Databases'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the database.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Restart database.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Database restaring request queued.'],
- ]
- )
- ),
- ]
- ),
- 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 action_restart(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $database = queryDatabaseByUuidWithinTeam($request->uuid, $teamId);
- if (! $database) {
- return response()->json(['message' => 'Database not found.'], 404);
- }
- RestartDatabase::dispatch($database);
-
- return response()->json(
- [
- 'message' => 'Database restarting request queued.',
- ],
- 200
- );
- }
-}
diff --git a/app/Http/Controllers/Api/DeployController.php b/app/Http/Controllers/Api/DeployController.php
deleted file mode 100644
index 73b452f865..0000000000
--- a/app/Http/Controllers/Api/DeployController.php
+++ /dev/null
@@ -1,317 +0,0 @@
-attributes->get('can_read_sensitive', false) === false) {
- $deployment->makeHidden([
- 'logs',
- ]);
- }
-
- return serializeApiResponse($deployment);
- }
-
- #[OA\Get(
- summary: 'List',
- description: 'List currently running deployments',
- path: '/deployments',
- operationId: 'list-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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $servers = Server::whereTeamId($teamId)->get();
- $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);
- });
-
- return response()->json($deployments_per_server);
- }
-
- #[OA\Get(
- summary: 'Get',
- description: 'Get deployment by UUID.',
- path: '/deployments/{uuid}',
- operationId: 'get-deployment-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Deployments'],
- parameters: [
- new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Deployment UUID', schema: new OA\Schema(type: 'string')),
- ],
- 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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $deployment = ApplicationDeploymentQueue::where('deployment_uuid', $uuid)->first();
- if (! $deployment) {
- return response()->json(['message' => 'Deployment not found.'], 404);
- }
-
- return response()->json($this->removeSensitiveData($deployment));
- }
-
- #[OA\Get(
- summary: 'Deploy',
- description: 'Deploy by tag or uuid. `Post` request also accepted.',
- path: '/deploy',
- operationId: 'deploy-by-tag-or-uuid',
- 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();
- $uuids = $request->query->get('uuid');
- $tags = $request->query->get('tag');
- $force = $request->query->get('force') ?? false;
-
- if ($uuids && $tags) {
- return response()->json(['message' => 'You can only use uuid or tag, not both.'], 400);
- }
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- if ($tags) {
- return $this->by_tags($tags, $teamId, $force);
- } elseif ($uuids) {
- return $this->by_uuids($uuids, $teamId, $force);
- }
-
- return response()->json(['message' => 'You must provide uuid or tag.'], 400);
- }
-
- private function by_uuids(string $uuid, int $teamId, bool $force = false)
- {
- $uuids = explode(',', $uuid);
- $uuids = collect(array_filter($uuids));
-
- if (count($uuids) === 0) {
- return response()->json(['message' => 'No UUIDs provided.'], 400);
- }
- $deployments = collect();
- $payload = collect();
- foreach ($uuids as $uuid) {
- $resource = getResourceByUuid($uuid, $teamId);
- if ($resource) {
- ['message' => $return_message, 'deployment_uuid' => $deployment_uuid] = $this->deploy_resource($resource, $force);
- if ($deployment_uuid) {
- $deployments->push(['message' => $return_message, 'resource_uuid' => $uuid, 'deployment_uuid' => $deployment_uuid->toString()]);
- } else {
- $deployments->push(['message' => $return_message, 'resource_uuid' => $uuid]);
- }
- }
- }
- if ($deployments->count() > 0) {
- $payload->put('deployments', $deployments->toArray());
-
- return response()->json(serializeApiResponse($payload->toArray()));
- }
-
- return response()->json(['message' => 'No resources found.'], 404);
- }
-
- public function by_tags(string $tags, int $team_id, bool $force = false)
- {
- $tags = explode(',', $tags);
- $tags = collect(array_filter($tags));
-
- if (count($tags) === 0) {
- return response()->json(['message' => 'No TAGs provided.'], 400);
- }
- $message = collect([]);
- $deployments = collect();
- $payload = collect();
- foreach ($tags as $tag) {
- $found_tag = Tag::where(['name' => $tag, 'team_id' => $team_id])->first();
- if (! $found_tag) {
- // $message->push("Tag {$tag} not found.");
- continue;
- }
- $applications = $found_tag->applications()->get();
- $services = $found_tag->services()->get();
- if ($applications->count() === 0 && $services->count() === 0) {
- $message->push("No resources found for tag {$tag}.");
-
- continue;
- }
- foreach ($applications as $resource) {
- ['message' => $return_message, 'deployment_uuid' => $deployment_uuid] = $this->deploy_resource($resource, $force);
- if ($deployment_uuid) {
- $deployments->push(['resource_uuid' => $resource->uuid, 'deployment_uuid' => $deployment_uuid->toString()]);
- }
- $message = $message->merge($return_message);
- }
- foreach ($services as $resource) {
- ['message' => $return_message] = $this->deploy_resource($resource, $force);
- $message = $message->merge($return_message);
- }
- }
- if ($message->count() > 0) {
- $payload->put('message', $message->toArray());
- if ($deployments->count() > 0) {
- $payload->put('details', $deployments->toArray());
- }
-
- return response()->json(serializeApiResponse($payload->toArray()));
- }
-
- return response()->json(['message' => 'No resources found with this tag.'], 404);
- }
-
- public function deploy_resource($resource, bool $force = false): array
- {
- $message = null;
- $deployment_uuid = null;
- if (gettype($resource) !== 'object') {
- return ['message' => "Resource ($resource) not found.", 'deployment_uuid' => $deployment_uuid];
- }
- switch ($resource?->getMorphClass()) {
- case \App\Models\Application::class:
- $deployment_uuid = new Cuid2;
- queue_application_deployment(
- application: $resource,
- deployment_uuid: $deployment_uuid,
- force_rebuild: $force,
- );
- $message = "Application {$resource->name} deployment queued.";
- break;
- case \App\Models\Service::class:
- StartService::run($resource);
- $message = "Service {$resource->name} started. It could take a while, be patient.";
- break;
- default:
- // Database resource
- StartDatabase::dispatch($resource);
- $resource->update([
- 'started_at' => now(),
- ]);
- $message = "Database {$resource->name} started.";
- break;
- }
-
- return ['message' => $message, 'deployment_uuid' => $deployment_uuid];
- }
-}
diff --git a/app/Http/Controllers/Api/OpenApi.php b/app/Http/Controllers/Api/OpenApi.php
deleted file mode 100644
index 60337a76cf..0000000000
--- a/app/Http/Controllers/Api/OpenApi.php
+++ /dev/null
@@ -1,51 +0,0 @@
- []],
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Returns the version of the application',
- content: new OA\JsonContent(
- type: 'string',
- example: 'v4.0.0',
- )),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function version(Request $request)
- {
- return response(config('constants.coolify.version'));
- }
-
- #[OA\Get(
- summary: 'Enable API',
- description: 'Enable API (only with root permissions).',
- path: '/enable',
- operationId: 'enable-api',
- security: [
- ['bearerAuth' => []],
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Enable API.',
- content: new OA\JsonContent(
- type: 'object',
- properties: [
- new OA\Property(property: 'message', type: 'string', example: 'API enabled.'),
- ]
- )),
- new OA\Response(
- response: 403,
- description: 'You are not allowed to enable the API.',
- content: new OA\JsonContent(
- type: 'object',
- properties: [
- new OA\Property(property: 'message', type: 'string', example: 'You are not allowed to enable the API.'),
- ]
- )),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function enable_api(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- if ($teamId !== '0') {
- return response()->json(['message' => 'You are not allowed to enable the API.'], 403);
- }
- $settings = instanceSettings();
- $settings->update(['is_api_enabled' => true]);
-
- return response()->json(['message' => 'API enabled.'], 200);
- }
-
- #[OA\Get(
- summary: 'Disable API',
- description: 'Disable API (only with root permissions).',
- path: '/disable',
- operationId: 'disable-api',
- security: [
- ['bearerAuth' => []],
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Disable API.',
- content: new OA\JsonContent(
- type: 'object',
- properties: [
- new OA\Property(property: 'message', type: 'string', example: 'API disabled.'),
- ]
- )),
- new OA\Response(
- response: 403,
- description: 'You are not allowed to disable the API.',
- content: new OA\JsonContent(
- type: 'object',
- properties: [
- new OA\Property(property: 'message', type: 'string', example: 'You are not allowed to disable the API.'),
- ]
- )),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function disable_api(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- if ($teamId !== '0') {
- return response()->json(['message' => 'You are not allowed to disable the API.'], 403);
- }
- $settings = instanceSettings();
- $settings->update(['is_api_enabled' => false]);
-
- return response()->json(['message' => 'API disabled.'], 200);
- }
-
- public function feedback(Request $request)
- {
- $content = $request->input('content');
- $webhook_url = config('constants.webhooks.feedback_discord_webhook');
- if ($webhook_url) {
- Http::post($webhook_url, [
- 'content' => $content,
- ]);
- }
-
- return response()->json(['message' => 'Feedback sent.'], 200);
- }
-
- #[OA\Get(
- summary: 'Healthcheck',
- description: 'Healthcheck endpoint.',
- path: '/health',
- operationId: 'healthcheck',
- responses: [
- new OA\Response(
- response: 200,
- description: 'Healthcheck endpoint.',
- content: new OA\JsonContent(
- type: 'string',
- example: 'OK',
- )),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function healthcheck(Request $request)
- {
- return 'OK';
- }
-}
diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php
deleted file mode 100644
index b94ce9c67f..0000000000
--- a/app/Http/Controllers/Api/ProjectController.php
+++ /dev/null
@@ -1,438 +0,0 @@
- []],
- ],
- 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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $projects = Project::whereTeamId($teamId)->select('id', 'name', 'description', 'uuid')->get();
-
- return response()->json(serializeApiResponse($projects),
- );
- }
-
- #[OA\Get(
- summary: 'Get',
- description: 'Get project by UUID.',
- path: '/projects/{uuid}',
- operationId: 'get-project-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Projects'],
- parameters: [
- new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Project UUID', schema: new OA\Schema(type: 'string')),
- ],
- 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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $project = Project::whereTeamId($teamId)->whereUuid(request()->uuid)->first();
- if (! $project) {
- return response()->json(['message' => 'Project not found.'], 404);
- }
-
- $project->load(['environments']);
-
- return response()->json(
- serializeApiResponse($project),
- );
- }
-
- #[OA\Get(
- summary: 'Environment',
- description: 'Get environment by name or UUID.',
- path: '/projects/{uuid}/{environment_name_or_uuid}',
- operationId: 'get-environment-by-name-or-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Projects'],
- parameters: [
- new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Project UUID', schema: new OA\Schema(type: 'string')),
- new OA\Parameter(name: 'environment_name_or_uuid', in: 'path', required: true, description: 'Environment name or UUID', schema: new OA\Schema(type: 'string')),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Environment 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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- if (! $request->uuid) {
- return response()->json(['message' => 'UUID is required.'], 422);
- }
- if (! $request->environment_name_or_uuid) {
- return response()->json(['message' => 'Environment name or UUID is required.'], 422);
- }
- $project = Project::whereTeamId($teamId)->whereUuid($request->uuid)->first();
- if (! $project) {
- return response()->json(['message' => 'Project not found.'], 404);
- }
- $environment = $project->environments()->whereName($request->environment_name_or_uuid)->first();
- if (! $environment) {
- $environment = $project->environments()->whereUuid($request->environment_name_or_uuid)->first();
- }
- if (! $environment) {
- return response()->json(['message' => 'Environment not found.'], 404);
- }
- $environment = $environment->load(['applications', 'postgresqls', 'redis', 'mongodbs', 'mysqls', 'mariadbs', 'services']);
-
- return response()->json(serializeApiResponse($environment));
- }
-
- #[OA\Post(
- summary: 'Create',
- description: 'Create Project.',
- path: '/projects',
- operationId: 'create-project',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Projects'],
- requestBody: new OA\RequestBody(
- required: true,
- description: 'Project created.',
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'name' => ['type' => 'string', 'description' => 'The name of the project.'],
- 'description' => ['type' => 'string', 'description' => 'The description of the project.'],
- ],
- ),
- ),
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Project created.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'uuid' => ['type' => 'string', 'example' => 'og888os', 'description' => 'The UUID of the project.'],
- ]
- )
- ),
- ]),
- 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 create_project(Request $request)
- {
- $allowedFields = ['name', 'description'];
-
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $validator = customApiValidator($request->all(), [
- 'name' => 'string|max:255|required',
- 'description' => 'string|nullable',
- ]);
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
-
- $project = Project::create([
- 'name' => $request->name,
- 'description' => $request->description,
- 'team_id' => $teamId,
- ]);
-
- return response()->json([
- 'uuid' => $project->uuid,
- ])->setStatusCode(201);
- }
-
- #[OA\Patch(
- summary: 'Update',
- description: 'Update Project.',
- path: '/projects/{uuid}',
- operationId: 'update-project-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Projects'],
- requestBody: new OA\RequestBody(
- required: true,
- description: 'Project updated.',
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'name' => ['type' => 'string', 'description' => 'The name of the project.'],
- 'description' => ['type' => 'string', 'description' => 'The description of the project.'],
- ],
- ),
- ),
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Project updated.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'uuid' => ['type' => 'string', 'example' => 'og888os'],
- 'name' => ['type' => 'string', 'example' => 'Project Name'],
- 'description' => ['type' => 'string', 'example' => 'Project Description'],
- ]
- )
- ),
- ]),
- 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 update_project(Request $request)
- {
- $allowedFields = ['name', 'description'];
-
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $validator = customApiValidator($request->all(), [
- 'name' => 'string|max:255|nullable',
- 'description' => 'string|nullable',
- ]);
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- $uuid = $request->uuid;
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 422);
- }
-
- $project = Project::whereTeamId($teamId)->whereUuid($uuid)->first();
- if (! $project) {
- return response()->json(['message' => 'Project not found.'], 404);
- }
-
- $project->update($request->only($allowedFields));
-
- return response()->json([
- 'uuid' => $project->uuid,
- 'name' => $project->name,
- 'description' => $project->description,
- ])->setStatusCode(201);
- }
-
- #[OA\Delete(
- summary: 'Delete',
- description: 'Delete project by UUID.',
- path: '/projects/{uuid}',
- operationId: 'delete-project-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Projects'],
- 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: 'Project deleted.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Project deleted.'],
- ]
- )
- ),
- ]),
- 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 delete_project(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- if (! $request->uuid) {
- return response()->json(['message' => 'UUID is required.'], 422);
- }
- $project = Project::whereTeamId($teamId)->whereUuid($request->uuid)->first();
- if (! $project) {
- return response()->json(['message' => 'Project not found.'], 404);
- }
- if (! $project->isEmpty()) {
- return response()->json(['message' => 'Project has resources, so it cannot be deleted.'], 400);
- }
-
- $project->delete();
-
- return response()->json(['message' => 'Project deleted.']);
- }
-}
diff --git a/app/Http/Controllers/Api/ResourcesController.php b/app/Http/Controllers/Api/ResourcesController.php
deleted file mode 100644
index ad12c83ab8..0000000000
--- a/app/Http/Controllers/Api/ResourcesController.php
+++ /dev/null
@@ -1,64 +0,0 @@
- []],
- ],
- 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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $projects = Project::where('team_id', $teamId)->get();
- $resources = collect();
- $resources->push($projects->pluck('applications')->flatten());
- $resources->push($projects->pluck('services')->flatten());
- foreach (collect(DATABASE_TYPES) as $db) {
- $resources->push($projects->pluck(str($db)->plural(2))->flatten());
- }
- $resources = $resources->flatten();
- $resources = $resources->map(function ($resource) {
- $payload = $resource->toArray();
- $payload['status'] = $resource->status;
- $payload['type'] = $resource->type();
-
- return $payload;
- });
-
- return response()->json(serializeApiResponse($resources));
- }
-}
diff --git a/app/Http/Controllers/Api/SecurityController.php b/app/Http/Controllers/Api/SecurityController.php
deleted file mode 100644
index fdd46b1001..0000000000
--- a/app/Http/Controllers/Api/SecurityController.php
+++ /dev/null
@@ -1,393 +0,0 @@
-attributes->get('can_read_sensitive', false) === false) {
- $team->makeHidden([
- 'private_key',
- ]);
- }
-
- return serializeApiResponse($team);
- }
-
- #[OA\Get(
- summary: 'List',
- description: 'List all private keys.',
- path: '/security/keys',
- operationId: 'list-private-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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $keys = PrivateKey::where('team_id', $teamId)->get();
-
- return response()->json($this->removeSensitiveData($keys));
- }
-
- #[OA\Get(
- summary: 'Get',
- description: 'Get key by UUID.',
- path: '/security/keys/{uuid}',
- operationId: 'get-private-key-by-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: 'string')),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Get all private keys.',
- content: new OA\JsonContent(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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $key = PrivateKey::where('team_id', $teamId)->where('uuid', $request->uuid)->first();
-
- if (is_null($key)) {
- return response()->json([
- 'message' => 'Private Key not found.',
- ], 404);
- }
-
- return response()->json($this->removeSensitiveData($key));
- }
-
- #[OA\Post(
- summary: 'Create',
- description: 'Create a new private key.',
- path: '/security/keys',
- operationId: 'create-private-key',
- 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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $validator = customApiValidator($request->all(), [
- 'name' => 'string|max:255',
- 'description' => 'string|max:255',
- 'private_key' => 'required|string',
- ]);
-
- if ($validator->fails()) {
- $errors = $validator->errors();
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- if (! $request->name) {
- $request->offsetSet('name', generate_random_name());
- }
- if (! $request->description) {
- $request->offsetSet('description', 'Created by Coolify via API');
- }
-
- $isPrivateKeyString = str_starts_with($request->private_key, '-----BEGIN');
- if (! $isPrivateKeyString) {
- try {
- $base64PrivateKey = base64_decode($request->private_key);
- $request->offsetSet('private_key', $base64PrivateKey);
- } catch (\Exception $e) {
- return response()->json([
- 'message' => 'Invalid private key.',
- ], 422);
- }
- }
- $isPrivateKeyValid = PrivateKey::validatePrivateKey($request->private_key);
- if (! $isPrivateKeyValid) {
- return response()->json([
- 'message' => 'Invalid private key.',
- ], 422);
- }
- $fingerPrint = PrivateKey::generateFingerprint($request->private_key);
- $isFingerPrintExists = PrivateKey::fingerprintExists($fingerPrint);
- if ($isFingerPrintExists) {
- return response()->json([
- 'message' => 'Private key already exists.',
- ], 422);
- }
- $key = PrivateKey::create([
- 'team_id' => $teamId,
- 'name' => $request->name,
- 'description' => $request->description,
- 'private_key' => $request->private_key,
- ]);
-
- return response()->json(serializeApiResponse([
- 'uuid' => $key->uuid,
- ]))->setStatusCode(201);
- }
-
- #[OA\Patch(
- summary: 'Update',
- description: 'Update a private key.',
- path: '/security/keys',
- operationId: 'update-private-key',
- 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'];
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
-
- $validator = customApiValidator($request->all(), [
- 'name' => 'string|max:255',
- 'description' => 'string|max:255',
- 'private_key' => 'required|string',
- ]);
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- $foundKey = PrivateKey::where('team_id', $teamId)->where('uuid', $request->uuid)->first();
- if (is_null($foundKey)) {
- return response()->json([
- 'message' => 'Private Key not found.',
- ], 404);
- }
- $foundKey->update($request->all());
-
- return response()->json(serializeApiResponse([
- 'uuid' => $foundKey->uuid,
- ]))->setStatusCode(201);
- }
-
- #[OA\Delete(
- summary: 'Delete',
- description: 'Delete a private key.',
- path: '/security/keys/{uuid}',
- operationId: 'delete-private-key-by-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: 'string')),
- ],
- 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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- if (! $request->uuid) {
- return response()->json(['message' => 'UUID is required.'], 422);
- }
-
- $key = PrivateKey::where('team_id', $teamId)->where('uuid', $request->uuid)->first();
- if (is_null($key)) {
- return response()->json(['message' => 'Private Key not found.'], 404);
- }
- $key->forceDelete();
-
- return response()->json([
- 'message' => 'Private Key deleted.',
- ]);
- }
-}
diff --git a/app/Http/Controllers/Api/ServersController.php b/app/Http/Controllers/Api/ServersController.php
deleted file mode 100644
index a9a0a2e536..0000000000
--- a/app/Http/Controllers/Api/ServersController.php
+++ /dev/null
@@ -1,814 +0,0 @@
-attributes->get('can_read_sensitive', false) === false) {
- $settings = $settings->makeHidden([
- 'sentinel_token',
- ]);
- }
-
- return serializeApiResponse($settings);
- }
-
- private function removeSensitiveData($server)
- {
- $server->makeHidden([
- 'id',
- ]);
- if (request()->attributes->get('can_read_sensitive', false) === false) {
- // Do nothing
- }
-
- return serializeApiResponse($server);
- }
-
- #[OA\Get(
- summary: 'List',
- description: 'List all servers.',
- path: '/servers',
- operationId: 'list-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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $servers = ModelsServer::whereTeamId($teamId)->select('id', 'name', 'uuid', 'ip', 'user', 'port', 'description')->get()->load(['settings'])->map(function ($server) {
- $server['is_reachable'] = $server->settings->is_reachable;
- $server['is_usable'] = $server->settings->is_usable;
-
- return $server;
- });
- $servers = $servers->map(function ($server) {
- $settings = $this->removeSensitiveDataFromSettings($server->settings);
- $server = $this->removeSensitiveData($server);
- data_set($server, 'settings', $settings);
-
- return $server;
- });
-
- return response()->json($servers);
- }
-
- #[OA\Get(
- summary: 'Get',
- description: 'Get server by UUID.',
- path: '/servers/{uuid}',
- operationId: 'get-server-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Servers'],
- parameters: [
- new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s UUID', schema: new OA\Schema(type: 'string')),
- ],
- 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');
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $server = ModelsServer::whereTeamId($teamId)->whereUuid(request()->uuid)->first();
- if (is_null($server)) {
- return response()->json(['message' => 'Server not found.'], 404);
- }
- if ($with_resources) {
- $server['resources'] = $server->definedResources()->map(function ($resource) {
- $payload = [
- 'id' => $resource->id,
- 'uuid' => $resource->uuid,
- 'name' => $resource->name,
- 'type' => $resource->type(),
- 'created_at' => $resource->created_at,
- 'updated_at' => $resource->updated_at,
- ];
- $payload['status'] = $resource->status;
-
- return $payload;
- });
- } else {
- $server->load(['settings']);
- }
-
- $settings = $this->removeSensitiveDataFromSettings($server->settings);
- $server = $this->removeSensitiveData($server);
- data_set($server, 'settings', $settings);
-
- return response()->json(serializeApiResponse($server));
- }
-
- #[OA\Get(
- summary: 'Resources',
- description: 'Get resources by server.',
- path: '/servers/{uuid}/resources',
- operationId: 'get-resources-by-server-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Servers'],
- parameters: [
- new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s UUID', schema: new OA\Schema(type: 'string')),
- ],
- 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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $server = ModelsServer::whereTeamId($teamId)->whereUuid(request()->uuid)->first();
- if (is_null($server)) {
- return response()->json(['message' => 'Server not found.'], 404);
- }
- $server['resources'] = $server->definedResources()->map(function ($resource) {
- $payload = [
- 'id' => $resource->id,
- 'uuid' => $resource->uuid,
- 'name' => $resource->name,
- 'type' => $resource->type(),
- 'created_at' => $resource->created_at,
- 'updated_at' => $resource->updated_at,
- ];
- $payload['status'] = $resource->status;
-
- return $payload;
- });
- $server = $this->removeSensitiveData($server);
-
- return response()->json(serializeApiResponse(data_get($server, 'resources')));
- }
-
- #[OA\Get(
- summary: 'Domains',
- description: 'Get domains by server.',
- path: '/servers/{uuid}/domains',
- operationId: 'get-domains-by-server-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Servers'],
- parameters: [
- new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s UUID', schema: new OA\Schema(type: 'string')),
- ],
- 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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->get('uuid');
- if ($uuid) {
- $domains = Application::getDomainsByUuid($uuid);
-
- return response()->json(serializeApiResponse($domains));
- }
- $projects = Project::where('team_id', $teamId)->get();
- $domains = collect();
- $applications = $projects->pluck('applications')->flatten();
- $settings = instanceSettings();
- if ($applications->count() > 0) {
- foreach ($applications as $application) {
- $ip = $application->destination->server->ip;
- $fqdn = str($application->fqdn)->explode(',')->map(function ($fqdn) {
- $f = str($fqdn)->replace('http://', '')->replace('https://', '')->explode('/');
-
- return str(str($f[0])->explode(':')[0]);
- })->filter(function (Stringable $fqdn) {
- return $fqdn->isNotEmpty();
- });
-
- if ($ip === 'host.docker.internal') {
- if ($settings->public_ipv4) {
- $domains->push([
- 'domain' => $fqdn,
- 'ip' => $settings->public_ipv4,
- ]);
- }
- if ($settings->public_ipv6) {
- $domains->push([
- 'domain' => $fqdn,
- 'ip' => $settings->public_ipv6,
- ]);
- }
- if (! $settings->public_ipv4 && ! $settings->public_ipv6) {
- $domains->push([
- 'domain' => $fqdn,
- 'ip' => $ip,
- ]);
- }
- } else {
- $domains->push([
- 'domain' => $fqdn,
- 'ip' => $ip,
- ]);
- }
- }
- }
- $services = $projects->pluck('services')->flatten();
- if ($services->count() > 0) {
- foreach ($services as $service) {
- $service_applications = $service->applications;
- if ($service_applications->count() > 0) {
- foreach ($service_applications as $application) {
- $fqdn = str($application->fqdn)->explode(',')->map(function ($fqdn) {
- $f = str($fqdn)->replace('http://', '')->replace('https://', '')->explode('/');
-
- return str(str($f[0])->explode(':')[0]);
- })->filter(function (Stringable $fqdn) {
- return $fqdn->isNotEmpty();
- });
- if ($ip === 'host.docker.internal') {
- if ($settings->public_ipv4) {
- $domains->push([
- 'domain' => $fqdn,
- 'ip' => $settings->public_ipv4,
- ]);
- }
- if ($settings->public_ipv6) {
- $domains->push([
- 'domain' => $fqdn,
- 'ip' => $settings->public_ipv6,
- ]);
- }
- if (! $settings->public_ipv4 && ! $settings->public_ipv6) {
- $domains->push([
- 'domain' => $fqdn,
- 'ip' => $ip,
- ]);
- }
- } else {
- $domains->push([
- 'domain' => $fqdn,
- 'ip' => $ip,
- ]);
- }
- }
- }
- }
- }
- $domains = $domains->groupBy('ip')->map(function ($domain) {
- return $domain->pluck('domain')->flatten();
- })->map(function ($domain, $ip) {
- return [
- 'ip' => $ip,
- 'domains' => $domain,
- ];
- })->values();
-
- return response()->json(serializeApiResponse($domains));
- }
-
- #[OA\Post(
- summary: 'Create',
- description: 'Create Server.',
- path: '/servers',
- operationId: 'create-server',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Servers'],
- requestBody: new OA\RequestBody(
- required: true,
- description: 'Server created.',
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'name' => ['type' => 'string', 'example' => 'My Server', 'description' => 'The name of the server.'],
- 'description' => ['type' => 'string', 'example' => 'My Server Description', 'description' => 'The description of the server.'],
- 'ip' => ['type' => 'string', 'example' => '127.0.0.1', 'description' => 'The IP of the server.'],
- 'port' => ['type' => 'integer', 'example' => 22, 'description' => 'The port of the server.'],
- 'user' => ['type' => 'string', 'example' => 'root', 'description' => 'The user of the server.'],
- 'private_key_uuid' => ['type' => 'string', 'example' => 'og888os', 'description' => 'The UUID of the private key.'],
- 'is_build_server' => ['type' => 'boolean', 'example' => false, 'description' => 'Is build server.'],
- 'instant_validate' => ['type' => 'boolean', 'example' => false, 'description' => 'Instant validate.'],
- 'proxy_type' => ['type' => 'string', 'enum' => ['traefik', 'caddy', 'none'], 'example' => 'traefik', 'description' => 'The proxy type.'],
- ],
- ),
- ),
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Server created.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'uuid' => ['type' => 'string', 'example' => 'og888os', 'description' => 'The UUID of the 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 create_server(Request $request)
- {
- $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate', 'proxy_type'];
-
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $validator = customApiValidator($request->all(), [
- 'name' => 'string|max:255',
- 'description' => 'string|nullable',
- 'ip' => 'string|required',
- 'port' => 'integer|nullable',
- 'private_key_uuid' => 'string|required',
- 'user' => 'string|nullable',
- 'is_build_server' => 'boolean|nullable',
- 'instant_validate' => 'boolean|nullable',
- 'proxy_type' => 'string|nullable',
- ]);
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- if (! $request->name) {
- $request->offsetSet('name', generate_random_name());
- }
- if (! $request->user) {
- $request->offsetSet('user', 'root');
- }
- if (is_null($request->port)) {
- $request->offsetSet('port', 22);
- }
- if (is_null($request->is_build_server)) {
- $request->offsetSet('is_build_server', false);
- }
- if (is_null($request->instant_validate)) {
- $request->offsetSet('instant_validate', false);
- }
- if ($request->proxy_type) {
- $validProxyTypes = collect(ProxyTypes::cases())->map(function ($proxyType) {
- return str($proxyType->value)->lower();
- });
- if (! $validProxyTypes->contains(str($request->proxy_type)->lower())) {
- return response()->json(['message' => 'Invalid proxy type.'], 422);
- }
- }
- $privateKey = PrivateKey::whereTeamId($teamId)->whereUuid($request->private_key_uuid)->first();
- if (! $privateKey) {
- return response()->json(['message' => 'Private key not found.'], 404);
- }
- $allServers = ModelsServer::whereIp($request->ip)->get();
- if ($allServers->count() > 0) {
- return response()->json(['message' => 'Server with this IP already exists.'], 400);
- }
-
- $proxyType = $request->proxy_type ? str($request->proxy_type)->upper() : ProxyTypes::TRAEFIK->value;
-
- $server = ModelsServer::create([
- 'name' => $request->name,
- 'description' => $request->description,
- 'ip' => $request->ip,
- 'port' => $request->port,
- 'user' => $request->user,
- 'private_key_id' => $privateKey->id,
- 'team_id' => $teamId,
- ]);
- $server->proxy->set('type', $proxyType);
- $server->proxy->set('status', ProxyStatus::EXITED->value);
- $server->save();
-
- $server->settings()->update([
- 'is_build_server' => $request->is_build_server,
- ]);
- if ($request->instant_validate) {
- ValidateServer::dispatch($server);
- }
-
- return response()->json([
- 'uuid' => $server->uuid,
- ])->setStatusCode(201);
- }
-
- #[OA\Patch(
- summary: 'Update',
- description: 'Update Server.',
- path: '/servers/{uuid}',
- operationId: 'update-server-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Servers'],
- parameters: [
- new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server UUID', schema: new OA\Schema(type: 'string')),
- ],
- requestBody: new OA\RequestBody(
- required: true,
- description: 'Server updated.',
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'name' => ['type' => 'string', 'description' => 'The name of the server.'],
- 'description' => ['type' => 'string', 'description' => 'The description of the server.'],
- 'ip' => ['type' => 'string', 'description' => 'The IP of the server.'],
- 'port' => ['type' => 'integer', 'description' => 'The port of the server.'],
- 'user' => ['type' => 'string', 'description' => 'The user of the server.'],
- 'private_key_uuid' => ['type' => 'string', 'description' => 'The UUID of the private key.'],
- 'is_build_server' => ['type' => 'boolean', 'description' => 'Is build server.'],
- 'instant_validate' => ['type' => 'boolean', 'description' => 'Instant validate.'],
- 'proxy_type' => ['type' => 'string', 'enum' => ['traefik', 'caddy', 'none'], 'description' => 'The proxy type.'],
- ],
- ),
- ),
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Server updated.',
- 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 update_server(Request $request)
- {
- $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate', 'proxy_type'];
-
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $validator = customApiValidator($request->all(), [
- 'name' => 'string|max:255|nullable',
- 'description' => 'string|nullable',
- 'ip' => 'string|nullable',
- 'port' => 'integer|nullable',
- 'private_key_uuid' => 'string|nullable',
- 'user' => 'string|nullable',
- 'is_build_server' => 'boolean|nullable',
- 'instant_validate' => 'boolean|nullable',
- 'proxy_type' => 'string|nullable',
- ]);
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- $server = ModelsServer::whereTeamId($teamId)->whereUuid($request->uuid)->first();
- if (! $server) {
- return response()->json(['message' => 'Server not found.'], 404);
- }
- if ($request->proxy_type) {
- $validProxyTypes = collect(ProxyTypes::cases())->map(function ($proxyType) {
- return str($proxyType->value)->lower();
- });
- if ($validProxyTypes->contains(str($request->proxy_type)->lower())) {
- $server->changeProxy($request->proxy_type, async: true);
- } else {
- return response()->json(['message' => 'Invalid proxy type.'], 422);
- }
- }
- $server->update($request->only(['name', 'description', 'ip', 'port', 'user']));
- if ($request->is_build_server) {
- $server->settings()->update([
- 'is_build_server' => $request->is_build_server,
- ]);
- }
- if ($request->instant_validate) {
- ValidateServer::dispatch($server);
- }
-
- return response()->json([
- 'uuid' => $server->uuid,
- ])->setStatusCode(201);
- }
-
- #[OA\Delete(
- summary: 'Delete',
- description: 'Delete server by UUID.',
- path: '/servers/{uuid}',
- operationId: 'delete-server-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Servers'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the server.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Server deleted.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Server deleted.'],
- ]
- )
- ),
- ]),
- 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 delete_server(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- if (! $request->uuid) {
- return response()->json(['message' => 'Uuid is required.'], 422);
- }
- $server = ModelsServer::whereTeamId($teamId)->whereUuid($request->uuid)->first();
-
- if (! $server) {
- return response()->json(['message' => 'Server not found.'], 404);
- }
- if ($server->definedResources()->count() > 0) {
- return response()->json(['message' => 'Server has resources, so you need to delete them before.'], 400);
- }
- if ($server->isLocalhost()) {
- return response()->json(['message' => 'Local server cannot be deleted.'], 400);
- }
- $server->delete();
- DeleteServer::dispatch($server);
-
- return response()->json(['message' => 'Server deleted.']);
- }
-
- #[OA\Get(
- summary: 'Validate',
- description: 'Validate server by UUID.',
- path: '/servers/{uuid}/validate',
- operationId: 'validate-server-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Servers'],
- parameters: [
- new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server UUID', schema: new OA\Schema(type: 'string')),
- ],
- responses: [
- new OA\Response(
- response: 201,
- description: 'Server validation started.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Validation started.'],
- ]
- )
- ),
- ]),
- 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 validate_server(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- if (! $request->uuid) {
- return response()->json(['message' => 'Uuid is required.'], 422);
- }
- $server = ModelsServer::whereTeamId($teamId)->whereUuid($request->uuid)->first();
-
- if (! $server) {
- return response()->json(['message' => 'Server not found.'], 404);
- }
- ValidateServer::dispatch($server);
-
- return response()->json(['message' => 'Validation started.']);
- }
-}
diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php
deleted file mode 100644
index 03d9d209cc..0000000000
--- a/app/Http/Controllers/Api/ServicesController.php
+++ /dev/null
@@ -1,1261 +0,0 @@
-makeHidden([
- 'id',
- 'resourceable',
- 'resourceable_id',
- 'resourceable_type',
- ]);
- if (request()->attributes->get('can_read_sensitive', false) === false) {
- $service->makeHidden([
- 'docker_compose_raw',
- 'docker_compose',
- 'value',
- 'real_value',
- ]);
- }
-
- return serializeApiResponse($service);
- }
-
- #[OA\Get(
- summary: 'List',
- description: 'List all services.',
- path: '/services',
- operationId: 'list-services',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Get all services',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'array',
- items: new OA\Items(ref: '#/components/schemas/Service')
- )
- ),
- ]
- ),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function services(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $projects = Project::where('team_id', $teamId)->get();
- $services = collect();
- foreach ($projects as $project) {
- $services->push($project->services()->get());
- }
- foreach ($services as $service) {
- $service = $this->removeSensitiveData($service);
- }
-
- return response()->json($services->flatten());
- }
-
- #[OA\Post(
- summary: 'Create',
- description: 'Create a one-click service',
- path: '/services',
- operationId: 'create-service',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- requestBody: new OA\RequestBody(
- required: true,
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['server_uuid', 'project_uuid', 'environment_name', 'environment_uuid', 'type'],
- properties: [
- 'type' => [
- 'description' => 'The one-click service type',
- 'type' => 'string',
- 'enum' => [
- 'activepieces',
- 'appsmith',
- 'appwrite',
- 'authentik',
- 'babybuddy',
- 'budge',
- 'changedetection',
- 'chatwoot',
- 'classicpress-with-mariadb',
- 'classicpress-with-mysql',
- 'classicpress-without-database',
- 'cloudflared',
- 'code-server',
- 'dashboard',
- 'directus',
- 'directus-with-postgresql',
- 'docker-registry',
- 'docuseal',
- 'docuseal-with-postgres',
- 'dokuwiki',
- 'duplicati',
- 'emby',
- 'embystat',
- 'fider',
- 'filebrowser',
- 'firefly',
- 'formbricks',
- 'ghost',
- 'gitea',
- 'gitea-with-mariadb',
- 'gitea-with-mysql',
- 'gitea-with-postgresql',
- 'glance',
- 'glances',
- 'glitchtip',
- 'grafana',
- 'grafana-with-postgresql',
- 'grocy',
- 'heimdall',
- 'homepage',
- 'jellyfin',
- 'kuzzle',
- 'listmonk',
- 'logto',
- 'mediawiki',
- 'meilisearch',
- 'metabase',
- 'metube',
- 'minio',
- 'moodle',
- 'n8n',
- 'n8n-with-postgresql',
- 'next-image-transformation',
- 'nextcloud',
- 'nocodb',
- 'odoo',
- 'openblocks',
- 'pairdrop',
- 'penpot',
- 'phpmyadmin',
- 'pocketbase',
- 'posthog',
- 'reactive-resume',
- 'rocketchat',
- 'shlink',
- 'slash',
- 'snapdrop',
- 'statusnook',
- 'stirling-pdf',
- 'supabase',
- 'syncthing',
- 'tolgee',
- 'trigger',
- 'trigger-with-external-database',
- 'twenty',
- 'umami',
- 'unleash-with-postgresql',
- 'unleash-without-database',
- 'uptime-kuma',
- 'vaultwarden',
- 'vikunja',
- 'weblate',
- 'whoogle',
- 'wordpress-with-mariadb',
- 'wordpress-with-mysql',
- 'wordpress-without-database',
- ],
- ],
- 'name' => ['type' => 'string', 'maxLength' => 255, 'description' => 'Name of the service.'],
- 'description' => ['type' => 'string', 'nullable' => true, 'description' => 'Description of the service.'],
- 'project_uuid' => ['type' => 'string', 'description' => 'Project UUID.'],
- 'environment_name' => ['type' => 'string', 'description' => 'Environment name. You need to provide at least one of environment_name or environment_uuid.'],
- 'environment_uuid' => ['type' => 'string', 'description' => 'Environment UUID. You need to provide at least one of environment_name or environment_uuid.'],
- 'server_uuid' => ['type' => 'string', 'description' => 'Server UUID.'],
- 'destination_uuid' => ['type' => 'string', 'description' => 'Destination UUID. Required if server has multiple destinations.'],
- 'instant_deploy' => ['type' => 'boolean', 'default' => false, 'description' => 'Start the service immediately after creation.'],
- ],
- ),
- ),
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Create a service.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'uuid' => ['type' => 'string', 'description' => 'Service UUID.'],
- 'domains' => ['type' => 'array', 'items' => ['type' => 'string'], 'description' => 'Service domains.'],
- ]
- )
- ),
- ]
- ),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function create_service(Request $request)
- {
- $allowedFields = ['type', 'name', 'description', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy'];
-
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $return = validateIncomingRequest($request);
- if ($return instanceof \Illuminate\Http\JsonResponse) {
- return $return;
- }
- $validator = customApiValidator($request->all(), [
- 'type' => 'string|required',
- 'project_uuid' => 'string|required',
- 'environment_name' => 'string|nullable',
- 'environment_uuid' => 'string|nullable',
- 'server_uuid' => 'string|required',
- 'destination_uuid' => 'string',
- 'name' => 'string|max:255',
- 'description' => 'string|nullable',
- 'instant_deploy' => 'boolean',
- ]);
-
- $extraFields = array_diff(array_keys($request->all()), $allowedFields);
- if ($validator->fails() || ! empty($extraFields)) {
- $errors = $validator->errors();
- if (! empty($extraFields)) {
- foreach ($extraFields as $field) {
- $errors->add($field, 'This field is not allowed.');
- }
- }
-
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $errors,
- ], 422);
- }
- $environmentUuid = $request->environment_uuid;
- $environmentName = $request->environment_name;
- if (blank($environmentUuid) && blank($environmentName)) {
- return response()->json(['message' => 'You need to provide at least one of environment_name or environment_uuid.'], 422);
- }
- $serverUuid = $request->server_uuid;
- $instantDeploy = $request->instant_deploy ?? false;
- if ($request->is_public && ! $request->public_port) {
- $request->offsetSet('is_public', false);
- }
- $project = Project::whereTeamId($teamId)->whereUuid($request->project_uuid)->first();
- if (! $project) {
- return response()->json(['message' => 'Project not found.'], 404);
- }
- $environment = $project->environments()->where('name', $environmentName)->first();
- if (! $environment) {
- $environment = $project->environments()->where('uuid', $environmentUuid)->first();
- }
- if (! $environment) {
- return response()->json(['message' => 'Environment not found.'], 404);
- }
- $server = Server::whereTeamId($teamId)->whereUuid($serverUuid)->first();
- if (! $server) {
- return response()->json(['message' => 'Server not found.'], 404);
- }
- $destinations = $server->destinations();
- if ($destinations->count() == 0) {
- return response()->json(['message' => 'Server has no destinations.'], 400);
- }
- if ($destinations->count() > 1 && ! $request->has('destination_uuid')) {
- return response()->json(['message' => 'Server has multiple destinations and you do not set destination_uuid.'], 400);
- }
- $destination = $destinations->first();
- $services = get_service_templates();
- $serviceKeys = $services->keys();
- if ($serviceKeys->contains($request->type)) {
- $oneClickServiceName = $request->type;
- $oneClickService = data_get($services, "$oneClickServiceName.compose");
- $oneClickDotEnvs = data_get($services, "$oneClickServiceName.envs", null);
- if ($oneClickDotEnvs) {
- $oneClickDotEnvs = str(base64_decode($oneClickDotEnvs))->split('/\r\n|\r|\n/')->filter(function ($value) {
- return ! empty($value);
- });
- }
- if ($oneClickService) {
- $service_payload = [
- 'name' => "$oneClickServiceName-".str()->random(10),
- 'docker_compose_raw' => base64_decode($oneClickService),
- 'environment_id' => $environment->id,
- 'service_type' => $oneClickServiceName,
- 'server_id' => $server->id,
- 'destination_id' => $destination->id,
- 'destination_type' => $destination->getMorphClass(),
- ];
- if ($oneClickServiceName === 'cloudflared') {
- data_set($service_payload, 'connect_to_docker_network', true);
- }
- $service = Service::create($service_payload);
- $service->name = "$oneClickServiceName-".$service->uuid;
- $service->save();
- if ($oneClickDotEnvs?->count() > 0) {
- $oneClickDotEnvs->each(function ($value) use ($service) {
- $key = str()->before($value, '=');
- $value = str(str()->after($value, '='));
- $generatedValue = $value;
- if ($value->contains('SERVICE_')) {
- $command = $value->after('SERVICE_')->beforeLast('_');
- $generatedValue = generateEnvValue($command->value(), $service);
- }
- EnvironmentVariable::create([
- 'key' => $key,
- 'value' => $generatedValue,
- 'resourceable_id' => $service->id,
- 'resourceable_type' => $service->getMorphClass(),
- 'is_build_time' => false,
- 'is_preview' => false,
- ]);
- });
- }
- $service->parse(isNew: true);
- if ($instantDeploy) {
- StartService::dispatch($service);
- }
- $domains = $service->applications()->get()->pluck('fqdn')->sort();
- $domains = $domains->map(function ($domain) {
- if (count(explode(':', $domain)) > 2) {
- return str($domain)->beforeLast(':')->value();
- }
-
- return $domain;
- });
-
- return response()->json([
- 'uuid' => $service->uuid,
- 'domains' => $domains,
- ]);
- }
-
- return response()->json(['message' => 'Service not found.'], 404);
- } else {
- return response()->json(['message' => 'Invalid service type.', 'valid_service_types' => $serviceKeys], 400);
- }
-
- return response()->json(['message' => 'Invalid service type.'], 400);
- }
-
- #[OA\Get(
- summary: 'Get',
- description: 'Get service by UUID.',
- path: '/services/{uuid}',
- operationId: 'get-service-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- parameters: [
- new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Service UUID', schema: new OA\Schema(type: 'string')),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Get a service by UUID.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- ref: '#/components/schemas/Service'
- )
- ),
- ]
- ),
- 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 service_by_uuid(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- if (! $request->uuid) {
- return response()->json(['message' => 'UUID is required.'], 404);
- }
- $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
- if (! $service) {
- return response()->json(['message' => 'Service not found.'], 404);
- }
-
- $service = $service->load(['applications', 'databases']);
-
- return response()->json($this->removeSensitiveData($service));
- }
-
- #[OA\Delete(
- summary: 'Delete',
- description: 'Delete service by UUID.',
- path: '/services/{uuid}',
- operationId: 'delete-service-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- parameters: [
- new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Service UUID', schema: new OA\Schema(type: 'string')),
- new OA\Parameter(name: 'delete_configurations', in: 'query', required: false, description: 'Delete configurations.', schema: new OA\Schema(type: 'boolean', default: true)),
- new OA\Parameter(name: 'delete_volumes', in: 'query', required: false, description: 'Delete volumes.', schema: new OA\Schema(type: 'boolean', default: true)),
- new OA\Parameter(name: 'docker_cleanup', in: 'query', required: false, description: 'Run docker cleanup.', schema: new OA\Schema(type: 'boolean', default: true)),
- new OA\Parameter(name: 'delete_connected_networks', in: 'query', required: false, description: 'Delete connected networks.', schema: new OA\Schema(type: 'boolean', default: true)),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Delete a service by UUID',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Service deletion request queued.'],
- ],
- )
- ),
- ]
- ),
- 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 delete_by_uuid(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- if (! $request->uuid) {
- return response()->json(['message' => 'UUID is required.'], 404);
- }
- $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
- if (! $service) {
- return response()->json(['message' => 'Service not found.'], 404);
- }
-
- DeleteResourceJob::dispatch(
- resource: $service,
- deleteConfigurations: $request->query->get('delete_configurations', true),
- deleteVolumes: $request->query->get('delete_volumes', true),
- dockerCleanup: $request->query->get('docker_cleanup', true),
- deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
- );
-
- return response()->json([
- 'message' => 'Service deletion request queued.',
- ]);
- }
-
- #[OA\Get(
- summary: 'List Envs',
- description: 'List all envs by service UUID.',
- path: '/services/{uuid}/envs',
- operationId: 'list-envs-by-service-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the service.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'All environment variables by service UUID.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'array',
- items: new OA\Items(ref: '#/components/schemas/EnvironmentVariable')
- )
- ),
- ]
- ),
- 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 envs(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
- if (! $service) {
- return response()->json(['message' => 'Service not found.'], 404);
- }
-
- $envs = $service->environment_variables->map(function ($env) {
- $env->makeHidden([
- 'application_id',
- 'standalone_clickhouse_id',
- 'standalone_dragonfly_id',
- 'standalone_keydb_id',
- 'standalone_mariadb_id',
- 'standalone_mongodb_id',
- 'standalone_mysql_id',
- 'standalone_postgresql_id',
- 'standalone_redis_id',
- ]);
-
- return $this->removeSensitiveData($env);
- });
-
- return response()->json($envs);
- }
-
- #[OA\Patch(
- summary: 'Update Env',
- description: 'Update env by service UUID.',
- path: '/services/{uuid}/envs',
- operationId: 'update-env-by-service-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the service.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- requestBody: new OA\RequestBody(
- description: 'Env updated.',
- required: true,
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['key', 'value'],
- properties: [
- 'key' => ['type' => 'string', 'description' => 'The key of the environment variable.'],
- 'value' => ['type' => 'string', 'description' => 'The value of the environment variable.'],
- 'is_preview' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in preview deployments.'],
- 'is_build_time' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in build time.'],
- 'is_literal' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is a literal, nothing espaced.'],
- 'is_multiline' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is multiline.'],
- 'is_shown_once' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable\'s value is shown on the UI.'],
- ],
- ),
- ),
- ],
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Environment variable updated.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Environment variable updated.'],
- ]
- )
- ),
- ]
- ),
- 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 update_env_by_uuid(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
- if (! $service) {
- return response()->json(['message' => 'Service not found.'], 404);
- }
-
- $validator = customApiValidator($request->all(), [
- 'key' => 'string|required',
- 'value' => 'string|nullable',
- 'is_build_time' => 'boolean',
- 'is_literal' => 'boolean',
- 'is_multiline' => 'boolean',
- 'is_shown_once' => 'boolean',
- ]);
-
- if ($validator->fails()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
-
- $key = str($request->key)->trim()->replace(' ', '_')->value;
- $env = $service->environment_variables()->where('key', $key)->first();
- if (! $env) {
- return response()->json(['message' => 'Environment variable not found.'], 404);
- }
-
- $env->fill($request->all());
- $env->save();
-
- return response()->json($this->removeSensitiveData($env))->setStatusCode(201);
- }
-
- #[OA\Patch(
- summary: 'Update Envs (Bulk)',
- description: 'Update multiple envs by service UUID.',
- path: '/services/{uuid}/envs/bulk',
- operationId: 'update-envs-by-service-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the service.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- requestBody: new OA\RequestBody(
- description: 'Bulk envs updated.',
- required: true,
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- required: ['data'],
- properties: [
- 'data' => [
- 'type' => 'array',
- 'items' => new OA\Schema(
- type: 'object',
- properties: [
- 'key' => ['type' => 'string', 'description' => 'The key of the environment variable.'],
- 'value' => ['type' => 'string', 'description' => 'The value of the environment variable.'],
- 'is_preview' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in preview deployments.'],
- 'is_build_time' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in build time.'],
- 'is_literal' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is a literal, nothing espaced.'],
- 'is_multiline' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is multiline.'],
- 'is_shown_once' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable\'s value is shown on the UI.'],
- ],
- ),
- ],
- ],
- ),
- ),
- ],
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Environment variables updated.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Environment variables updated.'],
- ]
- )
- ),
- ]
- ),
- 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 create_bulk_envs(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
- if (! $service) {
- return response()->json(['message' => 'Service not found.'], 404);
- }
-
- $bulk_data = $request->get('data');
- if (! $bulk_data) {
- return response()->json(['message' => 'Bulk data is required.'], 400);
- }
-
- $updatedEnvs = collect();
- foreach ($bulk_data as $item) {
- $validator = customApiValidator($item, [
- 'key' => 'string|required',
- 'value' => 'string|nullable',
- 'is_build_time' => 'boolean',
- 'is_literal' => 'boolean',
- 'is_multiline' => 'boolean',
- 'is_shown_once' => 'boolean',
- ]);
-
- if ($validator->fails()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
- $key = str($item['key'])->trim()->replace(' ', '_')->value;
- $env = $service->environment_variables()->updateOrCreate(
- ['key' => $key],
- $item
- );
-
- $updatedEnvs->push($this->removeSensitiveData($env));
- }
-
- return response()->json($updatedEnvs)->setStatusCode(201);
- }
-
- #[OA\Post(
- summary: 'Create Env',
- description: 'Create env by service UUID.',
- path: '/services/{uuid}/envs',
- operationId: 'create-env-by-service-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the service.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- requestBody: new OA\RequestBody(
- required: true,
- description: 'Env created.',
- content: new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'key' => ['type' => 'string', 'description' => 'The key of the environment variable.'],
- 'value' => ['type' => 'string', 'description' => 'The value of the environment variable.'],
- 'is_preview' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in preview deployments.'],
- 'is_build_time' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is used in build time.'],
- 'is_literal' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is a literal, nothing espaced.'],
- 'is_multiline' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable is multiline.'],
- 'is_shown_once' => ['type' => 'boolean', 'description' => 'The flag to indicate if the environment variable\'s value is shown on the UI.'],
- ],
- ),
- ),
- ),
- responses: [
- new OA\Response(
- response: 201,
- description: 'Environment variable created.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'uuid' => ['type' => 'string', 'example' => 'nc0k04gk8g0cgsk440g0koko'],
- ]
- )
- ),
- ]
- ),
- 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 create_env(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
- if (! $service) {
- return response()->json(['message' => 'Service not found.'], 404);
- }
-
- $validator = customApiValidator($request->all(), [
- 'key' => 'string|required',
- 'value' => 'string|nullable',
- 'is_build_time' => 'boolean',
- 'is_literal' => 'boolean',
- 'is_multiline' => 'boolean',
- 'is_shown_once' => 'boolean',
- ]);
-
- if ($validator->fails()) {
- return response()->json([
- 'message' => 'Validation failed.',
- 'errors' => $validator->errors(),
- ], 422);
- }
-
- $key = str($request->key)->trim()->replace(' ', '_')->value;
- $existingEnv = $service->environment_variables()->where('key', $key)->first();
- if ($existingEnv) {
- return response()->json([
- 'message' => 'Environment variable already exists. Use PATCH request to update it.',
- ], 409);
- }
-
- $env = $service->environment_variables()->create($request->all());
-
- return response()->json($this->removeSensitiveData($env))->setStatusCode(201);
- }
-
- #[OA\Delete(
- summary: 'Delete Env',
- description: 'Delete env by UUID.',
- path: '/services/{uuid}/envs/{env_uuid}',
- operationId: 'delete-env-by-service-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the service.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- new OA\Parameter(
- name: 'env_uuid',
- in: 'path',
- description: 'UUID of the environment variable.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Environment variable deleted.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Environment variable deleted.'],
- ]
- )
- ),
- ]
- ),
- 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 delete_env_by_uuid(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
-
- $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
- if (! $service) {
- return response()->json(['message' => 'Service not found.'], 404);
- }
-
- $env = EnvironmentVariable::where('uuid', $request->env_uuid)
- ->where('resourceable_type', Service::class)
- ->where('resourceable_id', $service->id)
- ->first();
-
- if (! $env) {
- return response()->json(['message' => 'Environment variable not found.'], 404);
- }
-
- $env->forceDelete();
-
- return response()->json(['message' => 'Environment variable deleted.']);
- }
-
- #[OA\Get(
- summary: 'Start',
- description: 'Start service. `Post` request is also accepted.',
- path: '/services/{uuid}/start',
- operationId: 'start-service-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the service.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Start service.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Service starting request queued.'],
- ]
- )
- ),
- ]
- ),
- 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 action_deploy(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
- if (! $service) {
- return response()->json(['message' => 'Service not found.'], 404);
- }
- if (str($service->status)->contains('running')) {
- return response()->json(['message' => 'Service is already running.'], 400);
- }
- StartService::dispatch($service);
-
- return response()->json(
- [
- 'message' => 'Service starting request queued.',
- ],
- 200
- );
- }
-
- #[OA\Get(
- summary: 'Stop',
- description: 'Stop service. `Post` request is also accepted.',
- path: '/services/{uuid}/stop',
- operationId: 'stop-service-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the service.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Stop service.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Service stopping request queued.'],
- ]
- )
- ),
- ]
- ),
- 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 action_stop(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
- if (! $service) {
- return response()->json(['message' => 'Service not found.'], 404);
- }
- if (str($service->status)->contains('stopped') || str($service->status)->contains('exited')) {
- return response()->json(['message' => 'Service is already stopped.'], 400);
- }
- StopService::dispatch($service);
-
- return response()->json(
- [
- 'message' => 'Service stopping request queued.',
- ],
- 200
- );
- }
-
- #[OA\Get(
- summary: 'Restart',
- description: 'Restart service. `Post` request is also accepted.',
- path: '/services/{uuid}/restart',
- operationId: 'restart-service-by-uuid',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Services'],
- parameters: [
- new OA\Parameter(
- name: 'uuid',
- in: 'path',
- description: 'UUID of the service.',
- required: true,
- schema: new OA\Schema(
- type: 'string',
- format: 'uuid',
- )
- ),
- ],
- responses: [
- new OA\Response(
- response: 200,
- description: 'Restart service.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'object',
- properties: [
- 'message' => ['type' => 'string', 'example' => 'Service restaring request queued.'],
- ]
- )
- ),
- ]
- ),
- 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 action_restart(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $uuid = $request->route('uuid');
- if (! $uuid) {
- return response()->json(['message' => 'UUID is required.'], 400);
- }
- $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
- if (! $service) {
- return response()->json(['message' => 'Service not found.'], 404);
- }
- RestartService::dispatch($service);
-
- return response()->json(
- [
- 'message' => 'Service restarting request queued.',
- ],
- 200
- );
- }
-}
diff --git a/app/Http/Controllers/Api/TeamController.php b/app/Http/Controllers/Api/TeamController.php
deleted file mode 100644
index d4b24d8ab2..0000000000
--- a/app/Http/Controllers/Api/TeamController.php
+++ /dev/null
@@ -1,273 +0,0 @@
-makeHidden([
- 'custom_server_limit',
- 'pivot',
- ]);
- if (request()->attributes->get('can_read_sensitive', false) === false) {
- $team->makeHidden([
- 'smtp_username',
- 'smtp_password',
- 'resend_api_key',
- 'telegram_token',
- ]);
- }
-
- return serializeApiResponse($team);
- }
-
- #[OA\Get(
- summary: 'List',
- description: 'Get all teams.',
- path: '/teams',
- operationId: 'list-teams',
- security: [
- ['bearerAuth' => []],
- ],
- tags: ['Teams'],
- responses: [
- new OA\Response(
- response: 200,
- description: 'List of teams.',
- content: [
- new OA\MediaType(
- mediaType: 'application/json',
- schema: new OA\Schema(
- type: 'array',
- items: new OA\Items(ref: '#/components/schemas/Team')
- )
- ),
- ]),
- new OA\Response(
- response: 401,
- ref: '#/components/responses/401',
- ),
- new OA\Response(
- response: 400,
- ref: '#/components/responses/400',
- ),
- ]
- )]
- public function teams(Request $request)
- {
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $teams = auth()->user()->teams->sortBy('id');
- $teams = $teams->map(function ($team) {
- return $this->removeSensitiveData($team);
- });
-
- return response()->json(
- $teams,
- );
- }
-
- #[OA\Get(
- summary: 'Get',
- description: 'Get team by TeamId.',
- path: '/teams/{id}',
- operationId: 'get-team-by-id',
- 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 teams.',
- 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',
- ),
- new OA\Response(
- response: 404,
- ref: '#/components/responses/404',
- ),
- ]
- )]
- public function team_by_id(Request $request)
- {
- $id = $request->id;
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $teams = auth()->user()->teams;
- $team = $teams->where('id', $id)->first();
- if (is_null($team)) {
- return response()->json(['message' => 'Team not found.'], 404);
- }
- $team = $this->removeSensitiveData($team);
-
- return response()->json(
- serializeApiResponse($team),
- );
- }
-
- #[OA\Get(
- summary: 'Members',
- description: 'Get members by TeamId.',
- path: '/teams/{id}/members',
- operationId: 'get-members-by-team-id',
- 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;
- $teamId = getTeamIdFromToken();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $teams = auth()->user()->teams;
- $team = $teams->where('id', $id)->first();
- if (is_null($team)) {
- return response()->json(['message' => 'Team not found.'], 404);
- }
- $members = $team->members;
- $members->makeHidden([
- 'pivot',
- ]);
-
- return response()->json(
- serializeApiResponse($members),
- );
- }
-
- #[OA\Get(
- summary: 'Authenticated Team',
- description: 'Get currently authenticated team.',
- path: '/teams/current',
- operationId: 'get-current-team',
- 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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $team = auth()->user()->currentTeam();
-
- return response()->json(
- $this->removeSensitiveData($team),
- );
- }
-
- #[OA\Get(
- summary: 'Authenticated Team Members',
- description: 'Get currently authenticated team members.',
- path: '/teams/current/members',
- operationId: 'get-current-team-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();
- if (is_null($teamId)) {
- return invalidTokenResponse();
- }
- $team = auth()->user()->currentTeam();
- $team->members->makeHidden([
- 'pivot',
- ]);
-
- return response()->json(
- serializeApiResponse($team->members),
- );
- }
-}
diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php
deleted file mode 100644
index 14a2950afb..0000000000
--- a/app/Http/Controllers/Controller.php
+++ /dev/null
@@ -1,161 +0,0 @@
-user()?->currentTeam()->id !== 0) {
- return redirect(RouteServiceProvider::HOME);
- }
- TestEvent::dispatch();
-
- return 'Look at your other tab.';
- }
-
- public function verify()
- {
- return view('auth.verify-email');
- }
-
- public function email_verify(EmailVerificationRequest $request)
- {
- $request->fulfill();
-
- return redirect(RouteServiceProvider::HOME);
- }
-
- public function forgot_password(Request $request)
- {
- if (is_transactional_emails_enabled()) {
- $arrayOfRequest = $request->only(Fortify::email());
- $request->merge([
- 'email' => Str::lower($arrayOfRequest['email']),
- ]);
- $type = set_transanctional_email_settings();
- if (blank($type)) {
- return response()->json(['message' => 'Transactional emails are not active'], 400);
- }
- $request->validate([Fortify::email() => 'required|email']);
- $status = Password::broker(config('fortify.passwords'))->sendResetLink(
- $request->only(Fortify::email())
- );
- if ($status == Password::RESET_LINK_SENT) {
- return app(SuccessfulPasswordResetLinkRequestResponse::class, ['status' => $status]);
- }
- if ($status == Password::RESET_THROTTLED) {
- return response('Already requested a password reset in the past minutes.', 400);
- }
-
- return app(FailedPasswordResetLinkRequestResponse::class, ['status' => $status]);
- }
-
- return response()->json(['message' => 'Transactional emails are not active'], 400);
- }
-
- public function link()
- {
- $token = request()->get('token');
- if ($token) {
- $decrypted = Crypt::decryptString($token);
- $email = str($decrypted)->before('@@@');
- $password = str($decrypted)->after('@@@');
- $user = User::whereEmail($email)->first();
- if (! $user) {
- return redirect()->route('login');
- }
- if (Hash::check($password, $user->password)) {
- $invitation = TeamInvitation::whereEmail($email);
- if ($invitation->exists()) {
- $team = $invitation->first()->team;
- $user->teams()->attach($team->id, ['role' => $invitation->first()->role]);
- $invitation->delete();
- } else {
- $team = $user->teams()->first();
- }
- if (is_null(data_get($user, 'email_verified_at'))) {
- $user->email_verified_at = now();
- $user->save();
- }
- Auth::login($user);
- session(['currentTeam' => $team]);
-
- return redirect()->route('dashboard');
- }
- }
-
- return redirect()->route('login')->with('error', 'Invalid credentials.');
- }
-
- public function acceptInvitation()
- {
- $resetPassword = request()->query('reset-password');
- $invitationUuid = request()->route('uuid');
-
- $invitation = TeamInvitation::whereUuid($invitationUuid)->firstOrFail();
- $user = User::whereEmail($invitation->email)->firstOrFail();
-
- if (Auth::id() !== $user->id) {
- abort(400, 'You are not allowed to accept this invitation.');
- }
- $invitationValid = $invitation->isValid();
-
- if ($invitationValid) {
- if ($resetPassword) {
- $user->update([
- 'password' => Hash::make($invitationUuid),
- 'force_password_reset' => true,
- ]);
- }
- if ($user->teams()->where('team_id', $invitation->team->id)->exists()) {
- $invitation->delete();
-
- return redirect()->route('team.index');
- }
- $user->teams()->attach($invitation->team->id, ['role' => $invitation->role]);
- $invitation->delete();
-
- refreshSession($invitation->team);
-
- return redirect()->route('team.index');
- } else {
- abort(400, 'Invitation expired.');
- }
- }
-
- public function revoke_invitation()
- {
- $invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail();
- $user = User::whereEmail($invitation->email)->firstOrFail();
- if (is_null(Auth::user())) {
- return redirect()->route('login');
- }
- if (Auth::id() !== $user->id) {
- abort(401);
- }
- $invitation->delete();
-
- return redirect()->route('team.index');
- }
-}
diff --git a/app/Http/Controllers/MagicController.php b/app/Http/Controllers/MagicController.php
deleted file mode 100644
index 59c9b8b94e..0000000000
--- a/app/Http/Controllers/MagicController.php
+++ /dev/null
@@ -1,84 +0,0 @@
-json([
- 'servers' => Server::isUsable()->get(),
- ]);
- }
-
- public function destinations()
- {
- return response()->json([
- 'destinations' => Server::destinationsByServer(request()->query('server_id'))->sortBy('name'),
- ]);
- }
-
- public function projects()
- {
- return response()->json([
- 'projects' => Project::ownedByCurrentTeam()->get(),
- ]);
- }
-
- public function environments()
- {
- $project = Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->first();
- if (! $project) {
- return response()->json([
- 'environments' => [],
- ]);
- }
-
- return response()->json([
- 'environments' => $project->environments,
- ]);
- }
-
- public function newProject()
- {
- $project = Project::firstOrCreate(
- ['name' => request()->query('name') ?? generate_random_name()],
- ['team_id' => currentTeam()->id]
- );
-
- return response()->json([
- 'project_uuid' => $project->uuid,
- ]);
- }
-
- public function newEnvironment()
- {
- $environment = Environment::firstOrCreate(
- ['name' => request()->query('name') ?? generate_random_name()],
- ['project_id' => Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->firstOrFail()->id]
- );
-
- return response()->json([
- 'environment_name' => $environment->name,
- ]);
- }
-
- public function newTeam()
- {
- $team = Team::create(
- [
- 'name' => request()->query('name') ?? generate_random_name(),
- 'personal_team' => false,
- ],
- );
- auth()->user()->teams()->attach($team, ['role' => 'admin']);
- refreshSession();
-
- return redirect(request()->header('Referer'));
- }
-}
diff --git a/app/Http/Controllers/OauthController.php b/app/Http/Controllers/OauthController.php
deleted file mode 100644
index 3a3f18c9c4..0000000000
--- a/app/Http/Controllers/OauthController.php
+++ /dev/null
@@ -1,43 +0,0 @@
-redirect();
- }
-
- public function callback(string $provider)
- {
- try {
- $oauthUser = get_socialite_provider($provider)->user();
- $user = User::whereEmail($oauthUser->email)->first();
- if (! $user) {
- $settings = instanceSettings();
- if (! $settings->is_registration_enabled) {
- abort(403, 'Registration is disabled');
- }
-
- $user = User::create([
- 'name' => $oauthUser->name,
- 'email' => $oauthUser->email,
- ]);
- }
- Auth::login($user);
-
- return redirect('/');
- } catch (\Exception $e) {
- $errorCode = $e instanceof HttpException ? 'auth.failed' : 'auth.failed.callback';
-
- return redirect()->route('login')->withErrors([__($errorCode)]);
- }
- }
-}
diff --git a/app/Http/Controllers/UploadController.php b/app/Http/Controllers/UploadController.php
deleted file mode 100644
index 4d34a10007..0000000000
--- a/app/Http/Controllers/UploadController.php
+++ /dev/null
@@ -1,81 +0,0 @@
-route('databaseUuid'), data_get(auth()->user()->currentTeam(), 'id'));
- if (is_null($resource)) {
- return response()->json(['error' => 'You do not have permission for this database'], 500);
- }
- $receiver = new FileReceiver('file', $request, HandlerFactory::classFromRequest($request));
-
- if ($receiver->isUploaded() === false) {
- throw new UploadMissingFileException;
- }
-
- $save = $receiver->receive();
-
- if ($save->isFinished()) {
- return $this->saveFile($save->getFile(), $resource);
- }
-
- $handler = $save->handler();
-
- return response()->json([
- 'done' => $handler->getPercentageDone(),
- 'status' => true,
- ]);
- }
- // protected function saveFileToS3($file)
- // {
- // $fileName = $this->createFilename($file);
-
- // $disk = Storage::disk('s3');
- // // It's better to use streaming Streaming (laravel 5.4+)
- // $disk->putFileAs('photos', $file, $fileName);
-
- // // for older laravel
- // // $disk->put($fileName, file_get_contents($file), 'public');
- // $mime = str_replace('/', '-', $file->getMimeType());
-
- // // We need to delete the file when uploaded to s3
- // unlink($file->getPathname());
-
- // return response()->json([
- // 'path' => $disk->url($fileName),
- // 'name' => $fileName,
- // 'mime_type' => $mime
- // ]);
- // }
- protected function saveFile(UploadedFile $file, $resource)
- {
- $mime = str_replace('/', '-', $file->getMimeType());
- $filePath = "upload/{$resource->uuid}";
- $finalPath = storage_path('app/'.$filePath);
- $file->move($finalPath, 'restore');
-
- return response()->json([
- 'mime_type' => $mime,
- ]);
- }
-
- protected function createFilename(UploadedFile $file)
- {
- $extension = $file->getClientOriginalExtension();
- $filename = str_replace('.'.$extension, '', $file->getClientOriginalName()); // Filename without extension
-
- $filename .= '_'.md5(time()).'.'.$extension;
-
- return $filename;
- }
-}
diff --git a/app/Http/Controllers/Webhook/Bitbucket.php b/app/Http/Controllers/Webhook/Bitbucket.php
deleted file mode 100644
index 33d8f85321..0000000000
--- a/app/Http/Controllers/Webhook/Bitbucket.php
+++ /dev/null
@@ -1,194 +0,0 @@
-isDownForMaintenance()) {
- $epoch = now()->valueOf();
- $data = [
- 'attributes' => $request->attributes->all(),
- 'request' => $request->request->all(),
- 'query' => $request->query->all(),
- 'server' => $request->server->all(),
- 'files' => $request->files->all(),
- 'cookies' => $request->cookies->all(),
- 'headers' => $request->headers->all(),
- 'content' => $request->getContent(),
- ];
- $json = json_encode($data);
- Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Bitbicket::manual_bitbucket", $json);
-
- return;
- }
- $return_payloads = collect([]);
- $payload = $request->collect();
- $headers = $request->headers->all();
- $x_bitbucket_token = data_get($headers, 'x-hub-signature.0', '');
- $x_bitbucket_event = data_get($headers, 'x-event-key.0', '');
- $handled_events = collect(['repo:push', 'pullrequest:updated', 'pullrequest:created', 'pullrequest:rejected', 'pullrequest:fulfilled']);
- if (! $handled_events->contains($x_bitbucket_event)) {
- return response([
- 'status' => 'failed',
- 'message' => 'Nothing to do. Event not handled.',
- ]);
- }
- if ($x_bitbucket_event === 'repo:push') {
- $branch = data_get($payload, 'push.changes.0.new.name');
- $full_name = data_get($payload, 'repository.full_name');
- $commit = data_get($payload, 'push.changes.0.new.target.hash');
-
- if (! $branch) {
- return response([
- 'status' => 'failed',
- 'message' => 'Nothing to do. No branch found in the request.',
- ]);
- }
- }
- if ($x_bitbucket_event === 'pullrequest:updated' || $x_bitbucket_event === 'pullrequest:created' || $x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') {
- $branch = data_get($payload, 'pullrequest.destination.branch.name');
- $base_branch = data_get($payload, 'pullrequest.source.branch.name');
- $full_name = data_get($payload, 'repository.full_name');
- $pull_request_id = data_get($payload, 'pullrequest.id');
- $pull_request_html_url = data_get($payload, 'pullrequest.links.html.href');
- $commit = data_get($payload, 'pullrequest.source.commit.hash');
- }
- $applications = Application::where('git_repository', 'like', "%$full_name%");
- $applications = $applications->where('git_branch', $branch)->get();
- if ($applications->isEmpty()) {
- return response([
- 'status' => 'failed',
- 'message' => "Nothing to do. No applications found with deploy key set, branch is '$branch' and Git Repository name has $full_name.",
- ]);
- }
- foreach ($applications as $application) {
- $webhook_secret = data_get($application, 'manual_webhook_secret_bitbucket');
- $payload = $request->getContent();
-
- [$algo, $hash] = explode('=', $x_bitbucket_token, 2);
- $payloadHash = hash_hmac($algo, $payload, $webhook_secret);
- if (! hash_equals($hash, $payloadHash) && ! isDev()) {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Invalid signature.',
- ]);
-
- continue;
- }
- $isFunctional = $application->destination->server->isFunctional();
- if (! $isFunctional) {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Server is not functional.',
- ]);
-
- continue;
- }
- if ($x_bitbucket_event === 'repo:push') {
- if ($application->isDeployable()) {
- $deployment_uuid = new Cuid2;
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- commit: $commit,
- force_rebuild: false,
- is_webhook: true
- );
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'success',
- 'message' => 'Preview deployment queued.',
- ]);
- } else {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Auto deployment disabled.',
- ]);
- }
- }
- if ($x_bitbucket_event === 'pullrequest:created' || $x_bitbucket_event === 'pullrequest:updated') {
- if ($application->isPRDeployable()) {
- $deployment_uuid = new Cuid2;
- $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
- if (! $found) {
- if ($application->build_pack === 'dockercompose') {
- $pr_app = ApplicationPreview::create([
- 'git_type' => 'bitbucket',
- 'application_id' => $application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- 'docker_compose_domains' => $application->docker_compose_domains,
- ]);
- $pr_app->generate_preview_fqdn_compose();
- } else {
- ApplicationPreview::create([
- 'git_type' => 'bitbucket',
- 'application_id' => $application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- ]);
- }
- }
- queue_application_deployment(
- application: $application,
- pull_request_id: $pull_request_id,
- deployment_uuid: $deployment_uuid,
- force_rebuild: false,
- commit: $commit,
- is_webhook: true,
- git_type: 'bitbucket'
- );
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'success',
- 'message' => 'Preview deployment queued.',
- ]);
- } else {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Preview deployments disabled.',
- ]);
- }
- }
- if ($x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') {
- $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
- if ($found) {
- $found->delete();
- $container_name = generateApplicationContainerName($application, $pull_request_id);
- instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'success',
- 'message' => 'Preview deployment closed.',
- ]);
- } else {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'No preview deployment found.',
- ]);
- }
- }
- }
-
- return response($return_payloads);
- } catch (Exception $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Http/Controllers/Webhook/Gitea.php b/app/Http/Controllers/Webhook/Gitea.php
deleted file mode 100644
index 87fd2255f2..0000000000
--- a/app/Http/Controllers/Webhook/Gitea.php
+++ /dev/null
@@ -1,227 +0,0 @@
-header('X-Gitea-Delivery');
- if (app()->isDownForMaintenance()) {
- $epoch = now()->valueOf();
- $files = Storage::disk('webhooks-during-maintenance')->files();
- $gitea_delivery_found = collect($files)->filter(function ($file) use ($x_gitea_delivery) {
- return Str::contains($file, $x_gitea_delivery);
- })->first();
- if ($gitea_delivery_found) {
- return;
- }
- $data = [
- 'attributes' => $request->attributes->all(),
- 'request' => $request->request->all(),
- 'query' => $request->query->all(),
- 'server' => $request->server->all(),
- 'files' => $request->files->all(),
- 'cookies' => $request->cookies->all(),
- 'headers' => $request->headers->all(),
- 'content' => $request->getContent(),
- ];
- $json = json_encode($data);
- Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Gitea::manual_{$x_gitea_delivery}", $json);
-
- return;
- }
- $x_gitea_event = Str::lower($request->header('X-Gitea-Event'));
- $x_hub_signature_256 = Str::after($request->header('X-Hub-Signature-256'), 'sha256=');
- $content_type = $request->header('Content-Type');
- $payload = $request->collect();
- if ($x_gitea_event === 'ping') {
- // Just pong
- return response('pong');
- }
-
- if ($content_type !== 'application/json') {
- $payload = json_decode(data_get($payload, 'payload'), true);
- }
- if ($x_gitea_event === 'push') {
- $branch = data_get($payload, 'ref');
- $full_name = data_get($payload, 'repository.full_name');
- if (Str::isMatch('/refs\/heads\/*/', $branch)) {
- $branch = Str::after($branch, 'refs/heads/');
- }
- $added_files = data_get($payload, 'commits.*.added');
- $removed_files = data_get($payload, 'commits.*.removed');
- $modified_files = data_get($payload, 'commits.*.modified');
- $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
- }
- if ($x_gitea_event === 'pull_request') {
- $action = data_get($payload, 'action');
- $full_name = data_get($payload, 'repository.full_name');
- $pull_request_id = data_get($payload, 'number');
- $pull_request_html_url = data_get($payload, 'pull_request.html_url');
- $branch = data_get($payload, 'pull_request.head.ref');
- $base_branch = data_get($payload, 'pull_request.base.ref');
- }
- if (! $branch) {
- return response('Nothing to do. No branch found in the request.');
- }
- $applications = Application::where('git_repository', 'like', "%$full_name%");
- if ($x_gitea_event === 'push') {
- $applications = $applications->where('git_branch', $branch)->get();
- if ($applications->isEmpty()) {
- return response("Nothing to do. No applications found with deploy key set, branch is '$branch' and Git Repository name has $full_name.");
- }
- }
- if ($x_gitea_event === 'pull_request') {
- $applications = $applications->where('git_branch', $base_branch)->get();
- if ($applications->isEmpty()) {
- return response("Nothing to do. No applications found with branch '$base_branch'.");
- }
- }
- foreach ($applications as $application) {
- $webhook_secret = data_get($application, 'manual_webhook_secret_gitea');
- $hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret);
- if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Invalid signature.',
- ]);
-
- continue;
- }
- $isFunctional = $application->destination->server->isFunctional();
- if (! $isFunctional) {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Server is not functional.',
- ]);
-
- continue;
- }
- if ($x_gitea_event === 'push') {
- if ($application->isDeployable()) {
- $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
- if ($is_watch_path_triggered || is_null($application->watch_paths)) {
- $deployment_uuid = new Cuid2;
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- force_rebuild: false,
- commit: data_get($payload, 'after', 'HEAD'),
- is_webhook: true,
- );
- $return_payloads->push([
- 'status' => 'success',
- 'message' => 'Deployment queued.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- ]);
- } else {
- $paths = str($application->watch_paths)->explode("\n");
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Changed files do not match watch paths. Ignoring deployment.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- 'details' => [
- 'changed_files' => $changed_files,
- 'watch_paths' => $paths,
- ],
- ]);
- }
- } else {
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Deployments disabled.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- ]);
- }
- }
- if ($x_gitea_event === 'pull_request') {
- if ($action === 'opened' || $action === 'synchronized' || $action === 'reopened') {
- if ($application->isPRDeployable()) {
- $deployment_uuid = new Cuid2;
- $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
- if (! $found) {
- if ($application->build_pack === 'dockercompose') {
- $pr_app = ApplicationPreview::create([
- 'git_type' => 'gitea',
- 'application_id' => $application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- 'docker_compose_domains' => $application->docker_compose_domains,
- ]);
- $pr_app->generate_preview_fqdn_compose();
- } else {
- ApplicationPreview::create([
- 'git_type' => 'gitea',
- 'application_id' => $application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- ]);
- }
- }
- queue_application_deployment(
- application: $application,
- pull_request_id: $pull_request_id,
- deployment_uuid: $deployment_uuid,
- force_rebuild: false,
- commit: data_get($payload, 'head.sha', 'HEAD'),
- is_webhook: true,
- git_type: 'gitea'
- );
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'success',
- 'message' => 'Preview deployment queued.',
- ]);
- } else {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Preview deployments disabled.',
- ]);
- }
- }
- if ($action === 'closed') {
- $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
- if ($found) {
- $found->delete();
- $container_name = generateApplicationContainerName($application, $pull_request_id);
- instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'success',
- 'message' => 'Preview deployment closed.',
- ]);
- } else {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'No preview deployment found.',
- ]);
- }
- }
- }
- }
-
- return response($return_payloads);
- } catch (Exception $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Http/Controllers/Webhook/Github.php b/app/Http/Controllers/Webhook/Github.php
deleted file mode 100644
index 882f2be8b9..0000000000
--- a/app/Http/Controllers/Webhook/Github.php
+++ /dev/null
@@ -1,518 +0,0 @@
-header('X-GitHub-Delivery');
- if (app()->isDownForMaintenance()) {
- $epoch = now()->valueOf();
- $files = Storage::disk('webhooks-during-maintenance')->files();
- $github_delivery_found = collect($files)->filter(function ($file) use ($x_github_delivery) {
- return Str::contains($file, $x_github_delivery);
- })->first();
- if ($github_delivery_found) {
- return;
- }
- $data = [
- 'attributes' => $request->attributes->all(),
- 'request' => $request->request->all(),
- 'query' => $request->query->all(),
- 'server' => $request->server->all(),
- 'files' => $request->files->all(),
- 'cookies' => $request->cookies->all(),
- 'headers' => $request->headers->all(),
- 'content' => $request->getContent(),
- ];
- $json = json_encode($data);
- Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::manual_{$x_github_delivery}", $json);
-
- return;
- }
- $x_github_event = Str::lower($request->header('X-GitHub-Event'));
- $x_hub_signature_256 = Str::after($request->header('X-Hub-Signature-256'), 'sha256=');
- $content_type = $request->header('Content-Type');
- $payload = $request->collect();
- if ($x_github_event === 'ping') {
- // Just pong
- return response('pong');
- }
-
- if ($content_type !== 'application/json') {
- $payload = json_decode(data_get($payload, 'payload'), true);
- }
- if ($x_github_event === 'push') {
- $branch = data_get($payload, 'ref');
- $full_name = data_get($payload, 'repository.full_name');
- if (Str::isMatch('/refs\/heads\/*/', $branch)) {
- $branch = Str::after($branch, 'refs/heads/');
- }
- $added_files = data_get($payload, 'commits.*.added');
- $removed_files = data_get($payload, 'commits.*.removed');
- $modified_files = data_get($payload, 'commits.*.modified');
- $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
- }
- if ($x_github_event === 'pull_request') {
- $action = data_get($payload, 'action');
- $full_name = data_get($payload, 'repository.full_name');
- $pull_request_id = data_get($payload, 'number');
- $pull_request_html_url = data_get($payload, 'pull_request.html_url');
- $branch = data_get($payload, 'pull_request.head.ref');
- $base_branch = data_get($payload, 'pull_request.base.ref');
- }
- if (! $branch) {
- return response('Nothing to do. No branch found in the request.');
- }
- $applications = Application::where('git_repository', 'like', "%$full_name%");
- if ($x_github_event === 'push') {
- $applications = $applications->where('git_branch', $branch)->get();
- if ($applications->isEmpty()) {
- return response("Nothing to do. No applications found with deploy key set, branch is '$branch' and Git Repository name has $full_name.");
- }
- }
- if ($x_github_event === 'pull_request') {
- $applications = $applications->where('git_branch', $base_branch)->get();
- if ($applications->isEmpty()) {
- return response("Nothing to do. No applications found with branch '$base_branch'.");
- }
- }
- foreach ($applications as $application) {
- $webhook_secret = data_get($application, 'manual_webhook_secret_github');
- $hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret);
- if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Invalid signature.',
- ]);
-
- continue;
- }
- $isFunctional = $application->destination->server->isFunctional();
- if (! $isFunctional) {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Server is not functional.',
- ]);
-
- continue;
- }
- if ($x_github_event === 'push') {
- if ($application->isDeployable()) {
- $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
- if ($is_watch_path_triggered || is_null($application->watch_paths)) {
- $deployment_uuid = new Cuid2;
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- force_rebuild: false,
- commit: data_get($payload, 'after', 'HEAD'),
- is_webhook: true,
- );
- $return_payloads->push([
- 'status' => 'success',
- 'message' => 'Deployment queued.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- ]);
- } else {
- $paths = str($application->watch_paths)->explode("\n");
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Changed files do not match watch paths. Ignoring deployment.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- 'details' => [
- 'changed_files' => $changed_files,
- 'watch_paths' => $paths,
- ],
- ]);
- }
- } else {
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Deployments disabled.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- ]);
- }
- }
- if ($x_github_event === 'pull_request') {
- if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
- if ($application->isPRDeployable()) {
- $deployment_uuid = new Cuid2;
- $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
- if (! $found) {
- if ($application->build_pack === 'dockercompose') {
- $pr_app = ApplicationPreview::create([
- 'git_type' => 'github',
- 'application_id' => $application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- 'docker_compose_domains' => $application->docker_compose_domains,
- ]);
- $pr_app->generate_preview_fqdn_compose();
- } else {
- ApplicationPreview::create([
- 'git_type' => 'github',
- 'application_id' => $application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- ]);
- }
- }
- queue_application_deployment(
- application: $application,
- pull_request_id: $pull_request_id,
- deployment_uuid: $deployment_uuid,
- force_rebuild: false,
- commit: data_get($payload, 'head.sha', 'HEAD'),
- is_webhook: true,
- git_type: 'github'
- );
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'success',
- 'message' => 'Preview deployment queued.',
- ]);
- } else {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Preview deployments disabled.',
- ]);
- }
- }
- if ($action === 'closed') {
- $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
- if ($found) {
- $found->delete();
- $container_name = generateApplicationContainerName($application, $pull_request_id);
- instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'success',
- 'message' => 'Preview deployment closed.',
- ]);
- } else {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'No preview deployment found.',
- ]);
- }
- }
- }
- }
-
- return response($return_payloads);
- } catch (Exception $e) {
- return handleError($e);
- }
- }
-
- public function normal(Request $request)
- {
- try {
- $return_payloads = collect([]);
- $id = null;
- $x_github_delivery = $request->header('X-GitHub-Delivery');
- if (app()->isDownForMaintenance()) {
- $epoch = now()->valueOf();
- $files = Storage::disk('webhooks-during-maintenance')->files();
- $github_delivery_found = collect($files)->filter(function ($file) use ($x_github_delivery) {
- return Str::contains($file, $x_github_delivery);
- })->first();
- if ($github_delivery_found) {
- return;
- }
- $data = [
- 'attributes' => $request->attributes->all(),
- 'request' => $request->request->all(),
- 'query' => $request->query->all(),
- 'server' => $request->server->all(),
- 'files' => $request->files->all(),
- 'cookies' => $request->cookies->all(),
- 'headers' => $request->headers->all(),
- 'content' => $request->getContent(),
- ];
- $json = json_encode($data);
- Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::normal_{$x_github_delivery}", $json);
-
- return;
- }
- $x_github_event = Str::lower($request->header('X-GitHub-Event'));
- $x_github_hook_installation_target_id = $request->header('X-GitHub-Hook-Installation-Target-Id');
- $x_hub_signature_256 = Str::after($request->header('X-Hub-Signature-256'), 'sha256=');
- $payload = $request->collect();
- if ($x_github_event === 'ping') {
- // Just pong
- return response('pong');
- }
- $github_app = GithubApp::where('app_id', $x_github_hook_installation_target_id)->first();
- if (is_null($github_app)) {
- return response('Nothing to do. No GitHub App found.');
- }
- $webhook_secret = data_get($github_app, 'webhook_secret');
- $hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret);
- if (config('app.env') !== 'local') {
- if (! hash_equals($x_hub_signature_256, $hmac)) {
- return response('Invalid signature.');
- }
- }
- if ($x_github_event === 'installation' || $x_github_event === 'installation_repositories') {
- // Installation handled by setup redirect url. Repositories queried on-demand.
- $action = data_get($payload, 'action');
- if ($action === 'new_permissions_accepted') {
- GithubAppPermissionJob::dispatch($github_app);
- }
-
- return response('cool');
- }
- if ($x_github_event === 'push') {
- $id = data_get($payload, 'repository.id');
- $branch = data_get($payload, 'ref');
- if (Str::isMatch('/refs\/heads\/*/', $branch)) {
- $branch = Str::after($branch, 'refs/heads/');
- }
- $added_files = data_get($payload, 'commits.*.added');
- $removed_files = data_get($payload, 'commits.*.removed');
- $modified_files = data_get($payload, 'commits.*.modified');
- $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
- }
- if ($x_github_event === 'pull_request') {
- $action = data_get($payload, 'action');
- $id = data_get($payload, 'repository.id');
- $pull_request_id = data_get($payload, 'number');
- $pull_request_html_url = data_get($payload, 'pull_request.html_url');
- $branch = data_get($payload, 'pull_request.head.ref');
- $base_branch = data_get($payload, 'pull_request.base.ref');
- }
- if (! $id || ! $branch) {
- return response('Nothing to do. No id or branch found.');
- }
- $applications = Application::where('repository_project_id', $id)->whereRelation('source', 'is_public', false);
- if ($x_github_event === 'push') {
- $applications = $applications->where('git_branch', $branch)->get();
- if ($applications->isEmpty()) {
- return response("Nothing to do. No applications found with branch '$branch'.");
- }
- }
- if ($x_github_event === 'pull_request') {
- $applications = $applications->where('git_branch', $base_branch)->get();
- if ($applications->isEmpty()) {
- return response("Nothing to do. No applications found with branch '$base_branch'.");
- }
- }
- foreach ($applications as $application) {
- $isFunctional = $application->destination->server->isFunctional();
- if (! $isFunctional) {
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Server is not functional.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- ]);
-
- continue;
- }
- if ($x_github_event === 'push') {
- if ($application->isDeployable()) {
- $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
- if ($is_watch_path_triggered || is_null($application->watch_paths)) {
- $deployment_uuid = new Cuid2;
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- commit: data_get($payload, 'after', 'HEAD'),
- force_rebuild: false,
- is_webhook: true,
- );
- $return_payloads->push([
- 'status' => 'success',
- 'message' => 'Deployment queued.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- ]);
- } else {
- $paths = str($application->watch_paths)->explode("\n");
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Changed files do not match watch paths. Ignoring deployment.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- 'details' => [
- 'changed_files' => $changed_files,
- 'watch_paths' => $paths,
- ],
- ]);
- }
- } else {
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Deployments disabled.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- ]);
- }
- }
- if ($x_github_event === 'pull_request') {
- if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
- if ($application->isPRDeployable()) {
- $deployment_uuid = new Cuid2;
- $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
- if (! $found) {
- ApplicationPreview::create([
- 'git_type' => 'github',
- 'application_id' => $application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- ]);
- }
- queue_application_deployment(
- application: $application,
- pull_request_id: $pull_request_id,
- deployment_uuid: $deployment_uuid,
- force_rebuild: false,
- commit: data_get($payload, 'head.sha', 'HEAD'),
- is_webhook: true,
- git_type: 'github'
- );
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'success',
- 'message' => 'Preview deployment queued.',
- ]);
- } else {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Preview deployments disabled.',
- ]);
- }
- }
- if ($action === 'closed' || $action === 'close') {
- $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
- if ($found) {
- $containers = getCurrentApplicationContainerStatus($application->destination->server, $application->id, $pull_request_id);
- if ($containers->isNotEmpty()) {
- $containers->each(function ($container) use ($application) {
- $container_name = data_get($container, 'Names');
- instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
- });
- }
-
- ApplicationPullRequestUpdateJob::dispatchSync(application: $application, preview: $found, status: ProcessStatus::CLOSED);
- $found->delete();
-
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'success',
- 'message' => 'Preview deployment closed.',
- ]);
- } else {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'No preview deployment found.',
- ]);
- }
- }
- }
- }
-
- return response($return_payloads);
- } catch (Exception $e) {
- return handleError($e);
- }
- }
-
- public function redirect(Request $request)
- {
- try {
- $code = $request->get('code');
- $state = $request->get('state');
- $github_app = GithubApp::where('uuid', $state)->firstOrFail();
- $api_url = data_get($github_app, 'api_url');
- $data = Http::withBody(null)->accept('application/vnd.github+json')->post("$api_url/app-manifests/$code/conversions")->throw()->json();
- $id = data_get($data, 'id');
- $slug = data_get($data, 'slug');
- $client_id = data_get($data, 'client_id');
- $client_secret = data_get($data, 'client_secret');
- $private_key = data_get($data, 'pem');
- $webhook_secret = data_get($data, 'webhook_secret');
- $private_key = PrivateKey::create([
- 'name' => "github-app-{$slug}",
- 'private_key' => $private_key,
- 'team_id' => $github_app->team_id,
- 'is_git_related' => true,
- ]);
- $github_app->name = $slug;
- $github_app->app_id = $id;
- $github_app->client_id = $client_id;
- $github_app->client_secret = $client_secret;
- $github_app->webhook_secret = $webhook_secret;
- $github_app->private_key_id = $private_key->id;
- $github_app->save();
-
- return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
- } catch (Exception $e) {
- return handleError($e);
- }
- }
-
- public function install(Request $request)
- {
- try {
- $installation_id = $request->get('installation_id');
- if (app()->isDownForMaintenance()) {
- $epoch = now()->valueOf();
- $data = [
- 'attributes' => $request->attributes->all(),
- 'request' => $request->request->all(),
- 'query' => $request->query->all(),
- 'server' => $request->server->all(),
- 'files' => $request->files->all(),
- 'cookies' => $request->cookies->all(),
- 'headers' => $request->headers->all(),
- 'content' => $request->getContent(),
- ];
- $json = json_encode($data);
- Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::install_{$installation_id}", $json);
-
- return;
- }
- $source = $request->get('source');
- $setup_action = $request->get('setup_action');
- $github_app = GithubApp::where('uuid', $source)->firstOrFail();
- if ($setup_action === 'install') {
- $github_app->installation_id = $installation_id;
- $github_app->save();
- }
-
- return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
- } catch (Exception $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Http/Controllers/Webhook/Gitlab.php b/app/Http/Controllers/Webhook/Gitlab.php
deleted file mode 100644
index cf6874b8cc..0000000000
--- a/app/Http/Controllers/Webhook/Gitlab.php
+++ /dev/null
@@ -1,259 +0,0 @@
-isDownForMaintenance()) {
- $epoch = now()->valueOf();
- $data = [
- 'attributes' => $request->attributes->all(),
- 'request' => $request->request->all(),
- 'query' => $request->query->all(),
- 'server' => $request->server->all(),
- 'files' => $request->files->all(),
- 'cookies' => $request->cookies->all(),
- 'headers' => $request->headers->all(),
- 'content' => $request->getContent(),
- ];
- $json = json_encode($data);
- Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Gitlab::manual_gitlab", $json);
-
- return;
- }
-
- $return_payloads = collect([]);
- $payload = $request->collect();
- $headers = $request->headers->all();
- $x_gitlab_token = data_get($headers, 'x-gitlab-token.0');
- $x_gitlab_event = data_get($payload, 'object_kind');
- $allowed_events = ['push', 'merge_request'];
- if (! in_array($x_gitlab_event, $allowed_events)) {
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Event not allowed. Only push and merge_request events are allowed.',
- ]);
-
- return response($return_payloads);
- }
-
- if (empty($x_gitlab_token)) {
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Invalid signature.',
- ]);
-
- return response($return_payloads);
- }
-
- if ($x_gitlab_event === 'push') {
- $branch = data_get($payload, 'ref');
- $full_name = data_get($payload, 'project.path_with_namespace');
- if (Str::isMatch('/refs\/heads\/*/', $branch)) {
- $branch = Str::after($branch, 'refs/heads/');
- }
- if (! $branch) {
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Nothing to do. No branch found in the request.',
- ]);
-
- return response($return_payloads);
- }
- $added_files = data_get($payload, 'commits.*.added');
- $removed_files = data_get($payload, 'commits.*.removed');
- $modified_files = data_get($payload, 'commits.*.modified');
- $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten();
- }
- if ($x_gitlab_event === 'merge_request') {
- $action = data_get($payload, 'object_attributes.action');
- $branch = data_get($payload, 'object_attributes.source_branch');
- $base_branch = data_get($payload, 'object_attributes.target_branch');
- $full_name = data_get($payload, 'project.path_with_namespace');
- $pull_request_id = data_get($payload, 'object_attributes.iid');
- $pull_request_html_url = data_get($payload, 'object_attributes.url');
- if (! $branch) {
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Nothing to do. No branch found in the request.',
- ]);
-
- return response($return_payloads);
- }
- }
- $applications = Application::where('git_repository', 'like', "%$full_name%");
- if ($x_gitlab_event === 'push') {
- $applications = $applications->where('git_branch', $branch)->get();
- if ($applications->isEmpty()) {
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => "Nothing to do. No applications found with deploy key set, branch is '$branch' and Git Repository name has $full_name.",
- ]);
-
- return response($return_payloads);
- }
- }
- if ($x_gitlab_event === 'merge_request') {
- $applications = $applications->where('git_branch', $base_branch)->get();
- if ($applications->isEmpty()) {
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => "Nothing to do. No applications found with branch '$base_branch'.",
- ]);
-
- return response($return_payloads);
- }
- }
- foreach ($applications as $application) {
- $webhook_secret = data_get($application, 'manual_webhook_secret_gitlab');
- if ($webhook_secret !== $x_gitlab_token) {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Invalid signature.',
- ]);
-
- continue;
- }
- $isFunctional = $application->destination->server->isFunctional();
- if (! $isFunctional) {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Server is not functional',
- ]);
-
- continue;
- }
- if ($x_gitlab_event === 'push') {
- if ($application->isDeployable()) {
- $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
- if ($is_watch_path_triggered || is_null($application->watch_paths)) {
- $deployment_uuid = new Cuid2;
- queue_application_deployment(
- application: $application,
- deployment_uuid: $deployment_uuid,
- commit: data_get($payload, 'after', 'HEAD'),
- force_rebuild: false,
- is_webhook: true,
- );
- $return_payloads->push([
- 'status' => 'success',
- 'message' => 'Deployment queued.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- ]);
- } else {
- $paths = str($application->watch_paths)->explode("\n");
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Changed files do not match watch paths. Ignoring deployment.',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- 'details' => [
- 'changed_files' => $changed_files,
- 'watch_paths' => $paths,
- ],
- ]);
- }
- } else {
- $return_payloads->push([
- 'status' => 'failed',
- 'message' => 'Deployments disabled',
- 'application_uuid' => $application->uuid,
- 'application_name' => $application->name,
- ]);
- }
- }
- if ($x_gitlab_event === 'merge_request') {
- if ($action === 'open' || $action === 'opened' || $action === 'synchronize' || $action === 'reopened' || $action === 'reopen' || $action === 'update') {
- if ($application->isPRDeployable()) {
- $deployment_uuid = new Cuid2;
- $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
- if (! $found) {
- if ($application->build_pack === 'dockercompose') {
- $pr_app = ApplicationPreview::create([
- 'git_type' => 'gitlab',
- 'application_id' => $application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- 'docker_compose_domains' => $application->docker_compose_domains,
- ]);
- $pr_app->generate_preview_fqdn_compose();
- } else {
- ApplicationPreview::create([
- 'git_type' => 'gitlab',
- 'application_id' => $application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- ]);
- }
- }
- queue_application_deployment(
- application: $application,
- pull_request_id: $pull_request_id,
- deployment_uuid: $deployment_uuid,
- commit: data_get($payload, 'object_attributes.last_commit.id', 'HEAD'),
- force_rebuild: false,
- is_webhook: true,
- git_type: 'gitlab'
- );
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'success',
- 'message' => 'Preview Deployment queued',
- ]);
- } else {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'Preview deployments disabled',
- ]);
- }
- } elseif ($action === 'closed' || $action === 'close' || $action === 'merge') {
- $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
- if ($found) {
- $found->delete();
- $container_name = generateApplicationContainerName($application, $pull_request_id);
- instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'success',
- 'message' => 'Preview Deployment closed',
- ]);
-
- return response($return_payloads);
- }
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'No Preview Deployment found',
- ]);
- } else {
- $return_payloads->push([
- 'application' => $application->name,
- 'status' => 'failed',
- 'message' => 'No action found. Contact us for debugging.',
- ]);
- }
- }
- }
-
- return response($return_payloads);
- } catch (Exception $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Http/Controllers/Webhook/Stripe.php b/app/Http/Controllers/Webhook/Stripe.php
deleted file mode 100644
index 83ba16699a..0000000000
--- a/app/Http/Controllers/Webhook/Stripe.php
+++ /dev/null
@@ -1,59 +0,0 @@
-header('Stripe-Signature');
- $event = \Stripe\Webhook::constructEvent(
- $request->getContent(),
- $signature,
- $webhookSecret
- );
- if (app()->isDownForMaintenance()) {
- $epoch = now()->valueOf();
- $data = [
- 'attributes' => $request->attributes->all(),
- 'request' => $request->request->all(),
- 'query' => $request->query->all(),
- 'server' => $request->server->all(),
- 'files' => $request->files->all(),
- 'cookies' => $request->cookies->all(),
- 'headers' => $request->headers->all(),
- 'content' => $request->getContent(),
- ];
- $json = json_encode($data);
- Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Stripe::events_stripe", $json);
-
- return response('Webhook received. Cool cool cool cool cool.', 200);
- }
- $this->webhook = Webhook::create([
- 'type' => 'stripe',
- 'payload' => $request->getContent(),
- ]);
- StripeProcessJob::dispatch($event);
-
- return response('Webhook received. Cool cool cool cool cool.', 200);
- } catch (Exception $e) {
- $this->webhook->update([
- 'status' => 'failed',
- 'failure_reason' => $e->getMessage(),
- ]);
-
- return response($e->getMessage(), 400);
- }
- }
-}
diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php
deleted file mode 100644
index a1ce20295b..0000000000
--- a/app/Http/Kernel.php
+++ /dev/null
@@ -1,75 +0,0 @@
-
- */
- protected $middleware = [
- // \App\Http\Middleware\TrustHosts::class,
- \App\Http\Middleware\TrustProxies::class,
- \Illuminate\Http\Middleware\HandleCors::class,
- \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
- \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
- \App\Http\Middleware\TrimStrings::class,
- \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
-
- ];
-
- /**
- * The application's route middleware groups.
- *
- * @var array>
- */
- protected $middlewareGroups = [
- 'web' => [
- \App\Http\Middleware\EncryptCookies::class,
- \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
- \Illuminate\Session\Middleware\StartSession::class,
- \Illuminate\View\Middleware\ShareErrorsFromSession::class,
- \App\Http\Middleware\VerifyCsrfToken::class,
- \Illuminate\Routing\Middleware\SubstituteBindings::class,
- \App\Http\Middleware\CheckForcePasswordReset::class,
- \App\Http\Middleware\DecideWhatToDoWithUser::class,
-
- ],
-
- 'api' => [
- // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
- \Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
- \Illuminate\Routing\Middleware\SubstituteBindings::class,
- ],
- ];
-
- /**
- * The application's middleware aliases.
- *
- * Aliases may be used to conveniently assign middleware to routes and groups.
- *
- * @var array
- */
- protected $middlewareAliases = [
- 'auth' => \App\Http\Middleware\Authenticate::class,
- 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
- 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
- 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
- 'can' => \Illuminate\Auth\Middleware\Authorize::class,
- 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
- 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
- 'signed' => \App\Http\Middleware\ValidateSignature::class,
- 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
- 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
- 'abilities' => \Laravel\Sanctum\Http\Middleware\CheckAbilities::class,
- 'ability' => \Laravel\Sanctum\Http\Middleware\CheckForAnyAbility::class,
- 'api.ability' => \App\Http\Middleware\ApiAbility::class,
- 'api.sensitive' => \App\Http\Middleware\ApiSensitiveData::class,
- ];
-}
diff --git a/app/Http/Middleware/ApiAbility.php b/app/Http/Middleware/ApiAbility.php
deleted file mode 100644
index 324eeebaa3..0000000000
--- a/app/Http/Middleware/ApiAbility.php
+++ /dev/null
@@ -1,27 +0,0 @@
-user()->tokenCan('root')) {
- return $next($request);
- }
-
- return parent::handle($request, $next, ...$abilities);
- } catch (\Illuminate\Auth\AuthenticationException $e) {
- return response()->json([
- 'message' => 'Unauthenticated.',
- ], 401);
- } catch (\Exception $e) {
- return response()->json([
- 'message' => 'Missing required permissions: '.implode(', ', $abilities),
- ], 403);
- }
- }
-}
diff --git a/app/Http/Middleware/ApiAllowed.php b/app/Http/Middleware/ApiAllowed.php
deleted file mode 100644
index dc6be5da3d..0000000000
--- a/app/Http/Middleware/ApiAllowed.php
+++ /dev/null
@@ -1,32 +0,0 @@
-is_api_enabled === false) {
- return response()->json(['success' => true, 'message' => 'API is disabled.'], 403);
- }
-
- if (! isDev()) {
- if ($settings->allowed_ips) {
- $allowedIps = explode(',', $settings->allowed_ips);
- if (! in_array($request->ip(), $allowedIps)) {
- return response()->json(['success' => true, 'message' => 'You are not allowed to access the API.'], 403);
- }
- }
- }
-
- return $next($request);
- }
-}
diff --git a/app/Http/Middleware/ApiSensitiveData.php b/app/Http/Middleware/ApiSensitiveData.php
deleted file mode 100644
index 49584ddb3f..0000000000
--- a/app/Http/Middleware/ApiSensitiveData.php
+++ /dev/null
@@ -1,21 +0,0 @@
-user()->currentAccessToken();
-
- // Allow access to sensitive data if token has root or read:sensitive permission
- $request->attributes->add([
- 'can_read_sensitive' => $token->can('root') || $token->can('read:sensitive'),
- ]);
-
- return $next($request);
- }
-}
diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php
deleted file mode 100644
index d4ef6447a9..0000000000
--- a/app/Http/Middleware/Authenticate.php
+++ /dev/null
@@ -1,17 +0,0 @@
-expectsJson() ? null : route('login');
- }
-}
diff --git a/app/Http/Middleware/CheckForcePasswordReset.php b/app/Http/Middleware/CheckForcePasswordReset.php
deleted file mode 100644
index 78b1f896c4..0000000000
--- a/app/Http/Middleware/CheckForcePasswordReset.php
+++ /dev/null
@@ -1,38 +0,0 @@
-user()) {
- if ($request->path() === 'auth/link') {
- auth()->logout();
- request()->session()->invalidate();
- request()->session()->regenerateToken();
-
- return $next($request);
- }
- $force_password_reset = auth()->user()->force_password_reset;
- if ($force_password_reset) {
- if ($request->routeIs('auth.force-password-reset') || $request->path() === 'force-password-reset' || $request->path() === 'livewire/update' || $request->path() === 'logout') {
- return $next($request);
- }
-
- return redirect()->route('auth.force-password-reset');
- }
- }
-
- return $next($request);
- }
-}
diff --git a/app/Http/Middleware/DecideWhatToDoWithUser.php b/app/Http/Middleware/DecideWhatToDoWithUser.php
deleted file mode 100644
index 8b1c550dfe..0000000000
--- a/app/Http/Middleware/DecideWhatToDoWithUser.php
+++ /dev/null
@@ -1,61 +0,0 @@
-user()?->teams?->count() === 0) {
- $currentTeam = auth()->user()?->recreate_personal_team();
- refreshSession($currentTeam);
- }
- if (auth()?->user()?->currentTeam()) {
- refreshSession(auth()->user()->currentTeam());
- }
- if (! auth()->user() || ! isCloud() || isInstanceAdmin()) {
- if (! isCloud() && showBoarding() && ! in_array($request->path(), allowedPathsForBoardingAccounts())) {
- return redirect()->route('onboarding');
- }
-
- return $next($request);
- }
- if (! auth()->user()->hasVerifiedEmail()) {
- if ($request->path() === 'verify' || in_array($request->path(), allowedPathsForInvalidAccounts()) || $request->routeIs('verify.verify')) {
- return $next($request);
- }
-
- return redirect()->route('verify.email');
- }
- if (! isSubscriptionActive() && ! isSubscriptionOnGracePeriod()) {
- if (! in_array($request->path(), allowedPathsForUnsubscribedAccounts())) {
- if (Str::startsWith($request->path(), 'invitations')) {
- return $next($request);
- }
-
- return redirect()->route('subscription.index');
- }
- }
- if (showBoarding() && ! in_array($request->path(), allowedPathsForBoardingAccounts())) {
- if (Str::startsWith($request->path(), 'invitations')) {
- return $next($request);
- }
-
- return redirect()->route('onboarding');
- }
- if (auth()->user()->hasVerifiedEmail() && $request->path() === 'verify') {
- return redirect(RouteServiceProvider::HOME);
- }
- if (isSubscriptionActive() && $request->routeIs('subscription.index')) {
- return redirect(RouteServiceProvider::HOME);
- }
-
- return $next($request);
- }
-}
diff --git a/app/Http/Middleware/EncryptCookies.php b/app/Http/Middleware/EncryptCookies.php
deleted file mode 100644
index 867695bdcf..0000000000
--- a/app/Http/Middleware/EncryptCookies.php
+++ /dev/null
@@ -1,17 +0,0 @@
-
- */
- protected $except = [
- //
- ];
-}
diff --git a/app/Http/Middleware/PreventRequestsDuringMaintenance.php b/app/Http/Middleware/PreventRequestsDuringMaintenance.php
deleted file mode 100644
index 2a4feea1e4..0000000000
--- a/app/Http/Middleware/PreventRequestsDuringMaintenance.php
+++ /dev/null
@@ -1,18 +0,0 @@
-
- */
- protected $except = [
- 'webhooks/*',
- '/api/health',
- ];
-}
diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php
deleted file mode 100644
index afc78c4e53..0000000000
--- a/app/Http/Middleware/RedirectIfAuthenticated.php
+++ /dev/null
@@ -1,30 +0,0 @@
-check()) {
- return redirect(RouteServiceProvider::HOME);
- }
- }
-
- return $next($request);
- }
-}
diff --git a/app/Http/Middleware/TrimStrings.php b/app/Http/Middleware/TrimStrings.php
deleted file mode 100644
index 88cadcaaf2..0000000000
--- a/app/Http/Middleware/TrimStrings.php
+++ /dev/null
@@ -1,19 +0,0 @@
-
- */
- protected $except = [
- 'current_password',
- 'password',
- 'password_confirmation',
- ];
-}
diff --git a/app/Http/Middleware/TrustHosts.php b/app/Http/Middleware/TrustHosts.php
deleted file mode 100644
index c9c58bddce..0000000000
--- a/app/Http/Middleware/TrustHosts.php
+++ /dev/null
@@ -1,20 +0,0 @@
-
- */
- public function hosts(): array
- {
- return [
- $this->allSubdomainsOfApplicationUrl(),
- ];
- }
-}
diff --git a/app/Http/Middleware/TrustProxies.php b/app/Http/Middleware/TrustProxies.php
deleted file mode 100644
index 559dd2fc3f..0000000000
--- a/app/Http/Middleware/TrustProxies.php
+++ /dev/null
@@ -1,28 +0,0 @@
-|string|null
- */
- protected $proxies = '*';
-
- /**
- * The headers that should be used to detect proxies.
- *
- * @var int
- */
- protected $headers =
- Request::HEADER_X_FORWARDED_FOR |
- Request::HEADER_X_FORWARDED_HOST |
- Request::HEADER_X_FORWARDED_PORT |
- Request::HEADER_X_FORWARDED_PROTO |
- Request::HEADER_X_FORWARDED_AWS_ELB;
-}
diff --git a/app/Http/Middleware/ValidateSignature.php b/app/Http/Middleware/ValidateSignature.php
deleted file mode 100644
index 093bf64af8..0000000000
--- a/app/Http/Middleware/ValidateSignature.php
+++ /dev/null
@@ -1,22 +0,0 @@
-
- */
- protected $except = [
- // 'fbclid',
- // 'utm_campaign',
- // 'utm_content',
- // 'utm_medium',
- // 'utm_source',
- // 'utm_term',
- ];
-}
diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php
deleted file mode 100644
index 9e86521722..0000000000
--- a/app/Http/Middleware/VerifyCsrfToken.php
+++ /dev/null
@@ -1,17 +0,0 @@
-
- */
- protected $except = [
- //
- ];
-}
diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php
deleted file mode 100644
index 5301363785..0000000000
--- a/app/Jobs/ApplicationDeploymentJob.php
+++ /dev/null
@@ -1,2460 +0,0 @@
-application_deployment_queue_id];
- }
-
- public function __construct(public int $application_deployment_queue_id)
- {
- $this->onQueue('high');
-
- $this->application_deployment_queue = ApplicationDeploymentQueue::find($this->application_deployment_queue_id);
- $this->nixpacks_plan_json = collect([]);
-
- $this->application = Application::find($this->application_deployment_queue->application_id);
- $this->build_pack = data_get($this->application, 'build_pack');
- $this->build_args = collect([]);
-
- $this->deployment_uuid = $this->application_deployment_queue->deployment_uuid;
- $this->pull_request_id = $this->application_deployment_queue->pull_request_id;
- $this->commit = $this->application_deployment_queue->commit;
- $this->rollback = $this->application_deployment_queue->rollback;
- $this->disableBuildCache = $this->application->settings->disable_build_cache;
- $this->force_rebuild = $this->application_deployment_queue->force_rebuild;
- if ($this->disableBuildCache) {
- $this->force_rebuild = true;
- }
- $this->restart_only = $this->application_deployment_queue->restart_only;
- $this->restart_only = $this->restart_only && $this->application->build_pack !== 'dockerimage' && $this->application->build_pack !== 'dockerfile';
- $this->only_this_server = $this->application_deployment_queue->only_this_server;
-
- $this->git_type = data_get($this->application_deployment_queue, 'git_type');
-
- $source = data_get($this->application, 'source');
- if ($source) {
- $this->source = $source->getMorphClass()::where('id', $this->application->source->id)->first();
- }
- $this->server = Server::find($this->application_deployment_queue->server_id);
- $this->timeout = $this->server->settings->dynamic_timeout;
- $this->destination = $this->server->destinations()->where('id', $this->application_deployment_queue->destination_id)->first();
- $this->server = $this->mainServer = $this->destination->server;
- $this->serverUser = $this->server->user;
- $this->is_this_additional_server = $this->application->additional_servers()->wherePivot('server_id', $this->server->id)->count() > 0;
- $this->preserveRepository = $this->application->settings->is_preserve_repository_enabled;
-
- $this->basedir = $this->application->generateBaseDir($this->deployment_uuid);
- $this->workdir = "{$this->basedir}".rtrim($this->application->base_directory, '/');
- $this->configuration_dir = application_configuration_dir()."/{$this->application->uuid}";
- $this->is_debug_enabled = $this->application->settings->is_debug_enabled;
-
- $this->container_name = generateApplicationContainerName($this->application, $this->pull_request_id);
- if ($this->application->settings->custom_internal_name && ! $this->application->settings->is_consistent_container_name_enabled) {
- if ($this->pull_request_id === 0) {
- $this->container_name = $this->application->settings->custom_internal_name;
- } else {
- $this->container_name = "{$this->application->settings->custom_internal_name}-pr-{$this->pull_request_id}";
- }
- }
-
- $this->saved_outputs = collect();
-
- // Set preview fqdn
- if ($this->pull_request_id !== 0) {
- $this->preview = $this->application->generate_preview_fqdn($this->pull_request_id);
- if ($this->application->is_github_based()) {
- ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->preview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::IN_PROGRESS);
- }
- if ($this->application->build_pack === 'dockerfile') {
- if (data_get($this->application, 'dockerfile_location')) {
- $this->dockerfile_location = $this->application->dockerfile_location;
- }
- }
- }
- }
-
- public function handle(): void
- {
- $this->application_deployment_queue->update([
- 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
- 'horizon_job_worker' => gethostname(),
- ]);
- if ($this->server->isFunctional() === false) {
- $this->application_deployment_queue->addLogEntry('Server is not functional.');
- $this->fail('Server is not functional.');
-
- return;
- }
- try {
- // Make sure the private key is stored in the filesystem
- $this->server->privateKey->storeInFileSystem();
-
- // Generate custom host<->ip mapping
- $allContainers = instant_remote_process(["docker network inspect {$this->destination->network} -f '{{json .Containers}}' "], $this->server);
-
- if (! is_null($allContainers)) {
- $allContainers = format_docker_command_output_to_json($allContainers);
- $ips = collect([]);
- if (count($allContainers) > 0) {
- $allContainers = $allContainers[0];
- $allContainers = collect($allContainers)->sort()->values();
- foreach ($allContainers as $container) {
- $containerName = data_get($container, 'Name');
- if ($containerName === 'coolify-proxy') {
- continue;
- }
- if (preg_match('/-(\d{12})/', $containerName)) {
- continue;
- }
- $containerIp = data_get($container, 'IPv4Address');
- if ($containerName && $containerIp) {
- $containerIp = str($containerIp)->before('/');
- $ips->put($containerName, $containerIp->value());
- }
- }
- }
- $this->addHosts = $ips->map(function ($ip, $name) {
- return "--add-host $name:$ip";
- })->implode(' ');
- }
-
- if ($this->application->dockerfile_target_build) {
- $this->buildTarget = " --target {$this->application->dockerfile_target_build} ";
- }
-
- // Check custom port
- ['repository' => $this->customRepository, 'port' => $this->customPort] = $this->application->customRepository();
-
- if (data_get($this->application, 'settings.is_build_server_enabled')) {
- $teamId = data_get($this->application, 'environment.project.team.id');
- $buildServers = Server::buildServers($teamId)->get();
- if ($buildServers->count() === 0) {
- $this->application_deployment_queue->addLogEntry('No suitable build server found. Using the deployment server.');
- $this->build_server = $this->server;
- $this->original_server = $this->server;
- } else {
- $this->build_server = $buildServers->random();
- $this->application_deployment_queue->build_server_id = $this->build_server->id;
- $this->application_deployment_queue->addLogEntry("Found a suitable build server ({$this->build_server->name}).");
- $this->original_server = $this->server;
- $this->use_build_server = true;
- }
- } else {
- // Set build server & original_server to the same as deployment server
- $this->build_server = $this->server;
- $this->original_server = $this->server;
- }
- $this->decide_what_to_do();
- } catch (Exception $e) {
- if ($this->pull_request_id !== 0 && $this->application->is_github_based()) {
- ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->preview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::ERROR);
- }
- $this->fail($e);
- throw $e;
- } finally {
- $this->application_deployment_queue->update([
- 'finished_at' => Carbon::now()->toImmutable(),
- ]);
-
- if ($this->use_build_server) {
- $this->server = $this->build_server;
- } else {
- $this->write_deployment_configurations();
- }
- $this->execute_remote_command(
- [
- "docker rm -f {$this->deployment_uuid} >/dev/null 2>&1",
- 'hidden' => true,
- 'ignore_errors' => true,
- ]
- );
-
- ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
- }
- }
-
- private function decide_what_to_do()
- {
- if ($this->restart_only) {
- $this->just_restart();
-
- return;
- } elseif ($this->pull_request_id !== 0) {
- $this->deploy_pull_request();
- } elseif ($this->application->dockerfile) {
- $this->deploy_simple_dockerfile();
- } elseif ($this->application->build_pack === 'dockercompose') {
- $this->deploy_docker_compose_buildpack();
- } elseif ($this->application->build_pack === 'dockerimage') {
- $this->deploy_dockerimage_buildpack();
- } elseif ($this->application->build_pack === 'dockerfile') {
- $this->deploy_dockerfile_buildpack();
- } elseif ($this->application->build_pack === 'static') {
- $this->deploy_static_buildpack();
- } else {
- $this->deploy_nixpacks_buildpack();
- }
- $this->post_deployment();
- }
-
- private function post_deployment()
- {
- if ($this->server->isProxyShouldRun()) {
- GetContainersStatus::dispatch($this->server);
- }
- $this->next(ApplicationDeploymentStatus::FINISHED->value);
- if ($this->pull_request_id !== 0) {
- if ($this->application->is_github_based()) {
- ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->preview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::FINISHED);
- }
- }
- $this->run_post_deployment_command();
- $this->application->isConfigurationChanged(true);
- }
-
- private function deploy_simple_dockerfile()
- {
- if ($this->use_build_server) {
- $this->server = $this->build_server;
- }
- $dockerfile_base64 = base64_encode($this->application->dockerfile);
- $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->application->name} to {$this->server->name}.");
- $this->prepare_builder_image();
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "echo '$dockerfile_base64' | base64 -d | tee {$this->workdir}{$this->dockerfile_location} > /dev/null"),
- ],
- );
- $this->generate_image_names();
- $this->generate_compose_file();
- $this->generate_build_env_variables();
- $this->add_build_env_variables_to_dockerfile();
- $this->build_image();
- $this->push_to_docker_registry();
- $this->rolling_update();
- }
-
- private function deploy_dockerimage_buildpack()
- {
- $this->dockerImage = $this->application->docker_registry_image_name;
- if (str($this->application->docker_registry_image_tag)->isEmpty()) {
- $this->dockerImageTag = 'latest';
- } else {
- $this->dockerImageTag = $this->application->docker_registry_image_tag;
- }
- $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}.");
- $this->generate_image_names();
- $this->prepare_builder_image();
- $this->generate_compose_file();
- $this->rolling_update();
- }
-
- private function deploy_docker_compose_buildpack()
- {
- if (data_get($this->application, 'docker_compose_location')) {
- $this->docker_compose_location = $this->application->docker_compose_location;
- }
- if (data_get($this->application, 'docker_compose_custom_start_command')) {
- $this->docker_compose_custom_start_command = $this->application->docker_compose_custom_start_command;
- if (! str($this->docker_compose_custom_start_command)->contains('--project-directory')) {
- $this->docker_compose_custom_start_command = str($this->docker_compose_custom_start_command)->replaceFirst('compose', 'compose --project-directory '.$this->workdir)->value();
- }
- }
- if (data_get($this->application, 'docker_compose_custom_build_command')) {
- $this->docker_compose_custom_build_command = $this->application->docker_compose_custom_build_command;
- if (! str($this->docker_compose_custom_build_command)->contains('--project-directory')) {
- $this->docker_compose_custom_build_command = str($this->docker_compose_custom_build_command)->replaceFirst('compose', 'compose --project-directory '.$this->workdir)->value();
- }
- }
- if ($this->pull_request_id === 0) {
- $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->application->name} to {$this->server->name}.");
- } else {
- $this->application_deployment_queue->addLogEntry("Starting pull request (#{$this->pull_request_id}) deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
- }
- $this->prepare_builder_image();
- $this->check_git_if_build_needed();
- $this->clone_repository();
- if ($this->preserveRepository) {
- foreach ($this->application->fileStorages as $fileStorage) {
- $path = $fileStorage->fs_path;
- $saveName = 'file_stat_'.$fileStorage->id;
- $realPathInGit = str($path)->replace($this->application->workdir(), $this->workdir)->value();
- // check if the file is a directory or a file inside the repository
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "stat -c '%F' {$realPathInGit}"), 'hidden' => true, 'ignore_errors' => true, 'save' => $saveName]
- );
- if ($this->saved_outputs->has($saveName)) {
- $fileStat = $this->saved_outputs->get($saveName);
- if ($fileStat->value() === 'directory' && ! $fileStorage->is_directory) {
- $fileStorage->is_directory = true;
- $fileStorage->content = null;
- $fileStorage->save();
- $fileStorage->deleteStorageOnServer();
- $fileStorage->saveStorageOnServer();
- } elseif ($fileStat->value() === 'regular file' && $fileStorage->is_directory) {
- $fileStorage->is_directory = false;
- $fileStorage->is_based_on_git = true;
- $fileStorage->save();
- $fileStorage->deleteStorageOnServer();
- $fileStorage->saveStorageOnServer();
- }
- }
- }
- }
- $this->generate_image_names();
- $this->cleanup_git();
- $this->application->loadComposeFile(isInit: false);
- if ($this->application->settings->is_raw_compose_deployment_enabled) {
- $this->application->oldRawParser();
- $yaml = $composeFile = $this->application->docker_compose_raw;
- $this->save_environment_variables();
- } else {
- $composeFile = $this->application->parse(pull_request_id: $this->pull_request_id, preview_id: data_get($this->preview, 'id'));
- $this->save_environment_variables();
- if (! is_null($this->env_filename)) {
- $services = collect(data_get($composeFile, 'services', []));
- $services = $services->map(function ($service, $name) {
- $service['env_file'] = [$this->env_filename];
-
- return $service;
- });
- $composeFile['services'] = $services->toArray();
- }
- if (is_null($composeFile)) {
- $this->application_deployment_queue->addLogEntry('Failed to parse docker-compose file.');
- $this->fail('Failed to parse docker-compose file.');
-
- return;
- }
- $yaml = Yaml::dump(convertToArray($composeFile), 10);
- }
- $this->docker_compose_base64 = base64_encode($yaml);
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d | tee {$this->workdir}{$this->docker_compose_location} > /dev/null"),
- 'hidden' => true,
- ]);
- // Build new container to limit downtime.
- $this->application_deployment_queue->addLogEntry('Pulling & building required images.');
-
- if ($this->docker_compose_custom_build_command) {
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_build_command}"), 'hidden' => true],
- );
- } else {
- $command = "{$this->coolify_variables} docker compose";
- if ($this->env_filename) {
- $command .= " --env-file {$this->workdir}/{$this->env_filename}";
- }
- $command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build --pull";
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
- );
- }
-
- $this->stop_running_container(force: true);
- $this->application_deployment_queue->addLogEntry('Starting new application.');
- $networkId = $this->application->uuid;
- if ($this->pull_request_id !== 0) {
- $networkId = "{$this->application->uuid}-{$this->pull_request_id}";
- }
- if ($this->server->isSwarm()) {
- // TODO
- } else {
- $this->execute_remote_command([
- "docker network inspect '{$networkId}' >/dev/null 2>&1 || docker network create --attachable '{$networkId}' >/dev/null || true",
- 'hidden' => true,
- 'ignore_errors' => true,
- ], [
- "docker network connect {$networkId} coolify-proxy >/dev/null 2>&1 || true",
- 'hidden' => true,
- 'ignore_errors' => true,
- ]);
- }
-
- // Start compose file
- $server_workdir = $this->application->workdir();
- if ($this->application->settings->is_raw_compose_deployment_enabled) {
- if ($this->docker_compose_custom_start_command) {
- $this->write_deployment_configurations();
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "cd {$this->workdir} && {$this->docker_compose_custom_start_command}"), 'hidden' => true],
- );
- } else {
- $this->write_deployment_configurations();
- $this->docker_compose_location = '/docker-compose.yaml';
-
- $command = "{$this->coolify_variables} docker compose";
- if ($this->env_filename) {
- $command .= " --env-file {$server_workdir}/{$this->env_filename}";
- }
- $command .= " --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d";
- $this->execute_remote_command(
- ['command' => $command, 'hidden' => true],
- );
- }
- } else {
- if ($this->docker_compose_custom_start_command) {
- $this->write_deployment_configurations();
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_start_command}"), 'hidden' => true],
- );
- } else {
- $command = "{$this->coolify_variables} docker compose";
- if ($this->preserveRepository) {
- if ($this->env_filename) {
- $command .= " --env-file {$server_workdir}/{$this->env_filename}";
- }
- $command .= " --project-name {$this->application->uuid} --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d";
- $this->write_deployment_configurations();
-
- $this->execute_remote_command(
- ['command' => $command, 'hidden' => true],
- );
- } else {
- if ($this->env_filename) {
- $command .= " --env-file {$this->workdir}/{$this->env_filename}";
- }
- $command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
- );
- $this->write_deployment_configurations();
- }
- }
- }
-
- $this->application_deployment_queue->addLogEntry('New container started.');
- }
-
- private function deploy_dockerfile_buildpack()
- {
- $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
- if ($this->use_build_server) {
- $this->server = $this->build_server;
- }
- if (data_get($this->application, 'dockerfile_location')) {
- $this->dockerfile_location = $this->application->dockerfile_location;
- }
- $this->prepare_builder_image();
- $this->check_git_if_build_needed();
- $this->generate_image_names();
- $this->clone_repository();
- if (! $this->force_rebuild) {
- $this->check_image_locally_or_remotely();
- if ($this->should_skip_build()) {
- return;
- }
- }
- $this->cleanup_git();
- $this->generate_compose_file();
- $this->generate_build_env_variables();
- $this->add_build_env_variables_to_dockerfile();
- $this->build_image();
- $this->push_to_docker_registry();
- $this->rolling_update();
- }
-
- private function deploy_nixpacks_buildpack()
- {
- if ($this->use_build_server) {
- $this->server = $this->build_server;
- }
- $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
- $this->prepare_builder_image();
- $this->check_git_if_build_needed();
- $this->generate_image_names();
- if (! $this->force_rebuild) {
- $this->check_image_locally_or_remotely();
- if ($this->should_skip_build()) {
- return;
- }
- }
- $this->clone_repository();
- $this->cleanup_git();
- $this->generate_nixpacks_confs();
- $this->generate_compose_file();
- $this->generate_build_env_variables();
- $this->build_image();
- $this->push_to_docker_registry();
- $this->rolling_update();
- }
-
- private function deploy_static_buildpack()
- {
- if ($this->use_build_server) {
- $this->server = $this->build_server;
- }
- $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
- $this->prepare_builder_image();
- $this->check_git_if_build_needed();
- $this->generate_image_names();
- if (! $this->force_rebuild) {
- $this->check_image_locally_or_remotely();
- if ($this->should_skip_build()) {
- return;
- }
- }
- $this->clone_repository();
- $this->cleanup_git();
- $this->generate_compose_file();
- $this->build_image();
- $this->push_to_docker_registry();
- $this->rolling_update();
- }
-
- private function write_deployment_configurations()
- {
- if ($this->preserveRepository) {
- if ($this->use_build_server) {
- $this->server = $this->original_server;
- }
- if (str($this->configuration_dir)->isNotEmpty()) {
- $this->execute_remote_command(
- [
- "mkdir -p $this->configuration_dir",
- ],
- [
- "docker cp {$this->deployment_uuid}:{$this->workdir}/. {$this->configuration_dir}",
- ],
- );
- }
- foreach ($this->application->fileStorages as $fileStorage) {
- if (! $fileStorage->is_based_on_git && ! $fileStorage->is_directory) {
- $fileStorage->saveStorageOnServer();
- }
- }
- if ($this->use_build_server) {
- $this->server = $this->build_server;
- }
- }
- if (isset($this->docker_compose_base64)) {
- if ($this->use_build_server) {
- $this->server = $this->original_server;
- }
- $readme = generate_readme_file($this->application->name, $this->application_deployment_queue->updated_at);
-
- $mainDir = $this->configuration_dir;
- if ($this->application->settings->is_raw_compose_deployment_enabled) {
- $mainDir = $this->application->workdir();
- }
- if ($this->pull_request_id === 0) {
- $composeFileName = "$mainDir/docker-compose.yaml";
- } else {
- $composeFileName = "$mainDir/docker-compose-pr-{$this->pull_request_id}.yaml";
- $this->docker_compose_location = "/docker-compose-pr-{$this->pull_request_id}.yaml";
- }
- $this->execute_remote_command(
- [
- "mkdir -p $mainDir",
- ],
- [
- "echo '{$this->docker_compose_base64}' | base64 -d | tee $composeFileName > /dev/null",
- ],
- [
- "echo '{$readme}' > $mainDir/README.md",
- ]
- );
- if ($this->use_build_server) {
- $this->server = $this->build_server;
- }
- }
- }
-
- private function push_to_docker_registry()
- {
- $forceFail = true;
- if (str($this->application->docker_registry_image_name)->isEmpty()) {
- return;
- }
- if ($this->restart_only) {
- return;
- }
- if ($this->application->build_pack === 'dockerimage') {
- return;
- }
- if ($this->use_build_server) {
- $forceFail = true;
- }
- if ($this->server->isSwarm() && $this->build_pack !== 'dockerimage') {
- $forceFail = true;
- }
- if ($this->application->additional_servers->count() > 0) {
- $forceFail = true;
- }
- if ($this->is_this_additional_server) {
- return;
- }
- try {
- instant_remote_process(["docker images --format '{{json .}}' {$this->production_image_name}"], $this->server);
- $this->application_deployment_queue->addLogEntry('----------------------------------------');
- $this->application_deployment_queue->addLogEntry("Pushing image to docker registry ({$this->production_image_name}).");
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "docker push {$this->production_image_name}"),
- 'hidden' => true,
- ],
- );
- if ($this->application->docker_registry_image_tag) {
- // Tag image with docker_registry_image_tag
- $this->application_deployment_queue->addLogEntry("Tagging and pushing image with {$this->application->docker_registry_image_tag} tag.");
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "docker tag {$this->production_image_name} {$this->application->docker_registry_image_name}:{$this->application->docker_registry_image_tag}"),
- 'ignore_errors' => true,
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, "docker push {$this->application->docker_registry_image_name}:{$this->application->docker_registry_image_tag}"),
- 'ignore_errors' => true,
- 'hidden' => true,
- ],
- );
- }
- } catch (Exception $e) {
- $this->application_deployment_queue->addLogEntry('Failed to push image to docker registry. Please check debug logs for more information.');
- if ($forceFail) {
- throw new RuntimeException($e->getMessage(), 69420);
- }
- }
- }
-
- private function generate_image_names()
- {
- if ($this->application->dockerfile) {
- if ($this->application->docker_registry_image_name) {
- $this->build_image_name = "{$this->application->docker_registry_image_name}:build";
- $this->production_image_name = "{$this->application->docker_registry_image_name}:latest";
- } else {
- $this->build_image_name = "{$this->application->uuid}:build";
- $this->production_image_name = "{$this->application->uuid}:latest";
- }
- } elseif ($this->application->build_pack === 'dockerimage') {
- $this->production_image_name = "{$this->dockerImage}:{$this->dockerImageTag}";
- } elseif ($this->pull_request_id !== 0) {
- if ($this->application->docker_registry_image_name) {
- $this->build_image_name = "{$this->application->docker_registry_image_name}:pr-{$this->pull_request_id}-build";
- $this->production_image_name = "{$this->application->docker_registry_image_name}:pr-{$this->pull_request_id}";
- } else {
- $this->build_image_name = "{$this->application->uuid}:pr-{$this->pull_request_id}-build";
- $this->production_image_name = "{$this->application->uuid}:pr-{$this->pull_request_id}";
- }
- } else {
- $this->dockerImageTag = str($this->commit)->substr(0, 128);
- // if ($this->application->docker_registry_image_tag) {
- // $this->dockerImageTag = $this->application->docker_registry_image_tag;
- // }
- if ($this->application->docker_registry_image_name) {
- $this->build_image_name = "{$this->application->docker_registry_image_name}:{$this->dockerImageTag}-build";
- $this->production_image_name = "{$this->application->docker_registry_image_name}:{$this->dockerImageTag}";
- } else {
- $this->build_image_name = "{$this->application->uuid}:{$this->dockerImageTag}-build";
- $this->production_image_name = "{$this->application->uuid}:{$this->dockerImageTag}";
- }
- }
- }
-
- private function just_restart()
- {
- $this->application_deployment_queue->addLogEntry("Restarting {$this->customRepository}:{$this->application->git_branch} on {$this->server->name}.");
- $this->prepare_builder_image();
- $this->check_git_if_build_needed();
- $this->generate_image_names();
- $this->check_image_locally_or_remotely();
- $this->should_skip_build();
- $this->next(ApplicationDeploymentStatus::FINISHED->value);
- }
-
- private function should_skip_build()
- {
- if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
- if ($this->is_this_additional_server) {
- $this->application_deployment_queue->addLogEntry("Image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
- $this->generate_compose_file();
- $this->push_to_docker_registry();
- $this->rolling_update();
- if ($this->restart_only) {
- $this->post_deployment();
- }
-
- return true;
- }
- if (! $this->application->isConfigurationChanged()) {
- $this->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
- $this->generate_compose_file();
- $this->push_to_docker_registry();
- $this->rolling_update();
-
- return true;
- } else {
- $this->application_deployment_queue->addLogEntry('Configuration changed. Rebuilding image.');
- }
- } else {
- $this->application_deployment_queue->addLogEntry("Image not found ({$this->production_image_name}). Building new image.");
- }
- if ($this->restart_only) {
- $this->restart_only = false;
- $this->decide_what_to_do();
- }
-
- return false;
- }
-
- private function check_image_locally_or_remotely()
- {
- $this->execute_remote_command([
- "docker images -q {$this->production_image_name} 2>/dev/null",
- 'hidden' => true,
- 'save' => 'local_image_found',
- ]);
- if (str($this->saved_outputs->get('local_image_found'))->isEmpty() && $this->application->docker_registry_image_name) {
- $this->execute_remote_command([
- "docker pull {$this->production_image_name} 2>/dev/null",
- 'ignore_errors' => true,
- 'hidden' => true,
- ]);
- $this->execute_remote_command([
- "docker images -q {$this->production_image_name} 2>/dev/null",
- 'hidden' => true,
- 'save' => 'local_image_found',
- ]);
- }
- }
-
- private function save_environment_variables()
- {
- $envs = collect([]);
- $local_branch = $this->branch;
- if ($this->pull_request_id !== 0) {
- $local_branch = "pull/{$this->pull_request_id}/head";
- }
- $sort = $this->application->settings->is_env_sorting_enabled;
- if ($sort) {
- $sorted_environment_variables = $this->application->environment_variables->sortBy('key');
- $sorted_environment_variables_preview = $this->application->environment_variables_preview->sortBy('key');
- } else {
- $sorted_environment_variables = $this->application->environment_variables->sortBy('id');
- $sorted_environment_variables_preview = $this->application->environment_variables_preview->sortBy('id');
- }
- $ports = $this->application->main_port();
- if ($this->pull_request_id !== 0) {
- $this->env_filename = ".env-pr-$this->pull_request_id";
- // Add SOURCE_COMMIT if not exists
- if ($this->application->environment_variables_preview->where('key', 'SOURCE_COMMIT')->isEmpty()) {
- if (! is_null($this->commit)) {
- $envs->push("SOURCE_COMMIT={$this->commit}");
- } else {
- $envs->push('SOURCE_COMMIT=unknown');
- }
- }
- if ($this->application->environment_variables_preview->where('key', 'COOLIFY_FQDN')->isEmpty()) {
- $envs->push("COOLIFY_FQDN={$this->preview->fqdn}");
- $envs->push("COOLIFY_DOMAIN_URL={$this->preview->fqdn}");
- }
- if ($this->application->environment_variables_preview->where('key', 'COOLIFY_URL')->isEmpty()) {
- $url = str($this->preview->fqdn)->replace('http://', '')->replace('https://', '');
- $envs->push("COOLIFY_URL={$url}");
- $envs->push("COOLIFY_DOMAIN_FQDN={$url}");
- }
- if ($this->application->build_pack !== 'dockercompose' || $this->application->compose_parsing_version === '1' || $this->application->compose_parsing_version === '2') {
- if ($this->application->environment_variables_preview->where('key', 'COOLIFY_BRANCH')->isEmpty()) {
- $envs->push("COOLIFY_BRANCH=\"{$local_branch}\"");
- }
- if ($this->application->environment_variables_preview->where('key', 'COOLIFY_RESOURCE_UUID')->isEmpty()) {
- $envs->push("COOLIFY_RESOURCE_UUID={$this->application->uuid}");
- }
- if ($this->application->environment_variables_preview->where('key', 'COOLIFY_CONTAINER_NAME')->isEmpty()) {
- $envs->push("COOLIFY_CONTAINER_NAME={$this->container_name}");
- }
- }
-
- add_coolify_default_environment_variables($this->application, $envs, $this->application->environment_variables_preview);
-
- foreach ($sorted_environment_variables_preview as $env) {
- $real_value = $env->real_value;
- if ($env->version === '4.0.0-beta.239') {
- $real_value = $env->real_value;
- } else {
- if ($env->is_literal || $env->is_multiline) {
- $real_value = '\''.$real_value.'\'';
- } else {
- $real_value = escapeEnvVariables($env->real_value);
- }
- }
- $envs->push($env->key.'='.$real_value);
- }
- // Add PORT if not exists, use the first port as default
- if ($this->build_pack !== 'dockercompose') {
- if ($this->application->environment_variables_preview->where('key', 'PORT')->isEmpty()) {
- $envs->push("PORT={$ports[0]}");
- }
- }
- // Add HOST if not exists
- if ($this->application->environment_variables_preview->where('key', 'HOST')->isEmpty()) {
- $envs->push('HOST=0.0.0.0');
- }
- } else {
- $this->env_filename = '.env';
- // Add SOURCE_COMMIT if not exists
- if ($this->application->environment_variables->where('key', 'SOURCE_COMMIT')->isEmpty()) {
- if (! is_null($this->commit)) {
- $envs->push("SOURCE_COMMIT={$this->commit}");
- } else {
- $envs->push('SOURCE_COMMIT=unknown');
- }
- }
- if ($this->application->environment_variables->where('key', 'COOLIFY_FQDN')->isEmpty()) {
- if ((int) $this->application->compose_parsing_version >= 3) {
- $envs->push("COOLIFY_URL={$this->application->fqdn}");
- } else {
- $envs->push("COOLIFY_FQDN={$this->application->fqdn}");
- }
- }
- if ($this->application->environment_variables->where('key', 'COOLIFY_URL')->isEmpty()) {
- $url = str($this->application->fqdn)->replace('http://', '')->replace('https://', '');
- if ((int) $this->application->compose_parsing_version >= 3) {
- $envs->push("COOLIFY_FQDN={$url}");
- } else {
- $envs->push("COOLIFY_URL={$url}");
- }
- }
- if ($this->application->build_pack !== 'dockercompose' || $this->application->compose_parsing_version === '1' || $this->application->compose_parsing_version === '2') {
- if ($this->application->environment_variables->where('key', 'COOLIFY_BRANCH')->isEmpty()) {
- $envs->push("COOLIFY_BRANCH=\"{$local_branch}\"");
- }
- if ($this->application->environment_variables->where('key', 'COOLIFY_RESOURCE_UUID')->isEmpty()) {
- $envs->push("COOLIFY_RESOURCE_UUID={$this->application->uuid}");
- }
- if ($this->application->environment_variables->where('key', 'COOLIFY_CONTAINER_NAME')->isEmpty()) {
- $envs->push("COOLIFY_CONTAINER_NAME={$this->container_name}");
- }
- }
-
- add_coolify_default_environment_variables($this->application, $envs, $this->application->environment_variables);
-
- foreach ($sorted_environment_variables as $env) {
- $real_value = $env->real_value;
- if ($env->version === '4.0.0-beta.239') {
- $real_value = $env->real_value;
- } else {
- if ($env->is_literal || $env->is_multiline) {
- $real_value = '\''.$real_value.'\'';
- } else {
- $real_value = escapeEnvVariables($env->real_value);
- }
- }
- $envs->push($env->key.'='.$real_value);
- }
- // Add PORT if not exists, use the first port as default
- if ($this->build_pack !== 'dockercompose') {
- if ($this->application->environment_variables->where('key', 'PORT')->isEmpty()) {
- $envs->push("PORT={$ports[0]}");
- }
- }
- // Add HOST if not exists
- if ($this->application->environment_variables->where('key', 'HOST')->isEmpty()) {
- $envs->push('HOST=0.0.0.0');
- }
- }
- if ($envs->isEmpty()) {
- $this->env_filename = null;
- if ($this->use_build_server) {
- $this->server = $this->original_server;
- $this->execute_remote_command(
- [
- 'command' => "rm -f $this->configuration_dir/{$this->env_filename}",
- 'hidden' => true,
- 'ignore_errors' => true,
- ]
- );
- $this->server = $this->build_server;
- $this->execute_remote_command(
- [
- 'command' => "rm -f $this->configuration_dir/{$this->env_filename}",
- 'hidden' => true,
- 'ignore_errors' => true,
- ]
- );
- } else {
- $this->execute_remote_command(
- [
- 'command' => "rm -f $this->configuration_dir/{$this->env_filename}",
- 'hidden' => true,
- 'ignore_errors' => true,
- ]
- );
- }
- } else {
- $envs_base64 = base64_encode($envs->implode("\n"));
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "echo '$envs_base64' | base64 -d | tee $this->workdir/{$this->env_filename} > /dev/null"),
- ],
-
- );
- if ($this->use_build_server) {
- $this->server = $this->original_server;
- $this->execute_remote_command(
- [
- "echo '$envs_base64' | base64 -d | tee $this->configuration_dir/{$this->env_filename} > /dev/null",
- ]
- );
- $this->server = $this->build_server;
- } else {
- $this->execute_remote_command(
- [
- "echo '$envs_base64' | base64 -d | tee $this->configuration_dir/{$this->env_filename} > /dev/null",
- ]
- );
- }
- }
- $this->environment_variables = $envs;
- }
-
- private function elixir_finetunes()
- {
- if ($this->pull_request_id === 0) {
- $envType = 'environment_variables';
- } else {
- $envType = 'environment_variables_preview';
- }
- $mix_env = $this->application->{$envType}->where('key', 'MIX_ENV')->first();
- if ($mix_env) {
- if ($mix_env->is_build_time === false) {
- $this->application_deployment_queue->addLogEntry('MIX_ENV environment variable is not set as build time.', type: 'error');
- $this->application_deployment_queue->addLogEntry('Please set MIX_ENV environment variable to be build time variable if you facing any issues with the deployment.', type: 'error');
- }
- } else {
- $this->application_deployment_queue->addLogEntry('MIX_ENV environment variable not found.', type: 'error');
- $this->application_deployment_queue->addLogEntry('Please add MIX_ENV environment variable and set it to be build time variable if you facing any issues with the deployment.', type: 'error');
- }
- $secret_key_base = $this->application->{$envType}->where('key', 'SECRET_KEY_BASE')->first();
- if ($secret_key_base) {
- if ($secret_key_base->is_build_time === false) {
- $this->application_deployment_queue->addLogEntry('SECRET_KEY_BASE environment variable is not set as build time.', type: 'error');
- $this->application_deployment_queue->addLogEntry('Please set SECRET_KEY_BASE environment variable to be build time variable if you facing any issues with the deployment.', type: 'error');
- }
- } else {
- $this->application_deployment_queue->addLogEntry('SECRET_KEY_BASE environment variable not found.', type: 'error');
- $this->application_deployment_queue->addLogEntry('Please add SECRET_KEY_BASE environment variable and set it to be build time variable if you facing any issues with the deployment.', type: 'error');
- }
- $database_url = $this->application->{$envType}->where('key', 'DATABASE_URL')->first();
- if ($database_url) {
- if ($database_url->is_build_time === false) {
- $this->application_deployment_queue->addLogEntry('DATABASE_URL environment variable is not set as build time.', type: 'error');
- $this->application_deployment_queue->addLogEntry('Please set DATABASE_URL environment variable to be build time variable if you facing any issues with the deployment.', type: 'error');
- }
- } else {
- $this->application_deployment_queue->addLogEntry('DATABASE_URL environment variable not found.', type: 'error');
- $this->application_deployment_queue->addLogEntry('Please add DATABASE_URL environment variable and set it to be build time variable if you facing any issues with the deployment.', type: 'error');
- }
- }
-
- private function laravel_finetunes()
- {
- if ($this->pull_request_id === 0) {
- $envType = 'environment_variables';
- } else {
- $envType = 'environment_variables_preview';
- }
- $nixpacks_php_fallback_path = $this->application->{$envType}->where('key', 'NIXPACKS_PHP_FALLBACK_PATH')->first();
- $nixpacks_php_root_dir = $this->application->{$envType}->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
-
- if (! $nixpacks_php_fallback_path) {
- $nixpacks_php_fallback_path = new EnvironmentVariable;
- $nixpacks_php_fallback_path->key = 'NIXPACKS_PHP_FALLBACK_PATH';
- $nixpacks_php_fallback_path->value = '/index.php';
- $nixpacks_php_fallback_path->is_build_time = false;
- $nixpacks_php_fallback_path->resourceable_id = $this->application->id;
- $nixpacks_php_fallback_path->resourceable_type = 'App\Models\Application';
- $nixpacks_php_fallback_path->save();
- }
- if (! $nixpacks_php_root_dir) {
- $nixpacks_php_root_dir = new EnvironmentVariable;
- $nixpacks_php_root_dir->key = 'NIXPACKS_PHP_ROOT_DIR';
- $nixpacks_php_root_dir->value = '/app/public';
- $nixpacks_php_root_dir->is_build_time = false;
- $nixpacks_php_root_dir->resourceable_id = $this->application->id;
- $nixpacks_php_root_dir->resourceable_type = 'App\Models\Application';
- $nixpacks_php_root_dir->save();
- }
-
- return [$nixpacks_php_fallback_path, $nixpacks_php_root_dir];
- }
-
- private function rolling_update()
- {
- if ($this->server->isSwarm()) {
- $this->application_deployment_queue->addLogEntry('Rolling update started.');
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "docker stack deploy --detach=true --with-registry-auth -c {$this->workdir}{$this->docker_compose_location} {$this->application->uuid}"),
- ],
- );
- $this->application_deployment_queue->addLogEntry('Rolling update completed.');
- } else {
- if ($this->use_build_server) {
- $this->write_deployment_configurations();
- $this->server = $this->original_server;
- }
- if (count($this->application->ports_mappings_array) > 0 || (bool) $this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty() || $this->pull_request_id !== 0 || str($this->application->custom_docker_run_options)->contains('--ip') || str($this->application->custom_docker_run_options)->contains('--ip6')) {
- $this->application_deployment_queue->addLogEntry('----------------------------------------');
- if (count($this->application->ports_mappings_array) > 0) {
- $this->application_deployment_queue->addLogEntry('Application has ports mapped to the host system, rolling update is not supported.');
- }
- if ((bool) $this->application->settings->is_consistent_container_name_enabled) {
- $this->application_deployment_queue->addLogEntry('Consistent container name feature enabled, rolling update is not supported.');
- }
- if (str($this->application->settings->custom_internal_name)->isNotEmpty()) {
- $this->application_deployment_queue->addLogEntry('Custom internal name is set, rolling update is not supported.');
- }
- if ($this->pull_request_id !== 0) {
- $this->application->settings->is_consistent_container_name_enabled = true;
- $this->application_deployment_queue->addLogEntry('Pull request deployment, rolling update is not supported.');
- }
- if (str($this->application->custom_docker_run_options)->contains('--ip') || str($this->application->custom_docker_run_options)->contains('--ip6')) {
- $this->application_deployment_queue->addLogEntry('Custom IP address is set, rolling update is not supported.');
- }
- $this->stop_running_container(force: true);
- $this->start_by_compose_file();
- } else {
- $this->application_deployment_queue->addLogEntry('----------------------------------------');
- $this->application_deployment_queue->addLogEntry('Rolling update started.');
- $this->start_by_compose_file();
- $this->health_check();
- $this->stop_running_container();
- $this->application_deployment_queue->addLogEntry('Rolling update completed.');
- }
- }
- }
-
- private function health_check()
- {
- if ($this->server->isSwarm()) {
- // Implement healthcheck for swarm
- } else {
- if ($this->application->isHealthcheckDisabled() && $this->application->custom_healthcheck_found === false) {
- $this->newVersionIsHealthy = true;
-
- return;
- }
- if ($this->application->custom_healthcheck_found) {
- $this->application_deployment_queue->addLogEntry('Custom healthcheck found, skipping default healthcheck.');
- }
- if ($this->container_name) {
- $counter = 1;
- $this->application_deployment_queue->addLogEntry('Waiting for healthcheck to pass on the new container.');
- if ($this->full_healthcheck_url) {
- $this->application_deployment_queue->addLogEntry("Healthcheck URL (inside the container): {$this->full_healthcheck_url}");
- }
- $this->application_deployment_queue->addLogEntry("Waiting for the start period ({$this->application->health_check_start_period} seconds) before starting healthcheck.");
- $sleeptime = 0;
- while ($sleeptime < $this->application->health_check_start_period) {
- Sleep::for(1)->seconds();
- $sleeptime++;
- }
- while ($counter <= $this->application->health_check_retries) {
- $this->execute_remote_command(
- [
- "docker inspect --format='{{json .State.Health.Status}}' {$this->container_name}",
- 'hidden' => true,
- 'save' => 'health_check',
- 'append' => false,
- ],
- [
- "docker inspect --format='{{json .State.Health.Log}}' {$this->container_name}",
- 'hidden' => true,
- 'save' => 'health_check_logs',
- 'append' => false,
- ],
- );
- $this->application_deployment_queue->addLogEntry("Attempt {$counter} of {$this->application->health_check_retries} | Healthcheck status: {$this->saved_outputs->get('health_check')}");
- $health_check_logs = data_get(collect(json_decode($this->saved_outputs->get('health_check_logs')))->last(), 'Output', '(no logs)');
- if (empty($health_check_logs)) {
- $health_check_logs = '(no logs)';
- }
- $health_check_return_code = data_get(collect(json_decode($this->saved_outputs->get('health_check_logs')))->last(), 'ExitCode', '(no return code)');
- if ($health_check_logs !== '(no logs)' || $health_check_return_code !== '(no return code)') {
- $this->application_deployment_queue->addLogEntry("Healthcheck logs: {$health_check_logs} | Return code: {$health_check_return_code}");
- }
-
- if (str($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'healthy') {
- $this->newVersionIsHealthy = true;
- $this->application->update(['status' => 'running']);
- $this->application_deployment_queue->addLogEntry('New container is healthy.');
- break;
- }
- if (str($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'unhealthy') {
- $this->newVersionIsHealthy = false;
- $this->query_logs();
- break;
- }
- $counter++;
- $sleeptime = 0;
- while ($sleeptime < $this->application->health_check_interval) {
- Sleep::for(1)->seconds();
- $sleeptime++;
- }
- }
- if (str($this->saved_outputs->get('health_check'))->replace('"', '')->value() === 'starting') {
- $this->query_logs();
- }
- }
- }
- }
-
- private function query_logs()
- {
- $this->application_deployment_queue->addLogEntry('----------------------------------------');
- $this->application_deployment_queue->addLogEntry('Container logs:');
- $this->execute_remote_command(
- [
- 'command' => "docker logs -n 100 {$this->container_name}",
- 'type' => 'stderr',
- 'ignore_errors' => true,
- ],
- );
- $this->application_deployment_queue->addLogEntry('----------------------------------------');
- }
-
- private function deploy_pull_request()
- {
- if ($this->application->build_pack === 'dockercompose') {
- $this->deploy_docker_compose_buildpack();
-
- return;
- }
- if ($this->use_build_server) {
- $this->server = $this->build_server;
- }
- $this->newVersionIsHealthy = true;
- $this->generate_image_names();
- $this->application_deployment_queue->addLogEntry("Starting pull request (#{$this->pull_request_id}) deployment of {$this->customRepository}:{$this->application->git_branch}.");
- $this->prepare_builder_image();
- $this->check_git_if_build_needed();
- $this->clone_repository();
- $this->cleanup_git();
- if ($this->application->build_pack === 'nixpacks') {
- $this->generate_nixpacks_confs();
- }
- $this->generate_compose_file();
- $this->generate_build_env_variables();
- if ($this->application->build_pack === 'dockerfile') {
- $this->add_build_env_variables_to_dockerfile();
- }
- $this->build_image();
- $this->push_to_docker_registry();
- // $this->stop_running_container();
- $this->rolling_update();
- }
-
- private function create_workdir()
- {
- if ($this->use_build_server) {
- $this->server = $this->original_server;
- $this->execute_remote_command(
- [
- 'command' => "mkdir -p {$this->configuration_dir}",
- ],
- );
- $this->server = $this->build_server;
- $this->execute_remote_command(
- [
- 'command' => executeInDocker($this->deployment_uuid, "mkdir -p {$this->workdir}"),
- ],
- [
- 'command' => "mkdir -p {$this->configuration_dir}",
- ],
- );
- } else {
- $this->execute_remote_command(
- [
- 'command' => executeInDocker($this->deployment_uuid, "mkdir -p {$this->workdir}"),
- ],
- [
- 'command' => "mkdir -p {$this->configuration_dir}",
- ],
- );
- }
- }
-
- private function prepare_builder_image()
- {
- $settings = instanceSettings();
- $helperImage = config('constants.coolify.helper_image');
- $helperImage = "{$helperImage}:{$settings->helper_version}";
- // Get user home directory
- $this->serverUserHomeDir = instant_remote_process(['echo $HOME'], $this->server);
- $this->dockerConfigFileExists = instant_remote_process(["test -f {$this->serverUserHomeDir}/.docker/config.json && echo 'OK' || echo 'NOK'"], $this->server);
- if ($this->use_build_server) {
- if ($this->dockerConfigFileExists === 'NOK') {
- throw new RuntimeException('Docker config file (~/.docker/config.json) not found on the build server. Please run "docker login" to login to the docker registry on the server.');
- }
- $runCommand = "docker run -d --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
- } else {
- if ($this->dockerConfigFileExists === 'OK') {
- $runCommand = "docker run -d --network {$this->destination->network} --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
- } else {
- $runCommand = "docker run -d --network {$this->destination->network} --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
- }
- }
- $this->application_deployment_queue->addLogEntry("Preparing container with helper image: $helperImage.");
- $this->execute_remote_command(
- [
- 'command' => "docker rm -f {$this->deployment_uuid}",
- 'ignore_errors' => true,
- 'hidden' => true,
- ]
- );
- $this->execute_remote_command(
- [
- $runCommand,
- 'hidden' => true,
- ],
- [
- 'command' => executeInDocker($this->deployment_uuid, "mkdir -p {$this->basedir}"),
- ],
- );
- $this->run_pre_deployment_command();
- }
-
- private function deploy_to_additional_destinations()
- {
- if ($this->application->additional_networks->count() === 0) {
- return;
- }
- if ($this->pull_request_id !== 0) {
- return;
- }
- $destination_ids = $this->application->additional_networks->pluck('id');
- if ($this->server->isSwarm()) {
- $this->application_deployment_queue->addLogEntry('Additional destinations are not supported in swarm mode.');
-
- return;
- }
- if ($destination_ids->contains($this->destination->id)) {
- return;
- }
- foreach ($destination_ids as $destination_id) {
- $destination = StandaloneDocker::find($destination_id);
- $server = $destination->server;
- if ($server->team_id !== $this->mainServer->team_id) {
- $this->application_deployment_queue->addLogEntry("Skipping deployment to {$server->name}. Not in the same team?!");
-
- continue;
- }
- $deployment_uuid = new Cuid2;
- queue_application_deployment(
- deployment_uuid: $deployment_uuid,
- application: $this->application,
- server: $server,
- destination: $destination,
- no_questions_asked: true,
- );
- $this->application_deployment_queue->addLogEntry("Deployment to {$server->name}. Logs: ".route('project.application.deployment.show', [
- 'project_uuid' => data_get($this->application, 'environment.project.uuid'),
- 'application_uuid' => data_get($this->application, 'uuid'),
- 'deployment_uuid' => $deployment_uuid,
- 'environment_uuid' => data_get($this->application, 'environment.uuid'),
- ]));
- }
- }
-
- private function set_coolify_variables()
- {
- $this->coolify_variables = "SOURCE_COMMIT={$this->commit} ";
- if ($this->pull_request_id === 0) {
- $fqdn = $this->application->fqdn;
- } else {
- $fqdn = $this->preview->fqdn;
- }
- if (isset($fqdn)) {
- $this->coolify_variables .= "COOLIFY_FQDN={$fqdn} ";
- $url = str($fqdn)->replace('http://', '')->replace('https://', '');
- $this->coolify_variables .= "COOLIFY_URL={$url} ";
- }
- if (isset($this->application->git_branch)) {
- $this->coolify_variables .= "COOLIFY_BRANCH={$this->application->git_branch} ";
- }
- }
-
- private function check_git_if_build_needed()
- {
- $this->generate_git_import_commands();
- $local_branch = $this->branch;
- if ($this->pull_request_id !== 0) {
- $local_branch = "pull/{$this->pull_request_id}/head";
- }
- $private_key = data_get($this->application, 'private_key.private_key');
- if ($private_key) {
- $private_key = base64_encode($private_key);
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, 'mkdir -p /root/.ssh'),
- ],
- [
- executeInDocker($this->deployment_uuid, "echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null"),
- ],
- [
- executeInDocker($this->deployment_uuid, 'chmod 600 /root/.ssh/id_rsa'),
- ],
- [
- executeInDocker($this->deployment_uuid, "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git ls-remote {$this->fullRepoUrl} {$local_branch}"),
- 'hidden' => true,
- 'save' => 'git_commit_sha',
- ]
- );
- } else {
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git ls-remote {$this->fullRepoUrl} {$local_branch}"),
- 'hidden' => true,
- 'save' => 'git_commit_sha',
- ],
- );
- }
- if ($this->saved_outputs->get('git_commit_sha') && ! $this->rollback) {
- $this->commit = $this->saved_outputs->get('git_commit_sha')->before("\t");
- $this->application_deployment_queue->commit = $this->commit;
- $this->application_deployment_queue->save();
- }
- $this->set_coolify_variables();
- }
-
- private function clone_repository()
- {
- $importCommands = $this->generate_git_import_commands();
- $this->application_deployment_queue->addLogEntry("\n----------------------------------------");
- $this->application_deployment_queue->addLogEntry("Importing {$this->customRepository}:{$this->application->git_branch} (commit sha {$this->application->git_commit_sha}) to {$this->basedir}.");
- if ($this->pull_request_id !== 0) {
- $this->application_deployment_queue->addLogEntry("Checking out tag pull/{$this->pull_request_id}/head.");
- }
- $this->execute_remote_command(
- [
- $importCommands,
- 'hidden' => true,
- ]
- );
- $this->create_workdir();
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "cd {$this->workdir} && git log -1 {$this->commit} --pretty=%B"),
- 'hidden' => true,
- 'save' => 'commit_message',
- ]
- );
- if ($this->saved_outputs->get('commit_message')) {
- $commit_message = str($this->saved_outputs->get('commit_message'));
- $this->application_deployment_queue->commit_message = $commit_message->value();
- ApplicationDeploymentQueue::whereCommit($this->commit)->whereApplicationId($this->application->id)->update(
- ['commit_message' => $commit_message->value()]
- );
- }
- }
-
- private function generate_git_import_commands()
- {
- ['commands' => $commands, 'branch' => $this->branch, 'fullRepoUrl' => $this->fullRepoUrl] = $this->application->generateGitImportCommands(
- deployment_uuid: $this->deployment_uuid,
- pull_request_id: $this->pull_request_id,
- git_type: $this->git_type,
- commit: $this->commit
- );
-
- return $commands;
- }
-
- private function cleanup_git()
- {
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "rm -fr {$this->basedir}/.git")],
- );
- }
-
- private function generate_nixpacks_confs()
- {
- $nixpacks_command = $this->nixpacks_build_cmd();
- $this->application_deployment_queue->addLogEntry("Generating nixpacks configuration with: $nixpacks_command");
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, $nixpacks_command), 'save' => 'nixpacks_plan', 'hidden' => true],
- [executeInDocker($this->deployment_uuid, "nixpacks detect {$this->workdir}"), 'save' => 'nixpacks_type', 'hidden' => true],
- );
- if ($this->saved_outputs->get('nixpacks_type')) {
- $this->nixpacks_type = $this->saved_outputs->get('nixpacks_type');
- if (str($this->nixpacks_type)->isEmpty()) {
- throw new RuntimeException('Nixpacks failed to detect the application type. Please check the documentation of Nixpacks: https://nixpacks.com/docs/providers');
- }
- }
-
- if ($this->saved_outputs->get('nixpacks_plan')) {
- $this->nixpacks_plan = $this->saved_outputs->get('nixpacks_plan');
- if ($this->nixpacks_plan) {
- $this->application_deployment_queue->addLogEntry("Found application type: {$this->nixpacks_type}.");
- $this->application_deployment_queue->addLogEntry("If you need further customization, please check the documentation of Nixpacks: https://nixpacks.com/docs/providers/{$this->nixpacks_type}");
- $parsed = Toml::Parse($this->nixpacks_plan);
-
- // Do any modifications here
- $this->generate_env_variables();
- $merged_envs = collect(data_get($parsed, 'variables', []))->merge($this->env_args);
- $aptPkgs = data_get($parsed, 'phases.setup.aptPkgs', []);
- if (count($aptPkgs) === 0) {
- $aptPkgs = ['curl', 'wget'];
- data_set($parsed, 'phases.setup.aptPkgs', ['curl', 'wget']);
- } else {
- if (! in_array('curl', $aptPkgs)) {
- $aptPkgs[] = 'curl';
- }
- if (! in_array('wget', $aptPkgs)) {
- $aptPkgs[] = 'wget';
- }
- data_set($parsed, 'phases.setup.aptPkgs', $aptPkgs);
- }
- data_set($parsed, 'variables', $merged_envs->toArray());
- $is_laravel = data_get($parsed, 'variables.IS_LARAVEL', false);
- if ($is_laravel) {
- $variables = $this->laravel_finetunes();
- data_set($parsed, 'variables.NIXPACKS_PHP_FALLBACK_PATH', $variables[0]->value);
- data_set($parsed, 'variables.NIXPACKS_PHP_ROOT_DIR', $variables[1]->value);
- }
- if ($this->nixpacks_type === 'elixir') {
- $this->elixir_finetunes();
- }
- $this->nixpacks_plan = json_encode($parsed, JSON_PRETTY_PRINT);
- $this->nixpacks_plan_json = collect($parsed);
- $this->application_deployment_queue->addLogEntry("Final Nixpacks plan: {$this->nixpacks_plan}", hidden: true);
- if ($this->nixpacks_type === 'rust') {
- // temporary: disable healthcheck for rust because the start phase does not have curl/wget
- $this->application->health_check_enabled = false;
- $this->application->save();
- }
- }
- }
- }
-
- private function nixpacks_build_cmd()
- {
- $this->generate_nixpacks_env_variables();
- $nixpacks_command = "nixpacks plan -f toml {$this->env_nixpacks_args}";
- if ($this->application->build_command) {
- $nixpacks_command .= " --build-cmd \"{$this->application->build_command}\"";
- }
- if ($this->application->start_command) {
- $nixpacks_command .= " --start-cmd \"{$this->application->start_command}\"";
- }
- if ($this->application->install_command) {
- $nixpacks_command .= " --install-cmd \"{$this->application->install_command}\"";
- }
- $nixpacks_command .= " {$this->workdir}";
-
- return $nixpacks_command;
- }
-
- private function generate_nixpacks_env_variables()
- {
- $this->env_nixpacks_args = collect([]);
- if ($this->pull_request_id === 0) {
- foreach ($this->application->nixpacks_environment_variables as $env) {
- if (! is_null($env->real_value)) {
- $this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}");
- }
- }
- } else {
- foreach ($this->application->nixpacks_environment_variables_preview as $env) {
- if (! is_null($env->real_value)) {
- $this->env_nixpacks_args->push("--env {$env->key}={$env->real_value}");
- }
- }
- }
-
- $this->env_nixpacks_args = $this->env_nixpacks_args->implode(' ');
- }
-
- private function generate_env_variables()
- {
- $this->env_args = collect([]);
- $this->env_args->put('SOURCE_COMMIT', $this->commit);
- if ($this->pull_request_id === 0) {
- foreach ($this->application->build_environment_variables as $env) {
- if (! is_null($env->real_value)) {
- $this->env_args->put($env->key, $env->real_value);
- }
- }
- } else {
- foreach ($this->application->build_environment_variables_preview as $env) {
- if (! is_null($env->real_value)) {
- $this->env_args->put($env->key, $env->real_value);
- }
- }
- }
- }
-
- private function generate_compose_file()
- {
- $this->create_workdir();
- $ports = $this->application->main_port();
- $onlyPort = null;
- if (count($ports) > 0) {
- $onlyPort = $ports[0];
- }
- $persistent_storages = $this->generate_local_persistent_volumes();
- $persistent_file_volumes = $this->application->fileStorages()->get();
- $volume_names = $this->generate_local_persistent_volumes_only_volume_names();
- // $environment_variables = $this->generate_environment_variables($ports);
- $this->save_environment_variables();
- if (data_get($this->application, 'custom_labels')) {
- $this->application->parseContainerLabels();
- $labels = collect(preg_split("/\r\n|\n|\r/", base64_decode($this->application->custom_labels)));
- $labels = $labels->filter(function ($value, $key) {
- return ! Str::startsWith($value, 'coolify.');
- });
- $found_caddy_labels = $labels->filter(function ($value, $key) {
- return Str::startsWith($value, 'caddy_');
- });
- if ($found_caddy_labels->count() === 0) {
- if ($this->pull_request_id !== 0) {
- $domains = str(data_get($this->preview, 'fqdn'))->explode(',');
- } else {
- $domains = str(data_get($this->application, 'fqdn'))->explode(',');
- }
- $labels = $labels->merge(fqdnLabelsForCaddy(
- network: $this->application->destination->network,
- uuid: $this->application->uuid,
- domains: $domains,
- onlyPort: $onlyPort,
- is_force_https_enabled: $this->application->isForceHttpsEnabled(),
- is_gzip_enabled: $this->application->isGzipEnabled(),
- is_stripprefix_enabled: $this->application->isStripprefixEnabled()
- ));
- }
- $this->application->custom_labels = base64_encode($labels->implode("\n"));
- $this->application->save();
- } else {
- if ($this->application->settings->is_container_label_readonly_enabled) {
- $labels = collect(generateLabelsApplication($this->application, $this->preview));
- }
- }
- if ($this->pull_request_id !== 0) {
- $labels = collect(generateLabelsApplication($this->application, $this->preview));
- }
- if ($this->application->settings->is_container_label_escape_enabled) {
- $labels = $labels->map(function ($value, $key) {
- return escapeDollarSign($value);
- });
- }
- $labels = $labels->merge(defaultLabels($this->application->id, $this->application->uuid, $this->application->project()->name, $this->application->name, $this->application->environment->name, $this->pull_request_id))->toArray();
-
- // Check for custom HEALTHCHECK
- if ($this->application->build_pack === 'dockerfile' || $this->application->dockerfile) {
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"),
- 'hidden' => true,
- 'save' => 'dockerfile_from_repo',
- 'ignore_errors' => true,
- ]);
- $dockerfile = collect(str($this->saved_outputs->get('dockerfile_from_repo'))->trim()->explode("\n"));
- $this->application->parseHealthcheckFromDockerfile($dockerfile);
- }
- $docker_compose = [
- 'services' => [
- $this->container_name => [
- 'image' => $this->production_image_name,
- 'container_name' => $this->container_name,
- 'restart' => RESTART_MODE,
- 'expose' => $ports,
- 'networks' => [
- $this->destination->network => [
- 'aliases' => [
- $this->container_name,
- ],
- ],
- ],
- 'mem_limit' => $this->application->limits_memory,
- 'memswap_limit' => $this->application->limits_memory_swap,
- 'mem_swappiness' => $this->application->limits_memory_swappiness,
- 'mem_reservation' => $this->application->limits_memory_reservation,
- 'cpus' => (float) $this->application->limits_cpus,
- 'cpu_shares' => $this->application->limits_cpu_shares,
- ],
- ],
- 'networks' => [
- $this->destination->network => [
- 'external' => true,
- 'name' => $this->destination->network,
- 'attachable' => true,
- ],
- ],
- ];
- if (! is_null($this->env_filename)) {
- $docker_compose['services'][$this->container_name]['env_file'] = [$this->env_filename];
- }
- $docker_compose['services'][$this->container_name]['healthcheck'] = [
- 'test' => [
- 'CMD-SHELL',
- $this->generate_healthcheck_commands(),
- ],
- 'interval' => $this->application->health_check_interval.'s',
- 'timeout' => $this->application->health_check_timeout.'s',
- 'retries' => $this->application->health_check_retries,
- 'start_period' => $this->application->health_check_start_period.'s',
- ];
-
- if (! is_null($this->application->limits_cpuset)) {
- data_set($docker_compose, 'services.'.$this->container_name.'.cpuset', $this->application->limits_cpuset);
- }
- if ($this->server->isSwarm()) {
- data_forget($docker_compose, 'services.'.$this->container_name.'.container_name');
- data_forget($docker_compose, 'services.'.$this->container_name.'.expose');
- data_forget($docker_compose, 'services.'.$this->container_name.'.restart');
-
- data_forget($docker_compose, 'services.'.$this->container_name.'.mem_limit');
- data_forget($docker_compose, 'services.'.$this->container_name.'.memswap_limit');
- data_forget($docker_compose, 'services.'.$this->container_name.'.mem_swappiness');
- data_forget($docker_compose, 'services.'.$this->container_name.'.mem_reservation');
- data_forget($docker_compose, 'services.'.$this->container_name.'.cpus');
- data_forget($docker_compose, 'services.'.$this->container_name.'.cpuset');
- data_forget($docker_compose, 'services.'.$this->container_name.'.cpu_shares');
-
- $docker_compose['services'][$this->container_name]['deploy'] = [
- 'mode' => 'replicated',
- 'replicas' => data_get($this->application, 'swarm_replicas', 1),
- 'update_config' => [
- 'order' => 'start-first',
- ],
- 'rollback_config' => [
- 'order' => 'start-first',
- ],
- 'labels' => $labels,
- 'resources' => [
- 'limits' => [
- 'cpus' => $this->application->limits_cpus,
- 'memory' => $this->application->limits_memory,
- ],
- 'reservations' => [
- 'cpus' => $this->application->limits_cpus,
- 'memory' => $this->application->limits_memory,
- ],
- ],
- ];
- if (data_get($this->application, 'swarm_placement_constraints')) {
- $swarm_placement_constraints = Yaml::parse(base64_decode(data_get($this->application, 'swarm_placement_constraints')));
- $docker_compose['services'][$this->container_name]['deploy'] = array_merge(
- $docker_compose['services'][$this->container_name]['deploy'],
- $swarm_placement_constraints
- );
- }
- if (data_get($this->application, 'settings.is_swarm_only_worker_nodes')) {
- $docker_compose['services'][$this->container_name]['deploy']['placement']['constraints'][] = 'node.role == worker';
- }
- if ($this->pull_request_id !== 0) {
- $docker_compose['services'][$this->container_name]['deploy']['replicas'] = 1;
- }
- } else {
- $docker_compose['services'][$this->container_name]['labels'] = $labels;
- }
- if ($this->server->isLogDrainEnabled() && $this->application->isLogDrainEnabled()) {
- $docker_compose['services'][$this->container_name]['logging'] = generate_fluentd_configuration();
- }
- if ($this->application->settings->is_gpu_enabled) {
- $docker_compose['services'][$this->container_name]['deploy']['resources']['reservations']['devices'] = [
- [
- 'driver' => data_get($this->application, 'settings.gpu_driver', 'nvidia'),
- 'capabilities' => ['gpu'],
- 'options' => data_get($this->application, 'settings.gpu_options', []),
- ],
- ];
- if (data_get($this->application, 'settings.gpu_count')) {
- $count = data_get($this->application, 'settings.gpu_count');
- if ($count === 'all') {
- $docker_compose['services'][$this->container_name]['deploy']['resources']['reservations']['devices'][0]['count'] = $count;
- } else {
- $docker_compose['services'][$this->container_name]['deploy']['resources']['reservations']['devices'][0]['count'] = (int) $count;
- }
- } elseif (data_get($this->application, 'settings.gpu_device_ids')) {
- $docker_compose['services'][$this->container_name]['deploy']['resources']['reservations']['devices'][0]['ids'] = data_get($this->application, 'settings.gpu_device_ids');
- }
- }
- if ($this->application->isHealthcheckDisabled()) {
- data_forget($docker_compose, 'services.'.$this->container_name.'.healthcheck');
- }
- if (count($this->application->ports_mappings_array) > 0 && $this->pull_request_id === 0) {
- $docker_compose['services'][$this->container_name]['ports'] = $this->application->ports_mappings_array;
- }
-
- if (count($persistent_storages) > 0) {
- if (! data_get($docker_compose, 'services.'.$this->container_name.'.volumes')) {
- $docker_compose['services'][$this->container_name]['volumes'] = [];
- }
- $docker_compose['services'][$this->container_name]['volumes'] = array_merge($docker_compose['services'][$this->container_name]['volumes'], $persistent_storages);
- }
- if (count($persistent_file_volumes) > 0) {
- if (! data_get($docker_compose, 'services.'.$this->container_name.'.volumes')) {
- $docker_compose['services'][$this->container_name]['volumes'] = [];
- }
- $docker_compose['services'][$this->container_name]['volumes'] = array_merge($docker_compose['services'][$this->container_name]['volumes'], $persistent_file_volumes->map(function ($item) {
- return "$item->fs_path:$item->mount_path";
- })->toArray());
- }
- if (count($volume_names) > 0) {
- $docker_compose['volumes'] = $volume_names;
- }
-
- if ($this->pull_request_id === 0) {
- $custom_compose = convertDockerRunToCompose($this->application->custom_docker_run_options);
- if ((bool) $this->application->settings->is_consistent_container_name_enabled) {
- if (! $this->application->settings->custom_internal_name) {
- $docker_compose['services'][$this->application->uuid] = $docker_compose['services'][$this->container_name];
- if (count($custom_compose) > 0) {
- $ipv4 = data_get($custom_compose, 'ip.0');
- $ipv6 = data_get($custom_compose, 'ip6.0');
- data_forget($custom_compose, 'ip');
- data_forget($custom_compose, 'ip6');
- if ($ipv4 || $ipv6) {
- data_forget($docker_compose['services'][$this->application->uuid], 'networks');
- }
- if ($ipv4) {
- $docker_compose['services'][$this->application->uuid]['networks'][$this->destination->network]['ipv4_address'] = $ipv4;
- }
- if ($ipv6) {
- $docker_compose['services'][$this->application->uuid]['networks'][$this->destination->network]['ipv6_address'] = $ipv6;
- }
- $docker_compose['services'][$this->application->uuid] = array_merge_recursive($docker_compose['services'][$this->application->uuid], $custom_compose);
- }
- }
- } else {
- if (count($custom_compose) > 0) {
- $ipv4 = data_get($custom_compose, 'ip.0');
- $ipv6 = data_get($custom_compose, 'ip6.0');
- data_forget($custom_compose, 'ip');
- data_forget($custom_compose, 'ip6');
- if ($ipv4 || $ipv6) {
- data_forget($docker_compose['services'][$this->container_name], 'networks');
- }
- if ($ipv4) {
- $docker_compose['services'][$this->container_name]['networks'][$this->destination->network]['ipv4_address'] = $ipv4;
- }
- if ($ipv6) {
- $docker_compose['services'][$this->container_name]['networks'][$this->destination->network]['ipv6_address'] = $ipv6;
- }
- $docker_compose['services'][$this->container_name] = array_merge_recursive($docker_compose['services'][$this->container_name], $custom_compose);
- }
- }
- }
-
- $this->docker_compose = Yaml::dump($docker_compose, 10);
- $this->docker_compose_base64 = base64_encode($this->docker_compose);
- $this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d | tee {$this->workdir}/docker-compose.yaml > /dev/null"), 'hidden' => true]);
- }
-
- private function generate_local_persistent_volumes()
- {
- $local_persistent_volumes = [];
- foreach ($this->application->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
- $volume_name = $persistentStorage->host_path;
- } else {
- $volume_name = $persistentStorage->name;
- }
- if ($this->pull_request_id !== 0) {
- $volume_name = $volume_name.'-pr-'.$this->pull_request_id;
- }
- $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
- }
-
- return $local_persistent_volumes;
- }
-
- private function generate_local_persistent_volumes_only_volume_names()
- {
- $local_persistent_volumes_names = [];
- foreach ($this->application->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path) {
- continue;
- }
- $name = $persistentStorage->name;
-
- if ($this->pull_request_id !== 0) {
- $name = $name.'-pr-'.$this->pull_request_id;
- }
-
- $local_persistent_volumes_names[$name] = [
- 'name' => $name,
- 'external' => false,
- ];
- }
-
- return $local_persistent_volumes_names;
- }
-
- private function generate_healthcheck_commands()
- {
- if (! $this->application->health_check_port) {
- $health_check_port = $this->application->ports_exposes_array[0];
- } else {
- $health_check_port = $this->application->health_check_port;
- }
- if ($this->application->settings->is_static || $this->application->build_pack === 'static') {
- $health_check_port = 80;
- }
- if ($this->application->health_check_path) {
- $this->full_healthcheck_url = "{$this->application->health_check_method}: {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path}";
- $generated_healthchecks_commands = [
- "curl -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path} > /dev/null || wget -q -O- {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path} > /dev/null || exit 1",
- ];
- } else {
- $this->full_healthcheck_url = "{$this->application->health_check_method}: {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}/";
- $generated_healthchecks_commands = [
- "curl -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}/ > /dev/null || wget -q -O- {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}/ > /dev/null || exit 1",
- ];
- }
-
- return implode(' ', $generated_healthchecks_commands);
- }
-
- private function pull_latest_image($image)
- {
- $this->application_deployment_queue->addLogEntry("Pulling latest image ($image) from the registry.");
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "docker pull {$image}"),
- 'hidden' => true,
- ]
- );
- }
-
- private function build_image()
- {
- // Add Coolify related variables to the build args
- $this->environment_variables->filter(function ($key, $value) {
- return str($key)->startsWith('COOLIFY_');
- })->each(function ($key, $value) {
- $this->build_args->push("--build-arg '{$key}'");
- });
-
- $this->build_args = $this->build_args->implode(' ');
-
- $this->application_deployment_queue->addLogEntry('----------------------------------------');
- if ($this->disableBuildCache) {
- $this->application_deployment_queue->addLogEntry('Docker build cache is disabled. It will not be used during the build process.');
- }
- if ($this->application->build_pack === 'static') {
- $this->application_deployment_queue->addLogEntry('Static deployment. Copying static assets to the image.');
- } else {
- $this->application_deployment_queue->addLogEntry('Building docker image started.');
- $this->application_deployment_queue->addLogEntry('To check the current progress, click on Show Debug Logs.');
- }
-
- if ($this->application->settings->is_static || $this->application->build_pack === 'static') {
- if ($this->application->static_image) {
- $this->pull_latest_image($this->application->static_image);
- $this->application_deployment_queue->addLogEntry('Continuing with the building process.');
- }
- if ($this->application->build_pack === 'static') {
- $dockerfile = base64_encode("FROM {$this->application->static_image}
-WORKDIR /usr/share/nginx/html/
-LABEL coolify.deploymentId={$this->deployment_uuid}
-COPY . .
-RUN rm -f /usr/share/nginx/html/nginx.conf
-RUN rm -f /usr/share/nginx/html/Dockerfile
-RUN rm -f /usr/share/nginx/html/docker-compose.yaml
-RUN rm -f /usr/share/nginx/html/.env
-COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
- if (str($this->application->custom_nginx_configuration)->isNotEmpty()) {
- $nginx_config = base64_encode($this->application->custom_nginx_configuration);
- } else {
- $nginx_config = base64_encode(defaultNginxConfiguration());
- }
- } else {
- if ($this->application->build_pack === 'nixpacks') {
- $this->nixpacks_plan = base64_encode($this->nixpacks_plan);
- $this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->nixpacks_plan}' | base64 -d | tee /artifacts/thegameplan.json > /dev/null"), 'hidden' => true]);
- if ($this->force_rebuild) {
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --no-cache --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"),
- 'hidden' => true,
- ]);
- $build_command = "docker build --no-cache {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->build_image_name} {$this->workdir}";
- } else {
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"),
- 'hidden' => true,
- ]);
- $build_command = "docker build {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->build_image_name} {$this->workdir}";
- }
-
- $base64_build_command = base64_encode($build_command);
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
- 'hidden' => true,
- ]
- );
- $this->execute_remote_command([executeInDocker($this->deployment_uuid, 'rm /artifacts/thegameplan.json'), 'hidden' => true]);
- } else {
- if ($this->force_rebuild) {
- $build_command = "docker build --no-cache {$this->buildTarget} --network {$this->destination->network} -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}";
- $base64_build_command = base64_encode($build_command);
- } else {
- $build_command = "docker build {$this->buildTarget} --network {$this->destination->network} -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}";
- $base64_build_command = base64_encode($build_command);
- }
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
- 'hidden' => true,
- ]
- );
- }
- $dockerfile = base64_encode("FROM {$this->application->static_image}
-WORKDIR /usr/share/nginx/html/
-LABEL coolify.deploymentId={$this->deployment_uuid}
-COPY --from=$this->build_image_name /app/{$this->application->publish_directory} .
-COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
- if (str($this->application->custom_nginx_configuration)->isNotEmpty()) {
- $nginx_config = base64_encode($this->application->custom_nginx_configuration);
- } else {
- $nginx_config = base64_encode(defaultNginxConfiguration());
- }
- }
- $build_command = "docker build {$this->addHosts} --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}";
- $base64_build_command = base64_encode($build_command);
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "echo '{$dockerfile}' | base64 -d | tee {$this->workdir}/Dockerfile > /dev/null"),
- ],
- [
- executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d | tee {$this->workdir}/nginx.conf > /dev/null"),
- ],
- [
- executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
- 'hidden' => true,
- ]
- );
- } else {
- // Pure Dockerfile based deployment
- if ($this->application->dockerfile) {
- if ($this->force_rebuild) {
- $build_command = "docker build --no-cache --pull {$this->buildTarget} {$this->addHosts} --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}";
- } else {
- $build_command = "docker build --pull {$this->buildTarget} {$this->addHosts} --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}";
- }
- $base64_build_command = base64_encode($build_command);
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
- 'hidden' => true,
- ]
- );
- } else {
- if ($this->application->build_pack === 'nixpacks') {
- $this->nixpacks_plan = base64_encode($this->nixpacks_plan);
- $this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->nixpacks_plan}' | base64 -d | tee /artifacts/thegameplan.json > /dev/null"), 'hidden' => true]);
- if ($this->force_rebuild) {
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --no-cache --no-error-without-start -n {$this->production_image_name} {$this->workdir} -o {$this->workdir}"),
- 'hidden' => true,
- ]);
- $build_command = "docker build --no-cache {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}";
- } else {
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->production_image_name} {$this->workdir} -o {$this->workdir}"),
- 'hidden' => true,
- ]);
- $build_command = "docker build {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}";
- }
- $base64_build_command = base64_encode($build_command);
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
- 'hidden' => true,
- ]
- );
- $this->execute_remote_command([executeInDocker($this->deployment_uuid, 'rm /artifacts/thegameplan.json'), 'hidden' => true]);
- } else {
- if ($this->force_rebuild) {
- $build_command = "docker build --no-cache {$this->buildTarget} {$this->addHosts} --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}";
- $base64_build_command = base64_encode($build_command);
- } else {
- $build_command = "docker build {$this->buildTarget} {$this->addHosts} --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}";
- $base64_build_command = base64_encode($build_command);
- }
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
- 'hidden' => true,
- ],
- [
- executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
- 'hidden' => true,
- ]
- );
- }
- }
- }
- $this->application_deployment_queue->addLogEntry('Building docker image completed.');
- }
-
- private function graceful_shutdown_container(string $containerName, int $timeout = 300)
- {
- try {
- $process = Process::timeout($timeout)->start("docker stop --time=$timeout $containerName");
-
- $startTime = time();
- while ($process->running()) {
- if (time() - $startTime >= $timeout) {
- $this->execute_remote_command(
- ["docker kill $containerName", 'hidden' => true, 'ignore_errors' => true]
- );
- break;
- }
- usleep(100000);
- }
-
- $isRunning = $this->execute_remote_command(
- ["docker inspect -f '{{.State.Running}}' $containerName", 'hidden' => true, 'ignore_errors' => true]
- ) === 'true';
-
- if ($isRunning) {
- $this->execute_remote_command(
- ["docker kill $containerName", 'hidden' => true, 'ignore_errors' => true]
- );
- }
- } catch (\Exception $error) {
- $this->application_deployment_queue->addLogEntry("Error stopping container $containerName: ".$error->getMessage(), 'stderr');
- }
-
- $this->remove_container($containerName);
- }
-
- private function remove_container(string $containerName)
- {
- $this->execute_remote_command(
- ["docker rm -f $containerName", 'hidden' => true, 'ignore_errors' => true]
- );
- }
-
- private function stop_running_container(bool $force = false)
- {
- $this->application_deployment_queue->addLogEntry('Removing old containers.');
- if ($this->newVersionIsHealthy || $force) {
- if ($this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty()) {
- $this->graceful_shutdown_container($this->container_name);
- } else {
- $containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, $this->pull_request_id);
- if ($this->pull_request_id === 0) {
- $containers = $containers->filter(function ($container) {
- return data_get($container, 'Names') !== $this->container_name && data_get($container, 'Names') !== $this->container_name.'-pr-'.$this->pull_request_id;
- });
- }
- $containers->each(function ($container) {
- $this->graceful_shutdown_container(data_get($container, 'Names'));
- });
- }
- } else {
- if ($this->application->dockerfile || $this->application->build_pack === 'dockerfile' || $this->application->build_pack === 'dockerimage') {
- $this->application_deployment_queue->addLogEntry('----------------------------------------');
- $this->application_deployment_queue->addLogEntry("WARNING: Dockerfile or Docker Image based deployment detected. The healthcheck needs a curl or wget command to check the health of the application. Please make sure that it is available in the image or turn off healthcheck on Coolify's UI.");
- $this->application_deployment_queue->addLogEntry('----------------------------------------');
- }
- $this->application_deployment_queue->addLogEntry('New container is not healthy, rolling back to the old container.');
- $this->application_deployment_queue->update([
- 'status' => ApplicationDeploymentStatus::FAILED->value,
- ]);
- $this->graceful_shutdown_container($this->container_name);
- }
- }
-
- private function start_by_compose_file()
- {
- if ($this->application->build_pack === 'dockerimage') {
- $this->application_deployment_queue->addLogEntry('Pulling latest images from the registry.');
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "docker compose --project-name {$this->application->uuid} --project-directory {$this->workdir} pull"), 'hidden' => true],
- [executeInDocker($this->deployment_uuid, "{$this->coolify_variables} docker compose --project-name {$this->application->uuid} --project-directory {$this->workdir} up --build -d"), 'hidden' => true],
- );
- } else {
- if ($this->use_build_server) {
- $this->execute_remote_command(
- ["{$this->coolify_variables} docker compose --project-name {$this->application->uuid} --project-directory {$this->configuration_dir} -f {$this->configuration_dir}{$this->docker_compose_location} up --pull always --build -d", 'hidden' => true],
- );
- } else {
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "{$this->coolify_variables} docker compose --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up --build -d"), 'hidden' => true],
- );
- }
- }
- $this->application_deployment_queue->addLogEntry('New container started.');
- }
-
- private function generate_build_env_variables()
- {
- if ($this->application->build_pack === 'nixpacks') {
- $variables = collect($this->nixpacks_plan_json->get('variables'));
- } else {
- $this->generate_env_variables();
- $variables = collect([])->merge($this->env_args);
- }
-
- $this->build_args = $variables->map(function ($value, $key) {
- $value = escapeshellarg($value);
-
- return "--build-arg {$key}={$value}";
- });
- }
-
- private function add_build_env_variables_to_dockerfile()
- {
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"),
- 'hidden' => true,
- 'save' => 'dockerfile',
- ]);
- $dockerfile = collect(str($this->saved_outputs->get('dockerfile'))->trim()->explode("\n"));
- if ($this->pull_request_id === 0) {
- foreach ($this->application->build_environment_variables as $env) {
- if (data_get($env, 'is_multiline') === true) {
- $dockerfile->splice(1, 0, "ARG {$env->key}");
- } else {
- $dockerfile->splice(1, 0, "ARG {$env->key}={$env->real_value}");
- }
- }
- } else {
- foreach ($this->application->build_environment_variables_preview as $env) {
- if (data_get($env, 'is_multiline') === true) {
- $dockerfile->splice(1, 0, "ARG {$env->key}");
- } else {
- $dockerfile->splice(1, 0, "ARG {$env->key}={$env->real_value}");
- }
- }
- }
- $dockerfile_base64 = base64_encode($dockerfile->implode("\n"));
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "echo '{$dockerfile_base64}' | base64 -d | tee {$this->workdir}{$this->dockerfile_location} > /dev/null"),
- 'hidden' => true,
- ]);
- }
-
- private function run_pre_deployment_command()
- {
- if (empty($this->application->pre_deployment_command)) {
- return;
- }
- $containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, $this->pull_request_id);
- if ($containers->count() == 0) {
- return;
- }
- $this->application_deployment_queue->addLogEntry('Executing pre-deployment command (see debug log for output/errors).');
-
- foreach ($containers as $container) {
- $containerName = data_get($container, 'Names');
- if ($containers->count() == 1 || str_starts_with($containerName, $this->application->pre_deployment_command_container.'-'.$this->application->uuid)) {
- $cmd = "sh -c '".str_replace("'", "'\''", $this->application->pre_deployment_command)."'";
- $exec = "docker exec {$containerName} {$cmd}";
- $this->execute_remote_command(
- [
- 'command' => $exec,
- 'hidden' => true,
- ],
- );
-
- return;
- }
- }
- throw new RuntimeException('Pre-deployment command: Could not find a valid container. Is the container name correct?');
- }
-
- private function run_post_deployment_command()
- {
- if (empty($this->application->post_deployment_command)) {
- return;
- }
- $this->application_deployment_queue->addLogEntry('----------------------------------------');
- $this->application_deployment_queue->addLogEntry('Executing post-deployment command (see debug log for output).');
-
- $containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, $this->pull_request_id);
- foreach ($containers as $container) {
- $containerName = data_get($container, 'Names');
- if ($containers->count() == 1 || str_starts_with($containerName, $this->application->post_deployment_command_container.'-'.$this->application->uuid)) {
- $cmd = "sh -c '".str_replace("'", "'\''", $this->application->post_deployment_command)."'";
- $exec = "docker exec {$containerName} {$cmd}";
- try {
- $this->execute_remote_command(
- [
- 'command' => $exec,
- 'hidden' => true,
- 'save' => 'post-deployment-command-output',
- ],
- );
- } catch (Exception $e) {
- $post_deployment_command_output = $this->saved_outputs->get('post-deployment-command-output');
- if ($post_deployment_command_output) {
- $this->application_deployment_queue->addLogEntry('Post-deployment command failed.');
- $this->application_deployment_queue->addLogEntry($post_deployment_command_output, 'stderr');
- }
- }
-
- return;
- }
- }
- throw new RuntimeException('Post-deployment command: Could not find a valid container. Is the container name correct?');
- }
-
- private function next(string $status)
- {
- queue_next_deployment($this->application);
- // If the deployment is cancelled by the user, don't update the status
- if (
- $this->application_deployment_queue->status !== ApplicationDeploymentStatus::CANCELLED_BY_USER->value &&
- $this->application_deployment_queue->status !== ApplicationDeploymentStatus::FAILED->value
- ) {
- $this->application_deployment_queue->update([
- 'status' => $status,
- ]);
- }
- if ($this->application_deployment_queue->status === ApplicationDeploymentStatus::FAILED->value) {
- $this->application->environment->project->team?->notify(new DeploymentFailed($this->application, $this->deployment_uuid, $this->preview));
-
- return;
- }
- if ($status === ApplicationDeploymentStatus::FINISHED->value) {
- if (! $this->only_this_server) {
- $this->deploy_to_additional_destinations();
- }
- $this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
- }
- }
-
- public function failed(Throwable $exception): void
- {
- $this->next(ApplicationDeploymentStatus::FAILED->value);
- $this->application_deployment_queue->addLogEntry('Oops something is not okay, are you okay? 😢', 'stderr');
- if (str($exception->getMessage())->isNotEmpty()) {
- $this->application_deployment_queue->addLogEntry($exception->getMessage(), 'stderr');
- }
-
- if ($this->application->build_pack !== 'dockercompose') {
- $code = $exception->getCode();
- if ($code !== 69420) {
- // 69420 means failed to push the image to the registry, so we don't need to remove the new version as it is the currently running one
- if ($this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty()) {
- // do not remove already running container
- } else {
- $this->application_deployment_queue->addLogEntry('Deployment failed. Removing the new version of your application.', 'stderr');
- $this->execute_remote_command(
- ["docker rm -f $this->container_name >/dev/null 2>&1", 'hidden' => true, 'ignore_errors' => true]
- );
- }
- }
- }
- }
-}
diff --git a/app/Jobs/ApplicationPullRequestUpdateJob.php b/app/Jobs/ApplicationPullRequestUpdateJob.php
deleted file mode 100755
index ef8e6efb6e..0000000000
--- a/app/Jobs/ApplicationPullRequestUpdateJob.php
+++ /dev/null
@@ -1,89 +0,0 @@
-onQueue('high');
- }
-
- public function handle()
- {
- try {
- if ($this->application->is_public_repository()) {
- return;
- }
- if ($this->status === ProcessStatus::CLOSED) {
- $this->delete_comment();
-
- return;
- } elseif ($this->status === ProcessStatus::IN_PROGRESS) {
- $this->body = "The preview deployment is in progress. 🟡\n\n";
- } elseif ($this->status === ProcessStatus::FINISHED) {
- $this->body = "The preview deployment is ready. 🟢\n\n";
- if ($this->preview->fqdn) {
- $this->body .= "[Open Preview]({$this->preview->fqdn}) | ";
- }
- } elseif ($this->status === ProcessStatus::ERROR) {
- $this->body = "The preview deployment failed. 🔴\n\n";
- }
- $this->build_logs_url = base_url()."/project/{$this->application->environment->project->uuid}/{$this->application->environment->name}/application/{$this->application->uuid}/deployment/{$this->deployment_uuid}";
-
- $this->body .= '[Open Build Logs]('.$this->build_logs_url.")\n\n\n";
- $this->body .= 'Last updated at: '.now()->toDateTimeString().' CET';
- if ($this->preview->pull_request_issue_comment_id) {
- $this->update_comment();
- } else {
- $this->create_comment();
- }
- } catch (\Throwable $e) {
- return $e;
- }
- }
-
- private function update_comment()
- {
- ['data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/comments/{$this->preview->pull_request_issue_comment_id}", method: 'patch', data: [
- 'body' => $this->body,
- ], throwError: false);
- if (data_get($data, 'message') === 'Not Found') {
- $this->create_comment();
- }
- }
-
- private function create_comment()
- {
- ['data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/{$this->preview->pull_request_id}/comments", method: 'post', data: [
- 'body' => $this->body,
- ]);
- $this->preview->pull_request_issue_comment_id = $data['id'];
- $this->preview->save();
- }
-
- private function delete_comment()
- {
- githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/comments/{$this->preview->pull_request_issue_comment_id}", method: 'delete');
- }
-}
diff --git a/app/Jobs/CheckAndStartSentinelJob.php b/app/Jobs/CheckAndStartSentinelJob.php
deleted file mode 100644
index 304b2a15c4..0000000000
--- a/app/Jobs/CheckAndStartSentinelJob.php
+++ /dev/null
@@ -1,52 +0,0 @@
-server, false, 10);
- $sentinelFoundJson = json_decode($sentinelFound, true);
- $sentinelStatus = data_get($sentinelFoundJson, '0.State.Status', 'exited');
- if ($sentinelStatus !== 'running') {
- StartSentinel::run(server: $this->server, restart: true, latestVersion: $latestVersion);
-
- return;
- }
- // If sentinel is running, check if it needs an update
- $runningVersion = instant_remote_process_with_timeout(['docker exec coolify-sentinel sh -c "curl http://127.0.0.1:8888/api/version"'], $this->server, false);
- if (empty($runningVersion)) {
- $runningVersion = '0.0.0';
- }
- if ($latestVersion === '0.0.0' && $runningVersion === '0.0.0') {
- StartSentinel::run(server: $this->server, restart: true, latestVersion: 'latest');
-
- return;
- } else {
- if (version_compare($runningVersion, $latestVersion, '<')) {
- StartSentinel::run(server: $this->server, restart: true, latestVersion: $latestVersion);
-
- return;
- }
- }
- }
-}
diff --git a/app/Jobs/CheckForUpdatesJob.php b/app/Jobs/CheckForUpdatesJob.php
deleted file mode 100644
index 1d3a345e15..0000000000
--- a/app/Jobs/CheckForUpdatesJob.php
+++ /dev/null
@@ -1,44 +0,0 @@
-get('https://cdn.coollabs.io/coolify/versions.json');
- if ($response->successful()) {
- $versions = $response->json();
-
- $latest_version = data_get($versions, 'coolify.v4.version');
- $current_version = config('constants.coolify.version');
-
- if (version_compare($latest_version, $current_version, '>')) {
- // New version available
- $settings->update(['new_version_available' => true]);
- File::put(base_path('versions.json'), json_encode($versions, JSON_PRETTY_PRINT));
- } else {
- $settings->update(['new_version_available' => false]);
- }
- }
- } catch (\Throwable $e) {
- // Consider implementing a notification to administrators
- }
- }
-}
diff --git a/app/Jobs/CheckHelperImageJob.php b/app/Jobs/CheckHelperImageJob.php
deleted file mode 100644
index 6abb8a1502..0000000000
--- a/app/Jobs/CheckHelperImageJob.php
+++ /dev/null
@@ -1,39 +0,0 @@
-get('https://cdn.coollabs.io/coolify/versions.json');
- if ($response->successful()) {
- $versions = $response->json();
- $settings = instanceSettings();
- $latest_version = data_get($versions, 'coolify.helper.version');
- $current_version = $settings->helper_version;
- if (version_compare($latest_version, $current_version, '>')) {
- $settings->update(['helper_version' => $latest_version]);
- }
- }
- } catch (\Throwable $e) {
- send_internal_notification('CheckHelperImageJob failed with: '.$e->getMessage());
- throw $e;
- }
- }
-}
diff --git a/app/Jobs/CleanupHelperContainersJob.php b/app/Jobs/CleanupHelperContainersJob.php
deleted file mode 100644
index 0e1fcb4d75..0000000000
--- a/app/Jobs/CleanupHelperContainersJob.php
+++ /dev/null
@@ -1,34 +0,0 @@
-server, false);
- $containerIds = collect(json_decode($containers))->pluck('ID');
- if ($containerIds->count() > 0) {
- foreach ($containerIds as $containerId) {
- instant_remote_process_with_timeout(['docker container rm -f '.$containerId], $this->server, false);
- }
- }
- } catch (\Throwable $e) {
- send_internal_notification('CleanupHelperContainersJob failed with error: '.$e->getMessage());
- }
- }
-}
diff --git a/app/Jobs/CleanupInstanceStuffsJob.php b/app/Jobs/CleanupInstanceStuffsJob.php
deleted file mode 100644
index 84f14ed02a..0000000000
--- a/app/Jobs/CleanupInstanceStuffsJob.php
+++ /dev/null
@@ -1,43 +0,0 @@
-dontRelease()];
- }
-
- public function handle(): void
- {
- try {
- $this->cleanupInvitationLink();
- } catch (\Throwable $e) {
- Log::error('CleanupInstanceStuffsJob failed with error: '.$e->getMessage());
- }
- }
-
- private function cleanupInvitationLink()
- {
- $invitation = TeamInvitation::all();
- foreach ($invitation as $item) {
- $item->isValid();
- }
- }
-}
diff --git a/app/Jobs/CleanupStaleMultiplexedConnections.php b/app/Jobs/CleanupStaleMultiplexedConnections.php
deleted file mode 100644
index 6d49bee4b0..0000000000
--- a/app/Jobs/CleanupStaleMultiplexedConnections.php
+++ /dev/null
@@ -1,82 +0,0 @@
-cleanupStaleConnections();
- $this->cleanupNonExistentServerConnections();
- }
-
- private function cleanupStaleConnections()
- {
- $muxFiles = Storage::disk('ssh-mux')->files();
-
- foreach ($muxFiles as $muxFile) {
- $serverUuid = $this->extractServerUuidFromMuxFile($muxFile);
- $server = Server::where('uuid', $serverUuid)->first();
-
- if (! $server) {
- $this->removeMultiplexFile($muxFile);
-
- continue;
- }
-
- $muxSocket = "/var/www/html/storage/app/ssh/mux/{$muxFile}";
- $checkCommand = "ssh -O check -o ControlPath={$muxSocket} {$server->user}@{$server->ip} 2>/dev/null";
- $checkProcess = Process::run($checkCommand);
-
- if ($checkProcess->exitCode() !== 0) {
- $this->removeMultiplexFile($muxFile);
- } else {
- $muxContent = Storage::disk('ssh-mux')->get($muxFile);
- $establishedAt = Carbon::parse(substr($muxContent, 37));
- $expirationTime = $establishedAt->addSeconds(config('constants.ssh.mux_persist_time'));
-
- if (Carbon::now()->isAfter($expirationTime)) {
- $this->removeMultiplexFile($muxFile);
- }
- }
- }
- }
-
- private function cleanupNonExistentServerConnections()
- {
- $muxFiles = Storage::disk('ssh-mux')->files();
- $existingServerUuids = Server::pluck('uuid')->toArray();
-
- foreach ($muxFiles as $muxFile) {
- $serverUuid = $this->extractServerUuidFromMuxFile($muxFile);
- if (! in_array($serverUuid, $existingServerUuids)) {
- $this->removeMultiplexFile($muxFile);
- }
- }
- }
-
- private function extractServerUuidFromMuxFile($muxFile)
- {
- return substr($muxFile, 4);
- }
-
- private function removeMultiplexFile($muxFile)
- {
- $muxSocket = "/var/www/html/storage/app/ssh/mux/{$muxFile}";
- $closeCommand = "ssh -O exit -o ControlPath={$muxSocket} localhost 2>/dev/null";
- Process::run($closeCommand);
- Storage::disk('ssh-mux')->delete($muxFile);
- }
-}
diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php
deleted file mode 100644
index 22ae06ebde..0000000000
--- a/app/Jobs/ContainerStatusJob.php
+++ /dev/null
@@ -1,31 +0,0 @@
-server);
- }
-}
diff --git a/app/Jobs/CoolifyTask.php b/app/Jobs/CoolifyTask.php
deleted file mode 100755
index 49a5ba8dd2..0000000000
--- a/app/Jobs/CoolifyTask.php
+++ /dev/null
@@ -1,45 +0,0 @@
-onQueue('high');
- }
-
- /**
- * Execute the job.
- */
- public function handle(): void
- {
- $remote_process = resolve(RunRemoteProcess::class, [
- 'activity' => $this->activity,
- 'ignore_errors' => $this->ignore_errors,
- 'call_event_on_finish' => $this->call_event_on_finish,
- 'call_event_data' => $this->call_event_data,
- ]);
-
- $remote_process();
- }
-}
diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php
deleted file mode 100644
index 6070ad16ab..0000000000
--- a/app/Jobs/DatabaseBackupJob.php
+++ /dev/null
@@ -1,520 +0,0 @@
-onQueue('high');
- }
-
- public function handle(): void
- {
- try {
- $databasesToBackup = null;
-
- $this->team = Team::find($this->backup->team_id);
- if (! $this->team) {
- $this->backup->delete();
-
- return;
- }
- if (data_get($this->backup, 'database_type') === \App\Models\ServiceDatabase::class) {
- $this->database = data_get($this->backup, 'database');
- $this->server = $this->database->service->server;
- $this->s3 = $this->backup->s3;
- } else {
- $this->database = data_get($this->backup, 'database');
- $this->server = $this->database->destination->server;
- $this->s3 = $this->backup->s3;
- }
- if (is_null($this->server)) {
- throw new \Exception('Server not found?!');
- }
- if (is_null($this->database)) {
- throw new \Exception('Database not found?!');
- }
-
- BackupCreated::dispatch($this->team->id);
-
- $status = str(data_get($this->database, 'status'));
- if (! $status->startsWith('running') && $this->database->id !== 0) {
- return;
- }
- if (data_get($this->backup, 'database_type') === \App\Models\ServiceDatabase::class) {
- $databaseType = $this->database->databaseType();
- $serviceUuid = $this->database->service->uuid;
- $serviceName = str($this->database->service->name)->slug();
- if (str($databaseType)->contains('postgres')) {
- $this->container_name = "{$this->database->name}-$serviceUuid";
- $this->directory_name = $serviceName.'-'.$this->container_name;
- $commands[] = "docker exec $this->container_name env | grep POSTGRES_";
- $envs = instant_remote_process($commands, $this->server);
- $envs = str($envs)->explode("\n");
-
- $user = $envs->filter(function ($env) {
- return str($env)->startsWith('POSTGRES_USER=');
- })->first();
- if ($user) {
- $this->database->postgres_user = str($user)->after('POSTGRES_USER=')->value();
- } else {
- $this->database->postgres_user = 'postgres';
- }
-
- $db = $envs->filter(function ($env) {
- return str($env)->startsWith('POSTGRES_DB=');
- })->first();
-
- if ($db) {
- $databasesToBackup = str($db)->after('POSTGRES_DB=')->value();
- } else {
- $databasesToBackup = $this->database->postgres_user;
- }
- $this->postgres_password = $envs->filter(function ($env) {
- return str($env)->startsWith('POSTGRES_PASSWORD=');
- })->first();
- if ($this->postgres_password) {
- $this->postgres_password = str($this->postgres_password)->after('POSTGRES_PASSWORD=')->value();
- }
- } elseif (str($databaseType)->contains('mysql')) {
- $this->container_name = "{$this->database->name}-$serviceUuid";
- $this->directory_name = $serviceName.'-'.$this->container_name;
- $commands[] = "docker exec $this->container_name env | grep MYSQL_";
- $envs = instant_remote_process($commands, $this->server);
- $envs = str($envs)->explode("\n");
-
- $rootPassword = $envs->filter(function ($env) {
- return str($env)->startsWith('MYSQL_ROOT_PASSWORD=');
- })->first();
- if ($rootPassword) {
- $this->database->mysql_root_password = str($rootPassword)->after('MYSQL_ROOT_PASSWORD=')->value();
- }
-
- $db = $envs->filter(function ($env) {
- return str($env)->startsWith('MYSQL_DATABASE=');
- })->first();
-
- if ($db) {
- $databasesToBackup = str($db)->after('MYSQL_DATABASE=')->value();
- } else {
- throw new \Exception('MYSQL_DATABASE not found');
- }
- } elseif (str($databaseType)->contains('mariadb')) {
- $this->container_name = "{$this->database->name}-$serviceUuid";
- $this->directory_name = $serviceName.'-'.$this->container_name;
- $commands[] = "docker exec $this->container_name env";
- $envs = instant_remote_process($commands, $this->server);
- $envs = str($envs)->explode("\n");
- $rootPassword = $envs->filter(function ($env) {
- return str($env)->startsWith('MARIADB_ROOT_PASSWORD=');
- })->first();
- if ($rootPassword) {
- $this->database->mariadb_root_password = str($rootPassword)->after('MARIADB_ROOT_PASSWORD=')->value();
- } else {
- $rootPassword = $envs->filter(function ($env) {
- return str($env)->startsWith('MYSQL_ROOT_PASSWORD=');
- })->first();
- if ($rootPassword) {
- $this->database->mariadb_root_password = str($rootPassword)->after('MYSQL_ROOT_PASSWORD=')->value();
- }
- }
-
- $db = $envs->filter(function ($env) {
- return str($env)->startsWith('MARIADB_DATABASE=');
- })->first();
-
- if ($db) {
- $databasesToBackup = str($db)->after('MARIADB_DATABASE=')->value();
- } else {
- $db = $envs->filter(function ($env) {
- return str($env)->startsWith('MYSQL_DATABASE=');
- })->first();
-
- if ($db) {
- $databasesToBackup = str($db)->after('MYSQL_DATABASE=')->value();
- } else {
- throw new \Exception('MARIADB_DATABASE or MYSQL_DATABASE not found');
- }
- }
- }
- } else {
- $databaseName = str($this->database->name)->slug()->value();
- $this->container_name = $this->database->uuid;
- $this->directory_name = $databaseName.'-'.$this->container_name;
- $databaseType = $this->database->type();
- $databasesToBackup = data_get($this->backup, 'databases_to_backup');
- }
- if (blank($databasesToBackup)) {
- if (str($databaseType)->contains('postgres')) {
- $databasesToBackup = [$this->database->postgres_db];
- } elseif (str($databaseType)->contains('mongodb')) {
- $databasesToBackup = ['*'];
- } elseif (str($databaseType)->contains('mysql')) {
- $databasesToBackup = [$this->database->mysql_database];
- } elseif (str($databaseType)->contains('mariadb')) {
- $databasesToBackup = [$this->database->mariadb_database];
- } else {
- return;
- }
- } else {
- if (str($databaseType)->contains('postgres')) {
- // Format: db1,db2,db3
- $databasesToBackup = explode(',', $databasesToBackup);
- $databasesToBackup = array_map('trim', $databasesToBackup);
- } elseif (str($databaseType)->contains('mongodb')) {
- // Format: db1:collection1,collection2|db2:collection3,collection4
- $databasesToBackup = explode('|', $databasesToBackup);
- $databasesToBackup = array_map('trim', $databasesToBackup);
- } elseif (str($databaseType)->contains('mysql')) {
- // Format: db1,db2,db3
- $databasesToBackup = explode(',', $databasesToBackup);
- $databasesToBackup = array_map('trim', $databasesToBackup);
- } elseif (str($databaseType)->contains('mariadb')) {
- // Format: db1,db2,db3
- $databasesToBackup = explode(',', $databasesToBackup);
- $databasesToBackup = array_map('trim', $databasesToBackup);
- } else {
- return;
- }
- }
- $this->backup_dir = backup_dir().'/databases/'.str($this->team->name)->slug().'-'.$this->team->id.'/'.$this->directory_name;
- if ($this->database->name === 'coolify-db') {
- $databasesToBackup = ['coolify'];
- $this->directory_name = $this->container_name = 'coolify-db';
- $ip = Str::slug($this->server->ip);
- $this->backup_dir = backup_dir().'/coolify'."/coolify-db-$ip";
- }
- foreach ($databasesToBackup as $database) {
- $size = 0;
- try {
- if (str($databaseType)->contains('postgres')) {
- $this->backup_file = "/pg-dump-$database-".Carbon::now()->timestamp.'.dmp';
- if ($this->backup->dump_all) {
- $this->backup_file = '/pg-dump-all-'.Carbon::now()->timestamp.'.gz';
- }
- $this->backup_location = $this->backup_dir.$this->backup_file;
- $this->backup_log = ScheduledDatabaseBackupExecution::create([
- 'database_name' => $database,
- 'filename' => $this->backup_location,
- 'scheduled_database_backup_id' => $this->backup->id,
- ]);
- $this->backup_standalone_postgresql($database);
- } elseif (str($databaseType)->contains('mongodb')) {
- if ($database === '*') {
- $database = 'all';
- $databaseName = 'all';
- } else {
- if (str($database)->contains(':')) {
- $databaseName = str($database)->before(':');
- } else {
- $databaseName = $database;
- }
- }
- $this->backup_file = "/mongo-dump-$databaseName-".Carbon::now()->timestamp.'.tar.gz';
- $this->backup_location = $this->backup_dir.$this->backup_file;
- $this->backup_log = ScheduledDatabaseBackupExecution::create([
- 'database_name' => $databaseName,
- 'filename' => $this->backup_location,
- 'scheduled_database_backup_id' => $this->backup->id,
- ]);
- $this->backup_standalone_mongodb($database);
- } elseif (str($databaseType)->contains('mysql')) {
- $this->backup_file = "/mysql-dump-$database-".Carbon::now()->timestamp.'.dmp';
- if ($this->backup->dump_all) {
- $this->backup_file = '/mysql-dump-all-'.Carbon::now()->timestamp.'.gz';
- }
- $this->backup_location = $this->backup_dir.$this->backup_file;
- $this->backup_log = ScheduledDatabaseBackupExecution::create([
- 'database_name' => $database,
- 'filename' => $this->backup_location,
- 'scheduled_database_backup_id' => $this->backup->id,
- ]);
- $this->backup_standalone_mysql($database);
- } elseif (str($databaseType)->contains('mariadb')) {
- $this->backup_file = "/mariadb-dump-$database-".Carbon::now()->timestamp.'.dmp';
- if ($this->backup->dump_all) {
- $this->backup_file = '/mariadb-dump-all-'.Carbon::now()->timestamp.'.gz';
- }
- $this->backup_location = $this->backup_dir.$this->backup_file;
- $this->backup_log = ScheduledDatabaseBackupExecution::create([
- 'database_name' => $database,
- 'filename' => $this->backup_location,
- 'scheduled_database_backup_id' => $this->backup->id,
- ]);
- $this->backup_standalone_mariadb($database);
- } else {
- throw new \Exception('Unsupported database type');
- }
- $size = $this->calculate_size();
- if ($this->backup->save_s3) {
- $this->upload_to_s3();
- }
-
- $this->team->notify(new BackupSuccess($this->backup, $this->database, $database));
-
- $this->backup_log->update([
- 'status' => 'success',
- 'message' => $this->backup_output,
- 'size' => $size,
- ]);
- } catch (\Throwable $e) {
- if ($this->backup_log) {
- $this->backup_log->update([
- 'status' => 'failed',
- 'message' => $this->backup_output,
- 'size' => $size,
- 'filename' => null,
- ]);
- }
- $this->team?->notify(new BackupFailed($this->backup, $this->database, $this->backup_output, $database));
- }
- }
- if ($this->backup_log && $this->backup_log->status === 'success') {
- removeOldBackups($this->backup);
- }
- } catch (\Throwable $e) {
- throw $e;
- } finally {
- if ($this->team) {
- BackupCreated::dispatch($this->team->id);
- }
- if ($this->backup_log) {
- $this->backup_log->update([
- 'finished_at' => Carbon::now()->toImmutable(),
- ]);
- }
- }
- }
-
- private function backup_standalone_mongodb(string $databaseWithCollections): void
- {
- try {
- $url = $this->database->internal_db_url;
- if ($databaseWithCollections === 'all') {
- $commands[] = 'mkdir -p '.$this->backup_dir;
- if (str($this->database->image)->startsWith('mongo:4')) {
- $commands[] = "docker exec $this->container_name mongodump --uri=\"$url\" --gzip --archive > $this->backup_location";
- } else {
- $commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=\"$url\" --gzip --archive > $this->backup_location";
- }
- } else {
- if (str($databaseWithCollections)->contains(':')) {
- $databaseName = str($databaseWithCollections)->before(':');
- $collectionsToExclude = str($databaseWithCollections)->after(':')->explode(',');
- } else {
- $databaseName = $databaseWithCollections;
- $collectionsToExclude = collect();
- }
- $commands[] = 'mkdir -p '.$this->backup_dir;
- if ($collectionsToExclude->count() === 0) {
- if (str($this->database->image)->startsWith('mongo:4')) {
- $commands[] = "docker exec $this->container_name mongodump --uri=\"$url\" --gzip --archive > $this->backup_location";
- } else {
- $commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=\"$url\" --db $databaseName --gzip --archive > $this->backup_location";
- }
- } else {
- if (str($this->database->image)->startsWith('mongo:4')) {
- $commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --excludeCollection ".$collectionsToExclude->implode(' --excludeCollection ')." --archive > $this->backup_location";
- } else {
- $commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=\"$url\" --db $databaseName --gzip --excludeCollection ".$collectionsToExclude->implode(' --excludeCollection ')." --archive > $this->backup_location";
- }
- }
- }
- $this->backup_output = instant_remote_process($commands, $this->server);
- $this->backup_output = trim($this->backup_output);
- if ($this->backup_output === '') {
- $this->backup_output = null;
- }
- } catch (\Throwable $e) {
- $this->add_to_backup_output($e->getMessage());
- throw $e;
- }
- }
-
- private function backup_standalone_postgresql(string $database): void
- {
- try {
- $commands[] = 'mkdir -p '.$this->backup_dir;
- $backupCommand = 'docker exec';
- if ($this->postgres_password) {
- $backupCommand .= " -e PGPASSWORD=$this->postgres_password";
- }
- if ($this->backup->dump_all) {
- $backupCommand .= " $this->container_name pg_dumpall --username {$this->database->postgres_user} | gzip > $this->backup_location";
- } else {
- $backupCommand .= " $this->container_name pg_dump --format=custom --no-acl --no-owner --username {$this->database->postgres_user} $database > $this->backup_location";
- }
-
- $commands[] = $backupCommand;
- $this->backup_output = instant_remote_process($commands, $this->server);
- $this->backup_output = trim($this->backup_output);
- if ($this->backup_output === '') {
- $this->backup_output = null;
- }
- } catch (\Throwable $e) {
- $this->add_to_backup_output($e->getMessage());
- throw $e;
- }
- }
-
- private function backup_standalone_mysql(string $database): void
- {
- try {
- $commands[] = 'mkdir -p '.$this->backup_dir;
- if ($this->backup->dump_all) {
- $commands[] = "docker exec $this->container_name mysqldump -u root -p\"{$this->database->mysql_root_password}\" --all-databases --single-transaction --quick --lock-tables=false --compress | gzip > $this->backup_location";
- } else {
- $commands[] = "docker exec $this->container_name mysqldump -u root -p\"{$this->database->mysql_root_password}\" $database > $this->backup_location";
- }
- $this->backup_output = instant_remote_process($commands, $this->server);
- $this->backup_output = trim($this->backup_output);
- if ($this->backup_output === '') {
- $this->backup_output = null;
- }
- } catch (\Throwable $e) {
- $this->add_to_backup_output($e->getMessage());
- throw $e;
- }
- }
-
- private function backup_standalone_mariadb(string $database): void
- {
- try {
- $commands[] = 'mkdir -p '.$this->backup_dir;
- if ($this->backup->dump_all) {
- $commands[] = "docker exec $this->container_name mariadb-dump -u root -p\"{$this->database->mariadb_root_password}\" --all-databases --single-transaction --quick --lock-tables=false --compress > $this->backup_location";
- } else {
- $commands[] = "docker exec $this->container_name mariadb-dump -u root -p\"{$this->database->mariadb_root_password}\" $database > $this->backup_location";
- }
- $this->backup_output = instant_remote_process($commands, $this->server);
- $this->backup_output = trim($this->backup_output);
- if ($this->backup_output === '') {
- $this->backup_output = null;
- }
- } catch (\Throwable $e) {
- $this->add_to_backup_output($e->getMessage());
- throw $e;
- }
- }
-
- private function add_to_backup_output($output): void
- {
- if ($this->backup_output) {
- $this->backup_output = $this->backup_output."\n".$output;
- } else {
- $this->backup_output = $output;
- }
- }
-
- private function calculate_size()
- {
- return instant_remote_process(["du -b $this->backup_location | cut -f1"], $this->server, false);
- }
-
- private function upload_to_s3(): void
- {
- try {
- if (is_null($this->s3)) {
- return;
- }
- $key = $this->s3->key;
- $secret = $this->s3->secret;
- // $region = $this->s3->region;
- $bucket = $this->s3->bucket;
- $endpoint = $this->s3->endpoint;
- $this->s3->testConnection(shouldSave: true);
- if (data_get($this->backup, 'database_type') === \App\Models\ServiceDatabase::class) {
- $network = $this->database->service->destination->network;
- } else {
- $network = $this->database->destination->network;
- }
-
- $fullImageName = $this->getFullImageName();
-
- if (isDev()) {
- if ($this->database->name === 'coolify-db') {
- $backup_location_from = '/var/lib/docker/volumes/coolify_dev_backups_data/_data/coolify/coolify-db-'.$this->server->ip.$this->backup_file;
- $commands[] = "docker run -d --network {$network} --name backup-of-{$this->backup->uuid} --rm -v $backup_location_from:$this->backup_location:ro {$fullImageName}";
- } else {
- $backup_location_from = '/var/lib/docker/volumes/coolify_dev_backups_data/_data/databases/'.str($this->team->name)->slug().'-'.$this->team->id.'/'.$this->directory_name.$this->backup_file;
- $commands[] = "docker run -d --network {$network} --name backup-of-{$this->backup->uuid} --rm -v $backup_location_from:$this->backup_location:ro {$fullImageName}";
- }
- } else {
- $commands[] = "docker run -d --network {$network} --name backup-of-{$this->backup->uuid} --rm -v $this->backup_location:$this->backup_location:ro {$fullImageName}";
- }
- $commands[] = "docker exec backup-of-{$this->backup->uuid} mc config host add temporary {$endpoint} $key \"$secret\"";
- $commands[] = "docker exec backup-of-{$this->backup->uuid} mc cp $this->backup_location temporary/$bucket{$this->backup_dir}/";
- instant_remote_process($commands, $this->server);
-
- $this->add_to_backup_output('Uploaded to S3.');
- } catch (\Throwable $e) {
- $this->add_to_backup_output($e->getMessage());
- throw $e;
- } finally {
- $command = "docker rm -f backup-of-{$this->backup->uuid}";
- instant_remote_process([$command], $this->server);
- }
- }
-
- private function getFullImageName(): string
- {
- $settings = instanceSettings();
- $helperImage = config('constants.coolify.helper_image');
- $latestVersion = $settings->helper_version;
-
- return "{$helperImage}:{$latestVersion}";
- }
-}
diff --git a/app/Jobs/DeleteResourceJob.php b/app/Jobs/DeleteResourceJob.php
deleted file mode 100644
index 8b9228e5f5..0000000000
--- a/app/Jobs/DeleteResourceJob.php
+++ /dev/null
@@ -1,101 +0,0 @@
-onQueue('high');
- }
-
- public function handle()
- {
- try {
- $persistentStorages = collect();
- switch ($this->resource->type()) {
- case 'application':
- $persistentStorages = $this->resource?->persistentStorages()?->get();
- StopApplication::run($this->resource, previewDeployments: true);
- break;
- case 'standalone-postgresql':
- case 'standalone-redis':
- case 'standalone-mongodb':
- case 'standalone-mysql':
- case 'standalone-mariadb':
- case 'standalone-keydb':
- case 'standalone-dragonfly':
- case 'standalone-clickhouse':
- $persistentStorages = $this->resource?->persistentStorages()?->get();
- StopDatabase::run($this->resource, true);
- break;
- case 'service':
- StopService::run($this->resource, true);
- DeleteService::run($this->resource, $this->deleteConfigurations, $this->deleteVolumes, $this->dockerCleanup, $this->deleteConnectedNetworks);
- break;
- }
-
- if ($this->deleteVolumes && $this->resource->type() !== 'service') {
- $this->resource?->delete_volumes($persistentStorages);
- }
- if ($this->deleteConfigurations) {
- $this->resource?->delete_configurations();
- }
-
- $isDatabase = $this->resource instanceof StandalonePostgresql
- || $this->resource instanceof StandaloneRedis
- || $this->resource instanceof StandaloneMongodb
- || $this->resource instanceof StandaloneMysql
- || $this->resource instanceof StandaloneMariadb
- || $this->resource instanceof StandaloneKeydb
- || $this->resource instanceof StandaloneDragonfly
- || $this->resource instanceof StandaloneClickhouse;
- $server = data_get($this->resource, 'server') ?? data_get($this->resource, 'destination.server');
- if (($this->dockerCleanup || $isDatabase) && $server) {
- CleanupDocker::dispatch($server, true);
- }
-
- if ($this->deleteConnectedNetworks && ! $isDatabase) {
- $this->resource?->delete_connected_networks($this->resource->uuid);
- }
- } catch (\Throwable $e) {
- throw $e;
- } finally {
- $this->resource->forceDelete();
- if ($this->dockerCleanup) {
- CleanupDocker::dispatch($server, true);
- }
- Artisan::queue('cleanup:stucked-resources');
- }
- }
-}
diff --git a/app/Jobs/DockerCleanupJob.php b/app/Jobs/DockerCleanupJob.php
deleted file mode 100644
index 05a4aa8de2..0000000000
--- a/app/Jobs/DockerCleanupJob.php
+++ /dev/null
@@ -1,131 +0,0 @@
-server->uuid))->dontRelease()];
- }
-
- public function __construct(public Server $server, public bool $manualCleanup = false) {}
-
- public function handle(): void
- {
- try {
- if (! $this->server->isFunctional()) {
- return;
- }
-
- $this->execution_log = DockerCleanupExecution::create([
- 'server_id' => $this->server->id,
- ]);
-
- $this->usageBefore = $this->server->getDiskUsage();
-
- if ($this->manualCleanup || $this->server->settings->force_docker_cleanup) {
- $cleanup_log = CleanupDocker::run(server: $this->server);
- $usageAfter = $this->server->getDiskUsage();
- $message = ($this->manualCleanup ? 'Manual' : 'Forced').' Docker cleanup job executed successfully. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.';
-
- $this->execution_log->update([
- 'status' => 'success',
- 'message' => $message,
- 'cleanup_log' => $cleanup_log,
- ]);
-
- $this->server->team?->notify(new DockerCleanupSuccess($this->server, $message));
- event(new DockerCleanupDone($this->execution_log));
-
- return;
- }
-
- if (str($this->usageBefore)->isEmpty() || $this->usageBefore === null || $this->usageBefore === 0) {
- $cleanup_log = CleanupDocker::run(server: $this->server);
- $message = 'Docker cleanup job executed successfully, but no disk usage could be determined.';
-
- $this->execution_log->update([
- 'status' => 'success',
- 'message' => $message,
- 'cleanup_log' => $cleanup_log,
- ]);
-
- $this->server->team?->notify(new DockerCleanupSuccess($this->server, $message));
- event(new DockerCleanupDone($this->execution_log));
- }
-
- if ($this->usageBefore >= $this->server->settings->docker_cleanup_threshold) {
- $cleanup_log = CleanupDocker::run(server: $this->server);
- $usageAfter = $this->server->getDiskUsage();
- $diskSaved = $this->usageBefore - $usageAfter;
-
- if ($diskSaved > 0) {
- $message = 'Saved '.$diskSaved.'% disk space. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.';
- } else {
- $message = 'Docker cleanup job executed successfully, but no disk space was saved. Disk usage before: '.$this->usageBefore.'%, Disk usage after: '.$usageAfter.'%.';
- }
-
- $this->execution_log->update([
- 'status' => 'success',
- 'message' => $message,
- 'cleanup_log' => $cleanup_log,
- ]);
-
- $this->server->team?->notify(new DockerCleanupSuccess($this->server, $message));
- event(new DockerCleanupDone($this->execution_log));
- } else {
- $message = 'No cleanup needed for '.$this->server->name;
-
- $this->execution_log->update([
- 'status' => 'success',
- 'message' => $message,
- ]);
-
- $this->server->team?->notify(new DockerCleanupSuccess($this->server, $message));
- event(new DockerCleanupDone($this->execution_log));
- }
- } catch (\Throwable $e) {
- if ($this->execution_log) {
- $this->execution_log->update([
- 'status' => 'failed',
- 'message' => $e->getMessage(),
- ]);
- event(new DockerCleanupDone($this->execution_log));
- }
- $this->server->team?->notify(new DockerCleanupFailed($this->server, 'Docker cleanup job failed with the following error: '.$e->getMessage()));
- throw $e;
- } finally {
- if ($this->execution_log) {
- $this->execution_log->update([
- 'finished_at' => Carbon::now()->toImmutable(),
- ]);
- }
- }
- }
-}
diff --git a/app/Jobs/GithubAppPermissionJob.php b/app/Jobs/GithubAppPermissionJob.php
deleted file mode 100644
index 7cd1b86ac0..0000000000
--- a/app/Jobs/GithubAppPermissionJob.php
+++ /dev/null
@@ -1,57 +0,0 @@
-github_app);
-
- $response = Http::withHeaders([
- 'Authorization' => "Bearer $github_access_token",
- 'Accept' => 'application/vnd.github+json',
- ])->get("{$this->github_app->api_url}/app");
-
- if (! $response->successful()) {
- throw new \RuntimeException('Failed to fetch GitHub app permissions: '.$response->body());
- }
-
- $response = $response->json();
- $permissions = data_get($response, 'permissions');
-
- $this->github_app->contents = data_get($permissions, 'contents');
- $this->github_app->metadata = data_get($permissions, 'metadata');
- $this->github_app->pull_requests = data_get($permissions, 'pull_requests');
- $this->github_app->administration = data_get($permissions, 'administration');
-
- $this->github_app->save();
- $this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
-
- } catch (\Throwable $e) {
- send_internal_notification('GithubAppPermissionJob failed with: '.$e->getMessage());
- throw $e;
- }
- }
-}
diff --git a/app/Jobs/PullHelperImageJob.php b/app/Jobs/PullHelperImageJob.php
deleted file mode 100644
index b92886d388..0000000000
--- a/app/Jobs/PullHelperImageJob.php
+++ /dev/null
@@ -1,30 +0,0 @@
-onQueue('high');
- }
-
- public function handle(): void
- {
- $helperImage = config('constants.coolify.helper_image');
- $latest_version = instanceSettings()->helper_version;
- instant_remote_process(["docker pull -q {$helperImage}:{$latest_version}"], $this->server, false);
- }
-}
diff --git a/app/Jobs/PullTemplatesFromCDN.php b/app/Jobs/PullTemplatesFromCDN.php
deleted file mode 100644
index 9a4c991bc6..0000000000
--- a/app/Jobs/PullTemplatesFromCDN.php
+++ /dev/null
@@ -1,42 +0,0 @@
-onQueue('high');
- }
-
- public function handle(): void
- {
- try {
- if (isDev()) {
- return;
- }
- $response = Http::retry(3, 1000)->get(config('constants.services.official'));
- if ($response->successful()) {
- $services = $response->json();
- File::put(base_path('templates/service-templates.json'), json_encode($services));
- } else {
- send_internal_notification('PullTemplatesAndVersions failed with: '.$response->status().' '.$response->body());
- }
- } catch (\Throwable $e) {
- send_internal_notification('PullTemplatesAndVersions failed with: '.$e->getMessage());
- }
- }
-}
diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php
deleted file mode 100644
index 93b203fcbd..0000000000
--- a/app/Jobs/PushServerUpdateJob.php
+++ /dev/null
@@ -1,372 +0,0 @@
-server->uuid))->dontRelease()];
- }
-
- public function backoff(): int
- {
- return isDev() ? 1 : 3;
- }
-
- public function __construct(public Server $server, public $data)
- {
- $this->containers = collect();
- $this->foundApplicationIds = collect();
- $this->foundDatabaseUuids = collect();
- $this->foundServiceApplicationIds = collect();
- $this->foundApplicationPreviewsIds = collect();
- $this->foundServiceDatabaseIds = collect();
- $this->allApplicationIds = collect();
- $this->allDatabaseUuids = collect();
- $this->allTcpProxyUuids = collect();
- $this->allServiceApplicationIds = collect();
- $this->allServiceDatabaseIds = collect();
- }
-
- public function handle()
- {
- // TODO: Swarm is not supported yet
- if (! $this->data) {
- throw new \Exception('No data provided');
- }
- $data = collect($this->data);
-
- $this->server->sentinelHeartbeat();
-
- $this->containers = collect(data_get($data, 'containers'));
-
- $filesystemUsageRoot = data_get($data, 'filesystem_usage_root.used_percentage');
- ServerStorageCheckJob::dispatch($this->server, $filesystemUsageRoot);
-
- if ($this->containers->isEmpty()) {
- return;
- }
- $this->applications = $this->server->applications();
- $this->databases = $this->server->databases();
- $this->previews = $this->server->previews();
- $this->services = $this->server->services()->get();
- $this->allApplicationIds = $this->applications->filter(function ($application) {
- return $application->additional_servers->count() === 0;
- })->pluck('id');
- $this->allApplicationsWithAdditionalServers = $this->applications->filter(function ($application) {
- return $application->additional_servers->count() > 0;
- });
- $this->allApplicationPreviewsIds = $this->previews->pluck('id');
- $this->allDatabaseUuids = $this->databases->pluck('uuid');
- $this->allTcpProxyUuids = $this->databases->where('is_public', true)->pluck('uuid');
- $this->services->each(function ($service) {
- $service->applications()->pluck('id')->each(function ($applicationId) {
- $this->allServiceApplicationIds->push($applicationId);
- });
- $service->databases()->pluck('id')->each(function ($databaseId) {
- $this->allServiceDatabaseIds->push($databaseId);
- });
- });
-
- foreach ($this->containers as $container) {
- $containerStatus = data_get($container, 'state', 'exited');
- $containerHealth = data_get($container, 'health_status', 'unhealthy');
- $containerStatus = "$containerStatus ($containerHealth)";
- $labels = collect(data_get($container, 'labels'));
- $coolify_managed = $labels->has('coolify.managed');
- if ($coolify_managed) {
- $name = data_get($container, 'name');
- if ($name === 'coolify-log-drain' && $this->isRunning($containerStatus)) {
- $this->foundLogDrainContainer = true;
- }
- if ($labels->has('coolify.applicationId')) {
- $applicationId = $labels->get('coolify.applicationId');
- $pullRequestId = data_get($labels, 'coolify.pullRequestId', '0');
- try {
- if ($pullRequestId === '0') {
- if ($this->allApplicationIds->contains($applicationId) && $this->isRunning($containerStatus)) {
- $this->foundApplicationIds->push($applicationId);
- }
- $this->updateApplicationStatus($applicationId, $containerStatus);
- } else {
- if ($this->allApplicationPreviewsIds->contains($applicationId) && $this->isRunning($containerStatus)) {
- $this->foundApplicationPreviewsIds->push($applicationId);
- }
- $this->updateApplicationPreviewStatus($applicationId, $containerStatus);
- }
- } catch (\Exception $e) {
- }
- } elseif ($labels->has('coolify.serviceId')) {
- $serviceId = $labels->get('coolify.serviceId');
- $subType = $labels->get('coolify.service.subType');
- $subId = $labels->get('coolify.service.subId');
- if ($subType === 'application' && $this->isRunning($containerStatus)) {
- $this->foundServiceApplicationIds->push($subId);
- $this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus);
- } elseif ($subType === 'database' && $this->isRunning($containerStatus)) {
- $this->foundServiceDatabaseIds->push($subId);
- $this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus);
- }
- } else {
- $uuid = $labels->get('com.docker.compose.service');
- $type = $labels->get('coolify.type');
- if ($name === 'coolify-proxy' && $this->isRunning($containerStatus)) {
- $this->foundProxy = true;
- } elseif ($type === 'service' && $this->isRunning($containerStatus)) {
- } else {
- if ($this->allDatabaseUuids->contains($uuid) && $this->isRunning($containerStatus)) {
- $this->foundDatabaseUuids->push($uuid);
- if ($this->allTcpProxyUuids->contains($uuid) && $this->isRunning($containerStatus)) {
- $this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: true);
- } else {
- $this->updateDatabaseStatus($uuid, $containerStatus, tcpProxy: false);
- }
- }
- }
- }
- }
- }
-
- $this->updateProxyStatus();
-
- $this->updateNotFoundApplicationStatus();
- $this->updateNotFoundApplicationPreviewStatus();
- $this->updateNotFoundDatabaseStatus();
- $this->updateNotFoundServiceStatus();
-
- $this->updateAdditionalServersStatus();
-
- $this->checkLogDrainContainer();
- }
-
- private function updateApplicationStatus(string $applicationId, string $containerStatus)
- {
- $application = $this->applications->where('id', $applicationId)->first();
- if (! $application) {
- return;
- }
- $application->status = $containerStatus;
- $application->save();
- }
-
- private function updateApplicationPreviewStatus(string $applicationId, string $containerStatus)
- {
- $application = $this->previews->where('id', $applicationId)->first();
- if (! $application) {
- return;
- }
- $application->status = $containerStatus;
- $application->save();
- }
-
- private function updateNotFoundApplicationStatus()
- {
- $notFoundApplicationIds = $this->allApplicationIds->diff($this->foundApplicationIds);
- if ($notFoundApplicationIds->isNotEmpty()) {
- $notFoundApplicationIds->each(function ($applicationId) {
- $application = Application::find($applicationId);
- if ($application) {
- $application->status = 'exited';
- $application->save();
- }
- });
- }
- }
-
- private function updateNotFoundApplicationPreviewStatus()
- {
- $notFoundApplicationPreviewsIds = $this->allApplicationPreviewsIds->diff($this->foundApplicationPreviewsIds);
- if ($notFoundApplicationPreviewsIds->isNotEmpty()) {
- $notFoundApplicationPreviewsIds->each(function ($applicationPreviewId) {
- $applicationPreview = ApplicationPreview::find($applicationPreviewId);
- if ($applicationPreview) {
- $applicationPreview->status = 'exited';
- $applicationPreview->save();
- }
- });
- }
- }
-
- private function updateProxyStatus()
- {
- // If proxy is not found, start it
- if ($this->server->isProxyShouldRun()) {
- if ($this->foundProxy === false) {
- try {
- if (CheckProxy::run($this->server)) {
- StartProxy::run($this->server, false);
- $this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server));
- }
- } catch (\Throwable $e) {
- }
- } else {
- $connectProxyToDockerNetworks = connectProxyToNetworks($this->server);
- instant_remote_process($connectProxyToDockerNetworks, $this->server, false);
- }
- }
- }
-
- private function updateDatabaseStatus(string $databaseUuid, string $containerStatus, bool $tcpProxy = false)
- {
- $database = $this->databases->where('uuid', $databaseUuid)->first();
- if (! $database) {
- return;
- }
- $database->status = $containerStatus;
- $database->save();
- if ($this->isRunning($containerStatus) && $tcpProxy) {
- $tcpProxyContainerFound = $this->containers->filter(function ($value, $key) use ($databaseUuid) {
- return data_get($value, 'name') === "$databaseUuid-proxy" && data_get($value, 'state') === 'running';
- })->first();
- if (! $tcpProxyContainerFound) {
- StartDatabaseProxy::dispatch($database);
- $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server));
- } else {
- }
- }
- }
-
- private function updateNotFoundDatabaseStatus()
- {
- $notFoundDatabaseUuids = $this->allDatabaseUuids->diff($this->foundDatabaseUuids);
- if ($notFoundDatabaseUuids->isNotEmpty()) {
- $notFoundDatabaseUuids->each(function ($databaseUuid) {
- $database = $this->databases->where('uuid', $databaseUuid)->first();
- if ($database) {
- $database->status = 'exited';
- $database->save();
- if ($database->is_public) {
- StopDatabaseProxy::dispatch($database);
- }
- }
- });
- }
- }
-
- private function updateServiceSubStatus(string $serviceId, string $subType, string $subId, string $containerStatus)
- {
- $service = $this->services->where('id', $serviceId)->first();
- if (! $service) {
- return;
- }
- if ($subType === 'application') {
- $application = $service->applications()->where('id', $subId)->first();
- $application->status = $containerStatus;
- $application->save();
- } elseif ($subType === 'database') {
- $database = $service->databases()->where('id', $subId)->first();
- $database->status = $containerStatus;
- $database->save();
- } else {
- }
- }
-
- private function updateNotFoundServiceStatus()
- {
- $notFoundServiceApplicationIds = $this->allServiceApplicationIds->diff($this->foundServiceApplicationIds);
- $notFoundServiceDatabaseIds = $this->allServiceDatabaseIds->diff($this->foundServiceDatabaseIds);
- if ($notFoundServiceApplicationIds->isNotEmpty()) {
- $notFoundServiceApplicationIds->each(function ($serviceApplicationId) {
- $application = ServiceApplication::find($serviceApplicationId);
- if ($application) {
- $application->status = 'exited';
- $application->save();
- }
- });
- }
- if ($notFoundServiceDatabaseIds->isNotEmpty()) {
- $notFoundServiceDatabaseIds->each(function ($serviceDatabaseId) {
- $database = ServiceDatabase::find($serviceDatabaseId);
- if ($database) {
- $database->status = 'exited';
- $database->save();
- }
- });
- }
- }
-
- private function updateAdditionalServersStatus()
- {
- $this->allApplicationsWithAdditionalServers->each(function ($application) {
- ComplexStatusCheck::run($application);
- });
- }
-
- private function isRunning(string $containerStatus)
- {
- return str($containerStatus)->contains('running');
- }
-
- private function checkLogDrainContainer()
- {
- if ($this->server->isLogDrainEnabled() && $this->foundLogDrainContainer === false) {
- StartLogDrain::dispatch($this->server);
- }
- }
-}
diff --git a/app/Jobs/ScheduledTaskJob.php b/app/Jobs/ScheduledTaskJob.php
deleted file mode 100644
index 6c0c017e73..0000000000
--- a/app/Jobs/ScheduledTaskJob.php
+++ /dev/null
@@ -1,142 +0,0 @@
-onQueue('high');
-
- $this->task = $task;
- if ($service = $task->service()->first()) {
- $this->resource = $service;
- } elseif ($application = $task->application()->first()) {
- $this->resource = $application;
- } else {
- throw new \RuntimeException('ScheduledTaskJob failed: No resource found.');
- }
- $this->team = Team::findOrFail($task->team_id);
- $this->server_timezone = $this->getServerTimezone();
- }
-
- private function getServerTimezone(): string
- {
- if ($this->resource instanceof Application) {
- return $this->resource->destination->server->settings->server_timezone;
- } elseif ($this->resource instanceof Service) {
- return $this->resource->server->settings->server_timezone;
- }
-
- return 'UTC';
- }
-
- public function handle(): void
- {
- try {
- $this->task_log = ScheduledTaskExecution::create([
- 'scheduled_task_id' => $this->task->id,
- ]);
-
- $this->server = $this->resource->destination->server;
-
- if ($this->resource->type() === 'application') {
- $containers = getCurrentApplicationContainerStatus($this->server, $this->resource->id, 0);
- if ($containers->count() > 0) {
- $containers->each(function ($container) {
- $this->containers[] = str_replace('/', '', $container['Names']);
- });
- }
- } elseif ($this->resource->type() === 'service') {
- $this->resource->applications()->get()->each(function ($application) {
- if (str(data_get($application, 'status'))->contains('running')) {
- $this->containers[] = data_get($application, 'name').'-'.data_get($this->resource, 'uuid');
- }
- });
- $this->resource->databases()->get()->each(function ($database) {
- if (str(data_get($database, 'status'))->contains('running')) {
- $this->containers[] = data_get($database, 'name').'-'.data_get($this->resource, 'uuid');
- }
- });
- }
- if (count($this->containers) == 0) {
- throw new \Exception('ScheduledTaskJob failed: No containers running.');
- }
-
- if (count($this->containers) > 1 && empty($this->task->container)) {
- throw new \Exception('ScheduledTaskJob failed: More than one container exists but no container name was provided.');
- }
-
- foreach ($this->containers as $containerName) {
- if (count($this->containers) == 1 || str_starts_with($containerName, $this->task->container.'-'.$this->resource->uuid)) {
- $cmd = "sh -c '".str_replace("'", "'\''", $this->task->command)."'";
- $exec = "docker exec {$containerName} {$cmd}";
- $this->task_output = instant_remote_process([$exec], $this->server, true);
- $this->task_log->update([
- 'status' => 'success',
- 'message' => $this->task_output,
- ]);
-
- $this->team?->notify(new TaskSuccess($this->task, $this->task_output));
-
- return;
- }
- }
-
- // No valid container was found.
- throw new \Exception('ScheduledTaskJob failed: No valid container was found. Is the container name correct?');
- } catch (\Throwable $e) {
- if ($this->task_log) {
- $this->task_log->update([
- 'status' => 'failed',
- 'message' => $this->task_output ?? $e->getMessage(),
- ]);
- }
- $this->team?->notify(new TaskFailed($this->task, $e->getMessage()));
- throw $e;
- } finally {
- ScheduledTaskDone::dispatch($this->team->id);
- if ($this->task_log) {
- $this->task_log->update([
- 'finished_at' => Carbon::now()->toImmutable(),
- ]);
- }
- }
- }
-}
diff --git a/app/Jobs/SendMessageToDiscordJob.php b/app/Jobs/SendMessageToDiscordJob.php
deleted file mode 100644
index 99aeaeea27..0000000000
--- a/app/Jobs/SendMessageToDiscordJob.php
+++ /dev/null
@@ -1,46 +0,0 @@
-onQueue('high');
- }
-
- /**
- * Execute the job.
- */
- public function handle(): void
- {
- Http::post($this->webhookUrl, $this->message->toPayload());
- }
-}
diff --git a/app/Jobs/SendMessageToPushoverJob.php b/app/Jobs/SendMessageToPushoverJob.php
deleted file mode 100644
index e2a94cdaa0..0000000000
--- a/app/Jobs/SendMessageToPushoverJob.php
+++ /dev/null
@@ -1,50 +0,0 @@
-onQueue('high');
- }
-
- /**
- * Execute the job.
- */
- public function handle(): void
- {
- $response = Http::post('https://api.pushover.net/1/messages.json', $this->message->toPayload($this->token, $this->user));
- if ($response->failed()) {
- throw new \RuntimeException('Pushover notification failed with '.$response->status().' status code.'.$response->body());
- }
- }
-}
diff --git a/app/Jobs/SendMessageToSlackJob.php b/app/Jobs/SendMessageToSlackJob.php
deleted file mode 100644
index dd5335850b..0000000000
--- a/app/Jobs/SendMessageToSlackJob.php
+++ /dev/null
@@ -1,60 +0,0 @@
-onQueue('high');
- }
-
- public function handle(): void
- {
- Http::post($this->webhookUrl, [
- 'text' => $this->message->title,
- 'blocks' => [
- [
- 'type' => 'section',
- 'text' => [
- 'type' => 'plain_text',
- 'text' => 'Coolify Notification',
- ],
- ],
- ],
- 'attachments' => [
- [
- 'color' => $this->message->color,
- 'blocks' => [
- [
- 'type' => 'header',
- 'text' => [
- 'type' => 'plain_text',
- 'text' => $this->message->title,
- ],
- ],
- [
- 'type' => 'section',
- 'text' => [
- 'type' => 'mrkdwn',
- 'text' => $this->message->description,
- ],
- ],
- ],
- ],
- ],
- ]);
- }
-}
diff --git a/app/Jobs/SendMessageToTelegramJob.php b/app/Jobs/SendMessageToTelegramJob.php
deleted file mode 100644
index 6b0a64ae39..0000000000
--- a/app/Jobs/SendMessageToTelegramJob.php
+++ /dev/null
@@ -1,78 +0,0 @@
-onQueue('high');
- }
-
- /**
- * Execute the job.
- */
- public function handle(): void
- {
- $url = 'https://api.telegram.org/bot'.$this->token.'/sendMessage';
- $inlineButtons = [];
- if (! empty($this->buttons)) {
- foreach ($this->buttons as $button) {
- $buttonUrl = data_get($button, 'url');
- $text = data_get($button, 'text', 'Click here');
- if ($buttonUrl && Str::contains($buttonUrl, 'http://localhost')) {
- $buttonUrl = str_replace('http://localhost', config('app.url'), $buttonUrl);
- }
- $inlineButtons[] = [
- 'text' => $text,
- 'url' => $buttonUrl,
- ];
- }
- }
- $payload = [
- // 'parse_mode' => 'markdown',
- 'reply_markup' => json_encode([
- 'inline_keyboard' => [
- [...$inlineButtons],
- ],
- ]),
- 'chat_id' => $this->chatId,
- 'text' => $this->text,
- ];
- if ($this->threadId) {
- $payload['message_thread_id'] = $this->threadId;
- }
- $response = Http::post($url, $payload);
- if ($response->failed()) {
- throw new \RuntimeException('Telegram notification failed with '.$response->status().' status code.'.$response->body());
- }
- }
-}
diff --git a/app/Jobs/ServerCheckJob.php b/app/Jobs/ServerCheckJob.php
deleted file mode 100644
index 9818d5c6a0..0000000000
--- a/app/Jobs/ServerCheckJob.php
+++ /dev/null
@@ -1,103 +0,0 @@
-server->uuid))->dontRelease()];
- }
-
- public function __construct(public Server $server) {}
-
- public function handle()
- {
- try {
- if ($this->server->serverStatus() === false) {
- return 'Server is not reachable or not ready.';
- }
-
- if (! $this->server->isSwarmWorker() && ! $this->server->isBuildServer()) {
- ['containers' => $this->containers, 'containerReplicates' => $containerReplicates] = $this->server->getContainers();
- if (is_null($this->containers)) {
- return 'No containers found.';
- }
- GetContainersStatus::run($this->server, $this->containers, $containerReplicates);
-
- if ($this->server->isSentinelEnabled()) {
- CheckAndStartSentinelJob::dispatch($this->server);
- }
-
- if ($this->server->isLogDrainEnabled()) {
- $this->checkLogDrainContainer();
- }
-
- if ($this->server->proxySet() && ! $this->server->proxy->force_stop) {
- $this->server->proxyType();
- $foundProxyContainer = $this->containers->filter(function ($value, $key) {
- if ($this->server->isSwarm()) {
- return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik';
- } else {
- return data_get($value, 'Name') === '/coolify-proxy';
- }
- })->first();
- if (! $foundProxyContainer) {
- try {
- $shouldStart = CheckProxy::run($this->server);
- if ($shouldStart) {
- StartProxy::run($this->server, false);
- $this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server));
- }
- } catch (\Throwable $e) {
- }
- } else {
- $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status');
- $this->server->save();
- $connectProxyToDockerNetworks = connectProxyToNetworks($this->server);
- instant_remote_process($connectProxyToDockerNetworks, $this->server, false);
- }
- }
- }
- } catch (\Throwable $e) {
- return handleError($e);
- }
- }
-
- private function checkLogDrainContainer()
- {
- $foundLogDrainContainer = $this->containers->filter(function ($value, $key) {
- return data_get($value, 'Name') === '/coolify-log-drain';
- })->first();
- if ($foundLogDrainContainer) {
- $status = data_get($foundLogDrainContainer, 'State.Status');
- if ($status !== 'running') {
- StartLogDrain::dispatch($this->server);
- }
- } else {
- StartLogDrain::dispatch($this->server);
- }
- }
-}
diff --git a/app/Jobs/ServerCheckNewJob.php b/app/Jobs/ServerCheckNewJob.php
deleted file mode 100644
index 3e8e60a31d..0000000000
--- a/app/Jobs/ServerCheckNewJob.php
+++ /dev/null
@@ -1,34 +0,0 @@
-server);
- ResourcesCheck::dispatch($this->server);
- } catch (\Throwable $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Jobs/ServerCleanupMux.php b/app/Jobs/ServerCleanupMux.php
deleted file mode 100644
index b793c3eca6..0000000000
--- a/app/Jobs/ServerCleanupMux.php
+++ /dev/null
@@ -1,40 +0,0 @@
-server->serverStatus() === false) {
- return 'Server is not reachable or not ready.';
- }
- SshMultiplexingHelper::removeMuxFile($this->server);
- } catch (\Throwable $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Jobs/ServerFilesFromServerJob.php b/app/Jobs/ServerFilesFromServerJob.php
deleted file mode 100644
index 58455df2f4..0000000000
--- a/app/Jobs/ServerFilesFromServerJob.php
+++ /dev/null
@@ -1,28 +0,0 @@
-onQueue('high');
- }
-
- public function handle()
- {
- $this->resource->getFilesFromServer(isInit: true);
- }
-}
diff --git a/app/Jobs/ServerLimitCheckJob.php b/app/Jobs/ServerLimitCheckJob.php
deleted file mode 100644
index aa82c6dade..0000000000
--- a/app/Jobs/ServerLimitCheckJob.php
+++ /dev/null
@@ -1,55 +0,0 @@
-team->servers;
- $servers_count = $servers->count();
- $number_of_servers_to_disable = $servers_count - $this->team->limits;
- if ($number_of_servers_to_disable > 0) {
- $servers = $servers->sortbyDesc('created_at');
- $servers_to_disable = $servers->take($number_of_servers_to_disable);
- $servers_to_disable->each(function ($server) {
- $server->forceDisableServer();
- $this->team->notify(new ForceDisabled($server));
- });
- } elseif ($number_of_servers_to_disable === 0) {
- $servers->each(function ($server) {
- if ($server->isForceDisabled()) {
- $server->forceEnableServer();
- $this->team->notify(new ForceEnabled($server));
- }
- });
- }
- } catch (\Throwable $e) {
- send_internal_notification('ServerLimitCheckJob failed with: '.$e->getMessage());
-
- return handleError($e);
- }
- }
-}
diff --git a/app/Jobs/ServerStorageCheckJob.php b/app/Jobs/ServerStorageCheckJob.php
deleted file mode 100644
index 9a8d86be1e..0000000000
--- a/app/Jobs/ServerStorageCheckJob.php
+++ /dev/null
@@ -1,65 +0,0 @@
-server->isFunctional() === false) {
- return 'Server is not functional.';
- }
- $team = data_get($this->server, 'team');
- $serverDiskUsageNotificationThreshold = data_get($this->server, 'settings.server_disk_usage_notification_threshold');
-
- if (is_null($this->percentage)) {
- $this->percentage = $this->server->storageCheck();
- }
- if (! $this->percentage) {
- return 'No percentage could be retrieved.';
- }
- if ($this->percentage > $serverDiskUsageNotificationThreshold) {
- $executed = RateLimiter::attempt(
- 'high-disk-usage:'.$this->server->id,
- $maxAttempts = 0,
- function () use ($team, $serverDiskUsageNotificationThreshold) {
- $team->notify(new HighDiskUsage($this->server, $this->percentage, $serverDiskUsageNotificationThreshold));
- },
- $decaySeconds = 3600,
- );
-
- if (! $executed) {
- return 'Too many messages sent!';
- }
- } else {
- RateLimiter::hit('high-disk-usage:'.$this->server->id, 600);
- }
- } catch (\Throwable $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Jobs/ServerStorageSaveJob.php b/app/Jobs/ServerStorageSaveJob.php
deleted file mode 100644
index 17a293f94f..0000000000
--- a/app/Jobs/ServerStorageSaveJob.php
+++ /dev/null
@@ -1,26 +0,0 @@
-onQueue('high');
- }
-
- public function handle()
- {
- $this->localFileVolume->saveStorageOnServer();
- }
-}
diff --git a/app/Jobs/StripeProcessJob.php b/app/Jobs/StripeProcessJob.php
deleted file mode 100644
index f1c5bc1a8a..0000000000
--- a/app/Jobs/StripeProcessJob.php
+++ /dev/null
@@ -1,291 +0,0 @@
-onQueue('high');
- }
-
- public function handle(): void
- {
- try {
- $excludedPlans = config('subscription.stripe_excluded_plans');
-
- $type = data_get($this->event, 'type');
- $this->type = $type;
- $data = data_get($this->event, 'data.object');
- switch ($type) {
- case 'radar.early_fraud_warning.created':
- $stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key'));
- $id = data_get($data, 'id');
- $charge = data_get($data, 'charge');
- if ($charge) {
- $stripe->refunds->create(['charge' => $charge]);
- }
- $pi = data_get($data, 'payment_intent');
- $piData = $stripe->paymentIntents->retrieve($pi, []);
- $customerId = data_get($piData, 'customer');
- $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
- if ($subscription) {
- $subscriptionId = data_get($subscription, 'stripe_subscription_id');
- $stripe->subscriptions->cancel($subscriptionId, []);
- $subscription->update([
- 'stripe_invoice_paid' => false,
- ]);
- send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}");
- } else {
- send_internal_notification("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}");
- throw new \RuntimeException("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}");
- }
- break;
- case 'checkout.session.completed':
- $clientReferenceId = data_get($data, 'client_reference_id');
- if (is_null($clientReferenceId)) {
- send_internal_notification('Checkout session completed without client reference id.');
- break;
- }
- $userId = Str::before($clientReferenceId, ':');
- $teamId = Str::after($clientReferenceId, ':');
- $subscriptionId = data_get($data, 'subscription');
- $customerId = data_get($data, 'customer');
- $team = Team::find($teamId);
- $found = $team->members->where('id', $userId)->first();
- if (! $found->isAdmin()) {
- send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
- throw new \RuntimeException("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
- }
- $subscription = Subscription::where('team_id', $teamId)->first();
- if ($subscription) {
- // send_internal_notification('Old subscription activated for team: '.$teamId);
- $subscription->update([
- 'stripe_subscription_id' => $subscriptionId,
- 'stripe_customer_id' => $customerId,
- 'stripe_invoice_paid' => true,
- 'stripe_past_due' => false,
- ]);
- } else {
- // send_internal_notification('New subscription for team: '.$teamId);
- Subscription::create([
- 'team_id' => $teamId,
- 'stripe_subscription_id' => $subscriptionId,
- 'stripe_customer_id' => $customerId,
- 'stripe_invoice_paid' => true,
- 'stripe_past_due' => false,
- ]);
- }
- break;
- case 'invoice.paid':
- $customerId = data_get($data, 'customer');
- $planId = data_get($data, 'lines.data.0.plan.id');
- if (Str::contains($excludedPlans, $planId)) {
- send_internal_notification('Subscription excluded.');
- break;
- }
- $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
- if ($subscription) {
- $subscription->update([
- 'stripe_invoice_paid' => true,
- 'stripe_past_due' => false,
- ]);
- } else {
- throw new \RuntimeException("No subscription found for customer: {$customerId}");
- }
- break;
- case 'invoice.payment_failed':
- $customerId = data_get($data, 'customer');
- $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
- if (! $subscription) {
- send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: '.$customerId);
- throw new \RuntimeException("No subscription found for customer: {$customerId}");
- }
- $team = data_get($subscription, 'team');
- if (! $team) {
- send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: '.$customerId);
- throw new \RuntimeException("No team found in Coolify for customer: {$customerId}");
- }
- if (! $subscription->stripe_invoice_paid) {
- SubscriptionInvoiceFailedJob::dispatch($team);
- // send_internal_notification('Invoice payment failed: '.$customerId);
- }
- break;
- case 'payment_intent.payment_failed':
- $customerId = data_get($data, 'customer');
- $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
- if (! $subscription) {
- send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: '.$customerId);
- throw new \RuntimeException("No subscription found in Coolify for customer: {$customerId}");
- }
- if ($subscription->stripe_invoice_paid) {
- send_internal_notification('payment_intent.payment_failed but invoice is active for customer: '.$customerId);
-
- return;
- }
- // send_internal_notification('Subscription payment failed for customer: '.$customerId);
- break;
- case 'customer.subscription.created':
- $customerId = data_get($data, 'customer');
- $subscriptionId = data_get($data, 'id');
- $teamId = data_get($data, 'metadata.team_id');
- $userId = data_get($data, 'metadata.user_id');
- if (! $teamId || ! $userId) {
- $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
- if ($subscription) {
- throw new \RuntimeException("Subscription already exists for customer: {$customerId}");
- }
- throw new \RuntimeException('No team id or user id found');
- }
- $team = Team::find($teamId);
- $found = $team->members->where('id', $userId)->first();
- if (! $found->isAdmin()) {
- send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.");
- throw new \RuntimeException("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.");
- }
- $subscription = Subscription::where('team_id', $teamId)->first();
- if ($subscription) {
- // send_internal_notification("Subscription already exists for team: {$teamId}");
- throw new \RuntimeException("Subscription already exists for team: {$teamId}");
- } else {
- Subscription::create([
- 'team_id' => $teamId,
- 'stripe_subscription_id' => $subscriptionId,
- 'stripe_customer_id' => $customerId,
- 'stripe_invoice_paid' => false,
- ]);
- }
- case 'customer.subscription.updated':
- $teamId = data_get($data, 'metadata.team_id');
- $userId = data_get($data, 'metadata.user_id');
- $customerId = data_get($data, 'customer');
- $status = data_get($data, 'status');
- $subscriptionId = data_get($data, 'items.data.0.subscription') ?? data_get($data, 'id');
- $planId = data_get($data, 'items.data.0.plan.id') ?? data_get($data, 'plan.id');
- if (Str::contains($excludedPlans, $planId)) {
- send_internal_notification('Subscription excluded.');
- break;
- }
- $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
- if (! $subscription) {
- if ($status === 'incomplete_expired') {
- // send_internal_notification('Subscription incomplete expired');
- throw new \RuntimeException('Subscription incomplete expired');
- }
- if ($teamId) {
- $subscription = Subscription::create([
- 'team_id' => $teamId,
- 'stripe_subscription_id' => $subscriptionId,
- 'stripe_customer_id' => $customerId,
- 'stripe_invoice_paid' => false,
- ]);
- } else {
- send_internal_notification('No subscription and team id found');
- throw new \RuntimeException('No subscription and team id found');
- }
- }
- $cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
- $feedback = data_get($data, 'cancellation_details.feedback');
- $comment = data_get($data, 'cancellation_details.comment');
- $lookup_key = data_get($data, 'items.data.0.price.lookup_key');
- if (str($lookup_key)->contains('dynamic')) {
- $quantity = data_get($data, 'items.data.0.quantity', 2);
- $team = data_get($subscription, 'team');
- if ($team) {
- $team->update([
- 'custom_server_limit' => $quantity,
- ]);
- }
- ServerLimitCheckJob::dispatch($team);
- }
- $subscription->update([
- 'stripe_feedback' => $feedback,
- 'stripe_comment' => $comment,
- 'stripe_plan_id' => $planId,
- 'stripe_cancel_at_period_end' => $cancelAtPeriodEnd,
- ]);
- if ($status === 'paused' || $status === 'incomplete_expired') {
- if ($subscription->stripe_subscription_id === $subscriptionId) {
- $subscription->update([
- 'stripe_invoice_paid' => false,
- ]);
- }
- }
- if ($status === 'past_due') {
- if ($subscription->stripe_subscription_id === $subscriptionId) {
- $subscription->update([
- 'stripe_past_due' => true,
- ]);
- send_internal_notification('Past Due: '.$customerId.'Subscription ID: '.$subscriptionId);
- }
- }
- if ($status === 'unpaid') {
- if ($subscription->stripe_subscription_id === $subscriptionId) {
- $subscription->update([
- 'stripe_invoice_paid' => false,
- ]);
- send_internal_notification('Unpaid: '.$customerId.'Subscription ID: '.$subscriptionId);
- }
- $team = data_get($subscription, 'team');
- if ($team) {
- $team->subscriptionEnded();
- } else {
- send_internal_notification('Subscription unpaid but no team found in Coolify for customer: '.$customerId);
- throw new \RuntimeException("No team found in Coolify for customer: {$customerId}");
- }
- }
- if ($status === 'active') {
- if ($subscription->stripe_subscription_id === $subscriptionId) {
- $subscription->update([
- 'stripe_past_due' => false,
- 'stripe_invoice_paid' => true,
- ]);
- }
- }
- if ($feedback) {
- $reason = "Cancellation feedback for {$customerId}: '".$feedback."'";
- if ($comment) {
- $reason .= ' with comment: \''.$comment."'";
- }
- }
-
- break;
- case 'customer.subscription.deleted':
- $customerId = data_get($data, 'customer');
- $subscriptionId = data_get($data, 'id');
- $subscription = Subscription::where('stripe_customer_id', $customerId)->where('stripe_subscription_id', $subscriptionId)->first();
- if ($subscription) {
- $team = data_get($subscription, 'team');
- if ($team) {
- $team->subscriptionEnded();
- } else {
- send_internal_notification('Subscription deleted but no team found in Coolify for customer: '.$customerId);
- throw new \RuntimeException("No team found in Coolify for customer: {$customerId}");
- }
- } else {
- send_internal_notification('Subscription deleted but no subscription found in Coolify for customer: '.$customerId);
- throw new \RuntimeException("No subscription found in Coolify for customer: {$customerId}");
- }
- break;
- default:
- throw new \RuntimeException("Unhandled event type: {$type}");
- }
- } catch (\Exception $e) {
- send_internal_notification('StripeProcessJob error: '.$e->getMessage());
- }
- }
-}
diff --git a/app/Jobs/SubscriptionInvoiceFailedJob.php b/app/Jobs/SubscriptionInvoiceFailedJob.php
deleted file mode 100755
index dc511f4452..0000000000
--- a/app/Jobs/SubscriptionInvoiceFailedJob.php
+++ /dev/null
@@ -1,42 +0,0 @@
-onQueue('high');
- }
-
- public function handle()
- {
- try {
- $session = getStripeCustomerPortalSession($this->team);
- $mail = new MailMessage;
- $mail->view('emails.subscription-invoice-failed', [
- 'stripeCustomerPortal' => $session->url,
- ]);
- $mail->subject('Your last payment was failed for Coolify Cloud.');
- $this->team->members()->each(function ($member) use ($mail) {
- if ($member->isAdmin()) {
- send_user_an_email($mail, $member->email);
- }
- });
- } catch (\Throwable $e) {
- send_internal_notification('SubscriptionInvoiceFailedJob failed with: '.$e->getMessage());
- throw $e;
- }
- }
-}
diff --git a/app/Jobs/UpdateCoolifyJob.php b/app/Jobs/UpdateCoolifyJob.php
deleted file mode 100644
index f0e43cbc0a..0000000000
--- a/app/Jobs/UpdateCoolifyJob.php
+++ /dev/null
@@ -1,54 +0,0 @@
-onQueue('high');
- }
-
- public function handle(): void
- {
- try {
- CheckForUpdatesJob::dispatchSync();
- $settings = instanceSettings();
- if (! $settings->new_version_available) {
- Log::info('No new version available. Skipping update.');
-
- return;
- }
-
- $server = Server::findOrFail(0);
- if (! $server) {
- Log::error('Server not found. Cannot proceed with update.');
-
- return;
- }
-
- Log::info('Starting Coolify update process...');
- UpdateCoolify::run(false); // false means it's not a manual update
-
- $settings->update(['new_version_available' => false]);
- Log::info('Coolify update completed successfully.');
- } catch (\Throwable $e) {
- Log::error('UpdateCoolifyJob failed: '.$e->getMessage());
- // Consider implementing a notification to administrators
- }
- }
-}
diff --git a/app/Jobs/VolumeCloneJob.php b/app/Jobs/VolumeCloneJob.php
deleted file mode 100644
index f37a9704e3..0000000000
--- a/app/Jobs/VolumeCloneJob.php
+++ /dev/null
@@ -1,104 +0,0 @@
-onQueue('high');
- }
-
- public function handle()
- {
- try {
- if (! $this->targetServer || $this->targetServer->id === $this->sourceServer->id) {
- $this->cloneLocalVolume();
- } else {
- $this->cloneRemoteVolume();
- }
- } catch (\Exception $e) {
- \Log::error("Failed to copy volume data for {$this->sourceVolume}: ".$e->getMessage());
- throw $e;
- }
- }
-
- protected function cloneLocalVolume()
- {
- instant_remote_process([
- "docker volume create $this->targetVolume",
- "docker run --rm -v $this->sourceVolume:/source -v $this->targetVolume:/target alpine sh -c 'cp -a /source/. /target/ && chown -R 1000:1000 /target'",
- ], $this->sourceServer);
- }
-
- protected function cloneRemoteVolume()
- {
- $sourceCloneDir = "{$this->cloneDir}/{$this->sourceVolume}";
- $targetCloneDir = "{$this->cloneDir}/{$this->targetVolume}";
-
- try {
- instant_remote_process([
- "mkdir -p $sourceCloneDir",
- "chmod 777 $sourceCloneDir",
- "docker run --rm -v $this->sourceVolume:/source -v $sourceCloneDir:/clone alpine sh -c 'cd /source && tar czf /clone/volume-data.tar.gz .'",
- ], $this->sourceServer);
-
- instant_remote_process([
- "mkdir -p $targetCloneDir",
- "chmod 777 $targetCloneDir",
- ], $this->targetServer);
-
- instant_scp(
- "$sourceCloneDir/volume-data.tar.gz",
- "$targetCloneDir/volume-data.tar.gz",
- $this->sourceServer,
- $this->targetServer
- );
-
- instant_remote_process([
- "docker volume create $this->targetVolume",
- "docker run --rm -v $this->targetVolume:/target -v $targetCloneDir:/clone alpine sh -c 'cd /target && tar xzf /clone/volume-data.tar.gz && chown -R 1000:1000 /target'",
- ], $this->targetServer);
-
- } catch (\Exception $e) {
- \Log::error("Failed to clone volume {$this->sourceVolume} to {$this->targetVolume}: ".$e->getMessage());
- throw $e;
- } finally {
- try {
- instant_remote_process([
- "rm -rf $sourceCloneDir",
- ], $this->sourceServer, false);
- } catch (\Exception $e) {
- \Log::warning('Failed to clean up source server clone directory: '.$e->getMessage());
- }
-
- try {
- if ($this->targetServer) {
- instant_remote_process([
- "rm -rf $targetCloneDir",
- ], $this->targetServer, false);
- }
- } catch (\Exception $e) {
- \Log::warning('Failed to clean up target server clone directory: '.$e->getMessage());
- }
- }
- }
-}
diff --git a/app/Listeners/MaintenanceModeDisabledNotification.php b/app/Listeners/MaintenanceModeDisabledNotification.php
deleted file mode 100644
index 6c3ab83d8f..0000000000
--- a/app/Listeners/MaintenanceModeDisabledNotification.php
+++ /dev/null
@@ -1,48 +0,0 @@
-files();
- $files = collect($files);
- $files = $files->sort();
- foreach ($files as $file) {
- $content = Storage::disk('webhooks-during-maintenance')->get($file);
- $data = json_decode($content, true);
- $symfonyRequest = new SymfonyRequest(
- $data['query'],
- $data['request'],
- $data['attributes'],
- $data['cookies'],
- $data['files'],
- $data['server'],
- $data['content']
- );
-
- foreach ($data['headers'] as $key => $value) {
- $symfonyRequest->headers->set($key, $value);
- }
- $request = Request::createFromBase($symfonyRequest);
- $endpoint = str($file)->after('_')->beforeLast('_')->value();
- $class = "App\Http\Controllers\Webhook\\".ucfirst(str($endpoint)->before('::')->value());
- $method = str($endpoint)->after('::')->value();
- try {
- $instance = new $class;
- $instance->$method($request);
- } catch (\Throwable $th) {
- } finally {
- Storage::disk('webhooks-during-maintenance')->delete($file);
- }
- }
- }
-}
diff --git a/app/Listeners/MaintenanceModeEnabledNotification.php b/app/Listeners/MaintenanceModeEnabledNotification.php
deleted file mode 100644
index 5aab248ea8..0000000000
--- a/app/Listeners/MaintenanceModeEnabledNotification.php
+++ /dev/null
@@ -1,21 +0,0 @@
-server = data_get($event, 'data');
- $this->server->setupDefaultRedirect();
- $this->server->setupDynamicProxyConfiguration();
- $this->server->proxy->force_stop = false;
- $this->server->save();
- }
-}
diff --git a/app/Livewire/ActivityMonitor.php b/app/Livewire/ActivityMonitor.php
deleted file mode 100644
index 024f53c3d2..0000000000
--- a/app/Livewire/ActivityMonitor.php
+++ /dev/null
@@ -1,67 +0,0 @@
- 'newMonitorActivity'];
-
- public function newMonitorActivity($activityId, $eventToDispatch = 'activityFinished')
- {
- $this->activityId = $activityId;
- $this->eventToDispatch = $eventToDispatch;
-
- $this->hydrateActivity();
-
- $this->isPollingActive = true;
- }
-
- public function hydrateActivity()
- {
- $this->activity = Activity::find($this->activityId);
- }
-
- public function polling()
- {
- $this->hydrateActivity();
- $exit_code = data_get($this->activity, 'properties.exitCode');
- if ($exit_code !== null) {
- $this->isPollingActive = false;
- if ($exit_code === 0) {
- if ($this->eventToDispatch !== null) {
- if (str($this->eventToDispatch)->startsWith('App\\Events\\')) {
- $causer_id = data_get($this->activity, 'causer_id');
- $user = User::find($causer_id);
- if ($user) {
- foreach ($user->teams as $team) {
- $teamId = $team->id;
- $this->eventToDispatch::dispatch($teamId);
- }
- }
-
- return;
- }
- $this->dispatch($this->eventToDispatch);
- }
- }
- }
- }
-}
diff --git a/app/Livewire/Admin/Index.php b/app/Livewire/Admin/Index.php
deleted file mode 100644
index b5f6d29294..0000000000
--- a/app/Livewire/Admin/Index.php
+++ /dev/null
@@ -1,81 +0,0 @@
-route('dashboard');
- }
- if (Auth::id() !== 0 && ! session('impersonating')) {
- return redirect()->route('dashboard');
- }
- $this->getSubscribers();
- }
-
- public function back()
- {
- if (session('impersonating')) {
- session()->forget('impersonating');
- $user = User::find(0);
- $team_to_switch_to = $user->teams->first();
- Auth::login($user);
- refreshSession($team_to_switch_to);
-
- return redirect(request()->header('Referer'));
- }
- }
-
- public function submitSearch()
- {
- if ($this->search !== '') {
- $this->foundUsers = User::where(function ($query) {
- $query->where('name', 'like', "%{$this->search}%")
- ->orWhere('email', 'like', "%{$this->search}%");
- })->get();
- }
- }
-
- public function getSubscribers()
- {
- $this->inactiveSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', false)->count();
- $this->activeSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', true)->count();
- }
-
- public function switchUser(int $user_id)
- {
- if (Auth::id() !== 0) {
- return redirect()->route('dashboard');
- }
- session(['impersonating' => true]);
- $user = User::find($user_id);
- $team_to_switch_to = $user->teams->first();
- // Cache::forget("team:{$user->id}");
- Auth::login($user);
- refreshSession($team_to_switch_to);
-
- return redirect(request()->header('Referer'));
- }
-
- public function render()
- {
- return view('livewire.admin.index');
- }
-}
diff --git a/app/Livewire/Boarding/Index.php b/app/Livewire/Boarding/Index.php
deleted file mode 100644
index 15eabfec57..0000000000
--- a/app/Livewire/Boarding/Index.php
+++ /dev/null
@@ -1,383 +0,0 @@
- 'validateServer'];
-
- public string $currentState = 'welcome';
-
- public ?string $selectedServerType = null;
-
- public ?Collection $privateKeys = null;
-
- public ?int $selectedExistingPrivateKey = null;
-
- public ?string $privateKeyType = null;
-
- public ?string $privateKey = null;
-
- public ?string $publicKey = null;
-
- public ?string $privateKeyName = null;
-
- public ?string $privateKeyDescription = null;
-
- public ?PrivateKey $createdPrivateKey = null;
-
- public ?Collection $servers = null;
-
- public ?int $selectedExistingServer = null;
-
- public ?string $remoteServerName = null;
-
- public ?string $remoteServerDescription = null;
-
- public ?string $remoteServerHost = null;
-
- public ?int $remoteServerPort = 22;
-
- public ?string $remoteServerUser = 'root';
-
- public bool $isSwarmManager = false;
-
- public bool $isCloudflareTunnel = false;
-
- public ?Server $createdServer = null;
-
- public Collection $projects;
-
- public ?int $selectedProject = null;
-
- public ?Project $createdProject = null;
-
- public bool $dockerInstallationStarted = false;
-
- public string $serverPublicKey;
-
- public bool $serverReachable = true;
-
- public ?string $minDockerVersion = null;
-
- public function mount()
- {
- if (auth()->user()?->isMember() && auth()->user()->currentTeam()->show_boarding === true) {
- return redirect()->route('dashboard');
- }
-
- $this->minDockerVersion = str(config('constants.docker.minimum_required_version'))->before('.');
- $this->privateKeyName = generate_random_name();
- $this->remoteServerName = generate_random_name();
- if (isDev()) {
- $this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY-----
-b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
-QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk
-hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA
-AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV
-uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
------END OPENSSH PRIVATE KEY-----';
- $this->privateKeyDescription = 'Created by Coolify';
- $this->remoteServerDescription = 'Created by Coolify';
- $this->remoteServerHost = 'coolify-testing-host';
- }
- }
-
- public function explanation()
- {
- if (isCloud()) {
- return $this->setServerType('remote');
- }
- $this->currentState = 'select-server-type';
- }
-
- public function restartBoarding()
- {
- return redirect()->route('onboarding');
- }
-
- public function skipBoarding()
- {
- Team::find(currentTeam()->id)->update([
- 'show_boarding' => false,
- ]);
- refreshSession();
-
- return redirect()->route('dashboard');
- }
-
- public function setServerType(string $type)
- {
- $this->selectedServerType = $type;
- if ($this->selectedServerType === 'localhost') {
- $this->createdServer = Server::find(0);
- $this->selectedExistingServer = 0;
- if (! $this->createdServer) {
- return $this->dispatch('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.');
- }
- $this->serverPublicKey = $this->createdServer->privateKey->getPublicKey();
-
- return $this->validateServer('localhost');
- } elseif ($this->selectedServerType === 'remote') {
- if (isDev()) {
- $this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->get();
- } else {
- $this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
- }
- if ($this->privateKeys->count() > 0) {
- $this->selectedExistingPrivateKey = $this->privateKeys->first()->id;
- }
- $this->servers = Server::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
- if ($this->servers->count() > 0) {
- $this->selectedExistingServer = $this->servers->first()->id;
- $this->updateServerDetails();
- $this->currentState = 'select-existing-server';
-
- return;
- }
- $this->currentState = 'private-key';
- }
- }
-
- public function selectExistingServer()
- {
- $this->createdServer = Server::find($this->selectedExistingServer);
- if (! $this->createdServer) {
- $this->dispatch('error', 'Server is not found.');
- $this->currentState = 'private-key';
-
- return;
- }
- $this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
- $this->serverPublicKey = $this->createdServer->privateKey->getPublicKey();
- $this->updateServerDetails();
- $this->currentState = 'validate-server';
- }
-
- private function updateServerDetails()
- {
- if ($this->createdServer) {
- $this->remoteServerPort = $this->createdServer->port;
- $this->remoteServerUser = $this->createdServer->user;
- }
- }
-
- public function getProxyType()
- {
- $this->selectProxy(ProxyTypes::TRAEFIK->value);
- $this->getProjects();
- }
-
- public function selectExistingPrivateKey()
- {
- if (is_null($this->selectedExistingPrivateKey)) {
- $this->restartBoarding();
-
- return;
- }
- $this->createdPrivateKey = PrivateKey::where('team_id', currentTeam()->id)->where('id', $this->selectedExistingPrivateKey)->first();
- $this->privateKey = $this->createdPrivateKey->private_key;
- $this->currentState = 'create-server';
- }
-
- public function createNewServer()
- {
- $this->selectedExistingServer = null;
- $this->currentState = 'private-key';
- }
-
- public function setPrivateKey(string $type)
- {
- $this->selectedExistingPrivateKey = null;
- $this->privateKeyType = $type;
- if ($type === 'create') {
- $this->createNewPrivateKey();
- }
- $this->currentState = 'create-private-key';
- }
-
- public function savePrivateKey()
- {
- $this->validate([
- 'privateKeyName' => 'required|string|max:255',
- 'privateKeyDescription' => 'nullable|string|max:255',
- 'privateKey' => 'required|string',
- ]);
-
- try {
- $privateKey = PrivateKey::createAndStore([
- 'name' => $this->privateKeyName,
- 'description' => $this->privateKeyDescription,
- 'private_key' => $this->privateKey,
- 'team_id' => currentTeam()->id,
- ]);
-
- $this->createdPrivateKey = $privateKey;
- $this->currentState = 'create-server';
- } catch (\Exception $e) {
- $this->addError('privateKey', 'Failed to save private key: '.$e->getMessage());
- }
- }
-
- public function saveServer()
- {
- $this->validate([
- 'remoteServerName' => 'required|string',
- 'remoteServerHost' => 'required|string',
- 'remoteServerPort' => 'required|integer',
- 'remoteServerUser' => 'required|string',
- ]);
-
- $this->privateKey = formatPrivateKey($this->privateKey);
- $foundServer = Server::whereIp($this->remoteServerHost)->first();
- if ($foundServer) {
- return $this->dispatch('error', 'IP address is already in use by another team.');
- }
- $this->createdServer = Server::create([
- 'name' => $this->remoteServerName,
- 'ip' => $this->remoteServerHost,
- 'port' => $this->remoteServerPort,
- 'user' => $this->remoteServerUser,
- 'description' => $this->remoteServerDescription,
- 'private_key_id' => $this->createdPrivateKey->id,
- 'team_id' => currentTeam()->id,
- ]);
- $this->createdServer->settings->is_swarm_manager = $this->isSwarmManager;
- $this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
- $this->createdServer->settings->save();
- $this->selectedExistingServer = $this->createdServer->id;
- $this->currentState = 'validate-server';
- }
-
- public function installServer()
- {
- $this->dispatch('init', true);
- }
-
- public function validateServer()
- {
- try {
- config()->set('constants.ssh.mux_enabled', false);
-
- // EC2 does not have `uptime` command, lol
- instant_remote_process(['ls /'], $this->createdServer, true);
-
- $this->createdServer->settings()->update([
- 'is_reachable' => true,
- ]);
- $this->serverReachable = true;
- } catch (\Throwable $e) {
- $this->serverReachable = false;
- $this->createdServer->settings()->update([
- 'is_reachable' => false,
- ]);
-
- return handleError(error: $e, livewire: $this);
- }
-
- try {
- $dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this->createdServer, true);
- $dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
- if (is_null($dockerVersion)) {
- $this->currentState = 'validate-server';
- throw new \Exception('Docker not found or old version is installed.');
- }
- $this->createdServer->settings()->update([
- 'is_usable' => true,
- ]);
- $this->getProxyType();
- } catch (\Throwable $e) {
- $this->createdServer->settings()->update([
- 'is_usable' => false,
- ]);
-
- return handleError(error: $e, livewire: $this);
- }
- }
-
- public function selectProxy(?string $proxyType = null)
- {
- if (! $proxyType) {
- return $this->getProjects();
- }
- $this->createdServer->proxy->type = $proxyType;
- $this->createdServer->proxy->status = 'exited';
- $this->createdServer->save();
- $this->getProjects();
- }
-
- public function getProjects()
- {
- $this->projects = Project::ownedByCurrentTeam(['name'])->get();
- if ($this->projects->count() > 0) {
- $this->selectedProject = $this->projects->first()->id;
- }
- $this->currentState = 'create-project';
- }
-
- public function selectExistingProject()
- {
- $this->createdProject = Project::find($this->selectedProject);
- $this->currentState = 'create-resource';
- }
-
- public function createNewProject()
- {
- $this->createdProject = Project::create([
- 'name' => 'My first project',
- 'team_id' => currentTeam()->id,
- 'uuid' => (string) new Cuid2,
- ]);
- $this->currentState = 'create-resource';
- }
-
- public function showNewResource()
- {
- $this->skipBoarding();
-
- return redirect()->route(
- 'project.resource.create',
- [
- 'project_uuid' => $this->createdProject->uuid,
- 'environment_uuid' => $this->createdProject->environments->first()->uuid,
- 'server' => $this->createdServer->id,
- ]
- );
- }
-
- public function saveAndValidateServer()
- {
- $this->validate([
- 'remoteServerPort' => 'required|integer|min:1|max:65535',
- 'remoteServerUser' => 'required|string',
- ]);
-
- $this->createdServer->update([
- 'port' => $this->remoteServerPort,
- 'user' => $this->remoteServerUser,
- 'timezone' => 'UTC',
- ]);
- $this->validateServer();
- }
-
- private function createNewPrivateKey()
- {
- $this->privateKeyName = generate_random_name();
- $this->privateKeyDescription = 'Created by Coolify';
- ['private' => $this->privateKey, 'public' => $this->publicKey] = generateSSHKey();
- }
-
- public function render()
- {
- return view('livewire.boarding.index')->layout('layouts.boarding');
- }
-}
diff --git a/app/Livewire/Dashboard.php b/app/Livewire/Dashboard.php
deleted file mode 100644
index d89f2b970f..0000000000
--- a/app/Livewire/Dashboard.php
+++ /dev/null
@@ -1,61 +0,0 @@
-privateKeys = PrivateKey::ownedByCurrentTeam()->get();
- $this->servers = Server::ownedByCurrentTeam()->get();
- $this->projects = Project::ownedByCurrentTeam()->get();
- $this->loadDeployments();
- }
-
- public function cleanupQueue()
- {
- Artisan::queue('cleanup:deployment-queue', [
- '--team-id' => currentTeam()->id,
- ]);
- }
-
- public function loadDeployments()
- {
- $this->deploymentsPerServer = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->whereIn('server_id', $this->servers->pluck('id'))->get([
- 'id',
- 'application_id',
- 'application_name',
- 'deployment_url',
- 'pull_request_id',
- 'server_name',
- 'server_id',
- 'status',
- ])->sortBy('id')->groupBy('server_name')->toArray();
- }
-
- public function navigateToProject($projectUuid)
- {
- return $this->redirect(collect($this->projects)->firstWhere('uuid', $projectUuid)->navigateTo(), true);
- }
-
- public function render()
- {
- return view('livewire.dashboard');
- }
-}
diff --git a/app/Livewire/Destination/Index.php b/app/Livewire/Destination/Index.php
deleted file mode 100644
index a3df3fd562..0000000000
--- a/app/Livewire/Destination/Index.php
+++ /dev/null
@@ -1,23 +0,0 @@
-servers = Server::isUsable()->get();
- }
-
- public function render()
- {
- return view('livewire.destination.index');
- }
-}
diff --git a/app/Livewire/Destination/New/Docker.php b/app/Livewire/Destination/New/Docker.php
deleted file mode 100644
index eb768d1916..0000000000
--- a/app/Livewire/Destination/New/Docker.php
+++ /dev/null
@@ -1,99 +0,0 @@
-network = new Cuid2;
- $this->servers = Server::isUsable()->get();
- if ($server_id) {
- $foundServer = $this->servers->find($server_id) ?: $this->servers->first();
- if (! $foundServer) {
- throw new \Exception('Server not found.');
- }
- $this->selectedServer = $foundServer;
- $this->serverId = $this->selectedServer->id;
- } else {
- $foundServer = $this->servers->first();
- if (! $foundServer) {
- throw new \Exception('Server not found.');
- }
- $this->selectedServer = $foundServer;
- $this->serverId = $this->selectedServer->id;
- }
- $this->generateName();
- }
-
- public function updatedServerId()
- {
- $this->selectedServer = $this->servers->find($this->serverId);
- $this->generateName();
- }
-
- public function generateName()
- {
- $name = data_get($this->selectedServer, 'name', new Cuid2);
- $this->name = str("{$name}-{$this->network}")->kebab();
- }
-
- public function submit()
- {
- try {
- $this->validate();
- if ($this->isSwarm) {
- $found = $this->selectedServer->swarmDockers()->where('network', $this->network)->first();
- if ($found) {
- throw new \Exception('Network already added to this server.');
- } else {
- $docker = SwarmDocker::create([
- 'name' => $this->name,
- 'network' => $this->network,
- 'server_id' => $this->selectedServer->id,
- ]);
- }
- } else {
- $found = $this->selectedServer->standaloneDockers()->where('network', $this->network)->first();
- if ($found) {
- throw new \Exception('Network already added to this server.');
- } else {
- $docker = StandaloneDocker::create([
- 'name' => $this->name,
- 'network' => $this->network,
- 'server_id' => $this->selectedServer->id,
- ]);
- }
- }
- $this->redirect(route('destination.show', $docker->uuid));
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Destination/Show.php b/app/Livewire/Destination/Show.php
deleted file mode 100644
index 5c4d6c1701..0000000000
--- a/app/Livewire/Destination/Show.php
+++ /dev/null
@@ -1,95 +0,0 @@
-first() ??
- SwarmDocker::whereUuid($destination_uuid)->firstOrFail();
-
- $ownedByTeam = Server::ownedByCurrentTeam()->each(function ($server) use ($destination) {
- if ($server->standaloneDockers->contains($destination) || $server->swarmDockers->contains($destination)) {
- $this->destination = $destination;
- $this->syncData();
- }
- });
- if ($ownedByTeam === false) {
- return redirect()->route('destination.index');
- }
- $this->destination = $destination;
- $this->syncData();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->destination->name = $this->name;
- $this->destination->network = $this->network;
- $this->destination->server->ip = $this->serverIp;
- $this->destination->save();
- } else {
- $this->name = $this->destination->name;
- $this->network = $this->destination->network;
- $this->serverIp = $this->destination->server->ip;
- }
- }
-
- public function submit()
- {
- try {
- $this->syncData(true);
- $this->dispatch('success', 'Destination saved.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function delete()
- {
- try {
- if ($this->destination->getMorphClass() === \App\Models\StandaloneDocker::class) {
- if ($this->destination->attachedTo()) {
- return $this->dispatch('error', 'You must delete all resources before deleting this destination.');
- }
- instant_remote_process(["docker network disconnect {$this->destination->network} coolify-proxy"], $this->destination->server, throwError: false);
- instant_remote_process(['docker network rm -f '.$this->destination->network], $this->destination->server);
- }
- $this->destination->delete();
-
- return redirect()->route('destination.index');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.destination.show');
- }
-}
diff --git a/app/Livewire/ForcePasswordReset.php b/app/Livewire/ForcePasswordReset.php
deleted file mode 100644
index 61a2a20e95..0000000000
--- a/app/Livewire/ForcePasswordReset.php
+++ /dev/null
@@ -1,64 +0,0 @@
- ['required', 'email'],
- 'password' => ['required', Password::defaults(), 'confirmed'],
- ];
- }
-
- public function mount()
- {
- if (auth()->user()->force_password_reset === false) {
- return redirect()->route('dashboard');
- }
- $this->email = auth()->user()->email;
- }
-
- public function render()
- {
- return view('livewire.force-password-reset')->layout('layouts.simple');
- }
-
- public function submit()
- {
- if (auth()->user()->force_password_reset === false) {
- return redirect()->route('dashboard');
- }
-
- try {
- $this->rateLimit(10);
- $this->validate();
- $firstLogin = auth()->user()->created_at == auth()->user()->updated_at;
- auth()->user()->forceFill([
- 'password' => Hash::make($this->password),
- 'force_password_reset' => false,
- ])->save();
- if ($firstLogin) {
- send_internal_notification('First login for '.auth()->user()->email);
- }
-
- return redirect()->route('dashboard');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Help.php b/app/Livewire/Help.php
deleted file mode 100644
index 9137105885..0000000000
--- a/app/Livewire/Help.php
+++ /dev/null
@@ -1,58 +0,0 @@
-validate();
- $this->rateLimit(3, 30);
-
- $settings = instanceSettings();
- $mail = new MailMessage;
- $mail->view(
- 'emails.help',
- [
- 'description' => $this->description,
- ]
- );
- $mail->subject("[HELP]: {$this->subject}");
- $type = set_transanctional_email_settings($settings);
-
- // Sending feedback through Cloud API
- if (blank($type)) {
- $url = 'https://app.coolify.io/api/feedback';
- Http::post($url, [
- 'content' => 'User: `'.auth()->user()?->email.'` with subject: `'.$this->subject.'` has the following problem: `'.$this->description.'`',
- ]);
- } else {
- send_user_an_email($mail, auth()->user()?->email, 'hi@coollabs.io');
- }
- $this->dispatch('success', 'Feedback sent.', 'We will get in touch with you as soon as possible.');
- $this->reset('description', 'subject');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.help')->layout('layouts.app');
- }
-}
diff --git a/app/Livewire/LayoutPopups.php b/app/Livewire/LayoutPopups.php
deleted file mode 100644
index f2ba788938..0000000000
--- a/app/Livewire/LayoutPopups.php
+++ /dev/null
@@ -1,27 +0,0 @@
-user()->currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},TestEvent" => 'testEvent',
- ];
- }
-
- public function testEvent()
- {
- $this->dispatch('success', 'Realtime events configured!');
- }
-
- public function render()
- {
- return view('livewire.layout-popups');
- }
-}
diff --git a/app/Livewire/MonacoEditor.php b/app/Livewire/MonacoEditor.php
deleted file mode 100644
index 53ca1d3866..0000000000
--- a/app/Livewire/MonacoEditor.php
+++ /dev/null
@@ -1,51 +0,0 @@
- '$refresh',
- ];
-
- public function __construct(
- public ?string $id,
- public ?string $name,
- public ?string $type,
- public ?string $monacoContent,
- public ?string $value,
- public ?string $label,
- public ?string $placeholder,
- public bool $required,
- public bool $disabled,
- public bool $readonly,
- public bool $allowTab,
- public bool $spellcheck,
- public ?string $helper,
- public bool $realtimeValidation,
- public bool $allowToPeak,
- public string $defaultClass,
- public string $defaultClassInput,
- public ?string $language
-
- ) {
- //
- }
-
- public function render()
- {
- if (is_null($this->id)) {
- $this->id = new Cuid2;
- }
-
- if (is_null($this->name)) {
- $this->name = $this->id;
- }
-
- return view('components.forms.monaco-editor');
- }
-}
diff --git a/app/Livewire/NavbarDeleteTeam.php b/app/Livewire/NavbarDeleteTeam.php
deleted file mode 100644
index e97cceb0da..0000000000
--- a/app/Livewire/NavbarDeleteTeam.php
+++ /dev/null
@@ -1,53 +0,0 @@
-team = currentTeam()->name;
- }
-
- public function delete($password)
- {
- if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return;
- }
- }
-
- $currentTeam = currentTeam();
- $currentTeam->delete();
-
- $currentTeam->members->each(function ($user) use ($currentTeam) {
- if ($user->id === Auth::id()) {
- return;
- }
- $user->teams()->detach($currentTeam);
- $session = DB::table('sessions')->where('user_id', $user->id)->first();
- if ($session) {
- DB::table('sessions')->where('id', $session->id)->delete();
- }
- });
-
- refreshSession();
-
- return redirect()->route('team.index');
- }
-
- public function render()
- {
- return view('livewire.navbar-delete-team');
- }
-}
diff --git a/app/Livewire/NewActivityMonitor.php b/app/Livewire/NewActivityMonitor.php
deleted file mode 100644
index a9334e7108..0000000000
--- a/app/Livewire/NewActivityMonitor.php
+++ /dev/null
@@ -1,74 +0,0 @@
- 'newMonitorActivity'];
-
- public function newMonitorActivity($activityId, $eventToDispatch = 'activityFinished', $eventData = null)
- {
- $this->activityId = $activityId;
- $this->eventToDispatch = $eventToDispatch;
- $this->eventData = $eventData;
-
- $this->hydrateActivity();
-
- $this->isPollingActive = true;
- }
-
- public function hydrateActivity()
- {
- $this->activity = Activity::find($this->activityId);
- }
-
- public function polling()
- {
- $this->hydrateActivity();
- // $this->setStatus(ProcessStatus::IN_PROGRESS);
- $exit_code = data_get($this->activity, 'properties.exitCode');
- if ($exit_code !== null) {
- // if ($exit_code === 0) {
- // // $this->setStatus(ProcessStatus::FINISHED);
- // } else {
- // // $this->setStatus(ProcessStatus::ERROR);
- // }
- $this->isPollingActive = false;
- if ($this->eventToDispatch !== null) {
- if (str($this->eventToDispatch)->startsWith('App\\Events\\')) {
- $causer_id = data_get($this->activity, 'causer_id');
- $user = User::find($causer_id);
- if ($user) {
- foreach ($user->teams as $team) {
- $teamId = $team->id;
- $this->eventToDispatch::dispatch($teamId);
- }
- }
-
- return;
- }
- if (! is_null($this->eventData)) {
- $this->dispatch($this->eventToDispatch, $this->eventData);
- } else {
- $this->dispatch($this->eventToDispatch);
- }
- }
- }
- }
-}
diff --git a/app/Livewire/Notifications/Discord.php b/app/Livewire/Notifications/Discord.php
deleted file mode 100644
index 57007813ee..0000000000
--- a/app/Livewire/Notifications/Discord.php
+++ /dev/null
@@ -1,168 +0,0 @@
-team = auth()->user()->currentTeam();
- $this->settings = $this->team->discordNotificationSettings;
- $this->syncData();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->settings->discord_enabled = $this->discordEnabled;
- $this->settings->discord_webhook_url = $this->discordWebhookUrl;
-
- $this->settings->deployment_success_discord_notifications = $this->deploymentSuccessDiscordNotifications;
- $this->settings->deployment_failure_discord_notifications = $this->deploymentFailureDiscordNotifications;
- $this->settings->status_change_discord_notifications = $this->statusChangeDiscordNotifications;
- $this->settings->backup_success_discord_notifications = $this->backupSuccessDiscordNotifications;
- $this->settings->backup_failure_discord_notifications = $this->backupFailureDiscordNotifications;
- $this->settings->scheduled_task_success_discord_notifications = $this->scheduledTaskSuccessDiscordNotifications;
- $this->settings->scheduled_task_failure_discord_notifications = $this->scheduledTaskFailureDiscordNotifications;
- $this->settings->docker_cleanup_success_discord_notifications = $this->dockerCleanupSuccessDiscordNotifications;
- $this->settings->docker_cleanup_failure_discord_notifications = $this->dockerCleanupFailureDiscordNotifications;
- $this->settings->server_disk_usage_discord_notifications = $this->serverDiskUsageDiscordNotifications;
- $this->settings->server_reachable_discord_notifications = $this->serverReachableDiscordNotifications;
- $this->settings->server_unreachable_discord_notifications = $this->serverUnreachableDiscordNotifications;
-
- $this->settings->save();
- refreshSession();
- } else {
- $this->discordEnabled = $this->settings->discord_enabled;
- $this->discordWebhookUrl = $this->settings->discord_webhook_url;
-
- $this->deploymentSuccessDiscordNotifications = $this->settings->deployment_success_discord_notifications;
- $this->deploymentFailureDiscordNotifications = $this->settings->deployment_failure_discord_notifications;
- $this->statusChangeDiscordNotifications = $this->settings->status_change_discord_notifications;
- $this->backupSuccessDiscordNotifications = $this->settings->backup_success_discord_notifications;
- $this->backupFailureDiscordNotifications = $this->settings->backup_failure_discord_notifications;
- $this->scheduledTaskSuccessDiscordNotifications = $this->settings->scheduled_task_success_discord_notifications;
- $this->scheduledTaskFailureDiscordNotifications = $this->settings->scheduled_task_failure_discord_notifications;
- $this->dockerCleanupSuccessDiscordNotifications = $this->settings->docker_cleanup_success_discord_notifications;
- $this->dockerCleanupFailureDiscordNotifications = $this->settings->docker_cleanup_failure_discord_notifications;
- $this->serverDiskUsageDiscordNotifications = $this->settings->server_disk_usage_discord_notifications;
- $this->serverReachableDiscordNotifications = $this->settings->server_reachable_discord_notifications;
- $this->serverUnreachableDiscordNotifications = $this->settings->server_unreachable_discord_notifications;
- }
- }
-
- public function instantSaveDiscordEnabled()
- {
- try {
- $this->validate([
- 'discordWebhookUrl' => 'required',
- ], [
- 'discordWebhookUrl.required' => 'Discord Webhook URL is required.',
- ]);
- $this->saveModel();
- } catch (\Throwable $e) {
- $this->discordEnabled = false;
-
- return handleError($e, $this);
- }
- }
-
- public function instantSave()
- {
- try {
- $this->syncData(true);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- $this->resetErrorBag();
- $this->syncData(true);
- $this->saveModel();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function saveModel()
- {
- $this->syncData(true);
- refreshSession();
- $this->dispatch('success', 'Settings saved.');
- }
-
- public function sendTestNotification()
- {
- try {
- $this->team->notify(new Test(channel: 'discord'));
- $this->dispatch('success', 'Test notification sent.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.notifications.discord');
- }
-}
diff --git a/app/Livewire/Notifications/Email.php b/app/Livewire/Notifications/Email.php
deleted file mode 100644
index 3ed20f907c..0000000000
--- a/app/Livewire/Notifications/Email.php
+++ /dev/null
@@ -1,372 +0,0 @@
- '$refresh'];
-
- #[Locked]
- public Team $team;
-
- #[Locked]
- public EmailNotificationSettings $settings;
-
- #[Locked]
- public string $emails;
-
- #[Validate(['boolean'])]
- public bool $smtpEnabled = false;
-
- #[Validate(['nullable', 'email'])]
- public ?string $smtpFromAddress = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $smtpFromName = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $smtpRecipients = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $smtpHost = null;
-
- #[Validate(['nullable', 'numeric', 'min:1', 'max:65535'])]
- public ?int $smtpPort = null;
-
- #[Validate(['nullable', 'string', 'in:starttls,tls,none'])]
- public ?string $smtpEncryption = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $smtpUsername = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $smtpPassword = null;
-
- #[Validate(['nullable', 'numeric'])]
- public ?int $smtpTimeout = null;
-
- #[Validate(['boolean'])]
- public bool $resendEnabled = false;
-
- #[Validate(['nullable', 'string'])]
- public ?string $resendApiKey = null;
-
- #[Validate(['boolean'])]
- public bool $useInstanceEmailSettings = false;
-
- #[Validate(['boolean'])]
- public bool $deploymentSuccessEmailNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $deploymentFailureEmailNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $statusChangeEmailNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $backupSuccessEmailNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $backupFailureEmailNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $scheduledTaskSuccessEmailNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $scheduledTaskFailureEmailNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $dockerCleanupSuccessEmailNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $dockerCleanupFailureEmailNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $serverDiskUsageEmailNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $serverReachableEmailNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $serverUnreachableEmailNotifications = true;
-
- #[Validate(['nullable', 'email'])]
- public ?string $testEmailAddress = null;
-
- public function mount()
- {
- try {
- $this->team = auth()->user()->currentTeam();
- $this->emails = auth()->user()->email;
- $this->settings = $this->team->emailNotificationSettings;
- $this->syncData();
- $this->testEmailAddress = auth()->user()->email;
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->settings->smtp_enabled = $this->smtpEnabled;
- $this->settings->smtp_from_address = $this->smtpFromAddress;
- $this->settings->smtp_from_name = $this->smtpFromName;
- $this->settings->smtp_recipients = $this->smtpRecipients;
- $this->settings->smtp_host = $this->smtpHost;
- $this->settings->smtp_port = $this->smtpPort;
- $this->settings->smtp_encryption = $this->smtpEncryption;
- $this->settings->smtp_username = $this->smtpUsername;
- $this->settings->smtp_password = $this->smtpPassword;
- $this->settings->smtp_timeout = $this->smtpTimeout;
-
- $this->settings->resend_enabled = $this->resendEnabled;
- $this->settings->resend_api_key = $this->resendApiKey;
-
- $this->settings->use_instance_email_settings = $this->useInstanceEmailSettings;
-
- $this->settings->deployment_success_email_notifications = $this->deploymentSuccessEmailNotifications;
- $this->settings->deployment_failure_email_notifications = $this->deploymentFailureEmailNotifications;
- $this->settings->status_change_email_notifications = $this->statusChangeEmailNotifications;
- $this->settings->backup_success_email_notifications = $this->backupSuccessEmailNotifications;
- $this->settings->backup_failure_email_notifications = $this->backupFailureEmailNotifications;
- $this->settings->scheduled_task_success_email_notifications = $this->scheduledTaskSuccessEmailNotifications;
- $this->settings->scheduled_task_failure_email_notifications = $this->scheduledTaskFailureEmailNotifications;
- $this->settings->docker_cleanup_success_email_notifications = $this->dockerCleanupSuccessEmailNotifications;
- $this->settings->docker_cleanup_failure_email_notifications = $this->dockerCleanupFailureEmailNotifications;
- $this->settings->server_disk_usage_email_notifications = $this->serverDiskUsageEmailNotifications;
- $this->settings->server_reachable_email_notifications = $this->serverReachableEmailNotifications;
- $this->settings->server_unreachable_email_notifications = $this->serverUnreachableEmailNotifications;
- $this->settings->save();
-
- } else {
- $this->smtpEnabled = $this->settings->smtp_enabled;
- $this->smtpFromAddress = $this->settings->smtp_from_address;
- $this->smtpFromName = $this->settings->smtp_from_name;
- $this->smtpRecipients = $this->settings->smtp_recipients;
- $this->smtpHost = $this->settings->smtp_host;
- $this->smtpPort = $this->settings->smtp_port;
- $this->smtpEncryption = $this->settings->smtp_encryption;
- $this->smtpUsername = $this->settings->smtp_username;
- $this->smtpPassword = $this->settings->smtp_password;
- $this->smtpTimeout = $this->settings->smtp_timeout;
-
- $this->resendEnabled = $this->settings->resend_enabled;
- $this->resendApiKey = $this->settings->resend_api_key;
-
- $this->useInstanceEmailSettings = $this->settings->use_instance_email_settings;
-
- $this->deploymentSuccessEmailNotifications = $this->settings->deployment_success_email_notifications;
- $this->deploymentFailureEmailNotifications = $this->settings->deployment_failure_email_notifications;
- $this->statusChangeEmailNotifications = $this->settings->status_change_email_notifications;
- $this->backupSuccessEmailNotifications = $this->settings->backup_success_email_notifications;
- $this->backupFailureEmailNotifications = $this->settings->backup_failure_email_notifications;
- $this->scheduledTaskSuccessEmailNotifications = $this->settings->scheduled_task_success_email_notifications;
- $this->scheduledTaskFailureEmailNotifications = $this->settings->scheduled_task_failure_email_notifications;
- $this->dockerCleanupSuccessEmailNotifications = $this->settings->docker_cleanup_success_email_notifications;
- $this->dockerCleanupFailureEmailNotifications = $this->settings->docker_cleanup_failure_email_notifications;
- $this->serverDiskUsageEmailNotifications = $this->settings->server_disk_usage_email_notifications;
- $this->serverReachableEmailNotifications = $this->settings->server_reachable_email_notifications;
- $this->serverUnreachableEmailNotifications = $this->settings->server_unreachable_email_notifications;
- }
- }
-
- public function submit()
- {
- try {
- $this->resetErrorBag();
- $this->saveModel();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function saveModel()
- {
- $this->syncData(true);
- $this->dispatch('success', 'Email notifications settings updated.');
- }
-
- public function instantSave(?string $type = null)
- {
- try {
- $this->resetErrorBag();
-
- if ($type === 'SMTP') {
- $this->submitSmtp();
- } elseif ($type === 'Resend') {
- $this->submitResend();
- } else {
- $this->smtpEnabled = false;
- $this->resendEnabled = false;
- $this->saveModel();
-
- return;
- }
- } catch (\Throwable $e) {
- if ($type === 'SMTP') {
- $this->smtpEnabled = false;
- } elseif ($type === 'Resend') {
- $this->resendEnabled = false;
- }
-
- return handleError($e, $this);
- } finally {
- $this->dispatch('refresh');
- }
- }
-
- public function submitSmtp()
- {
- try {
- $this->resetErrorBag();
- $this->validate([
- 'smtpEnabled' => 'boolean',
- 'smtpFromAddress' => 'required|email',
- 'smtpFromName' => 'required|string',
- 'smtpHost' => 'required|string',
- 'smtpPort' => 'required|numeric',
- 'smtpEncryption' => 'required|string|in:starttls,tls,none',
- 'smtpUsername' => 'nullable|string',
- 'smtpPassword' => 'nullable|string',
- 'smtpTimeout' => 'nullable|numeric',
- ], [
- 'smtpFromAddress.required' => 'From Address is required.',
- 'smtpFromAddress.email' => 'Please enter a valid email address.',
- 'smtpFromName.required' => 'From Name is required.',
- 'smtpHost.required' => 'SMTP Host is required.',
- 'smtpPort.required' => 'SMTP Port is required.',
- 'smtpPort.numeric' => 'SMTP Port must be a number.',
- 'smtpEncryption.required' => 'Encryption type is required.',
- ]);
-
- $this->settings->resend_enabled = false;
- $this->settings->use_instance_email_settings = false;
- $this->resendEnabled = false;
- $this->useInstanceEmailSettings = false;
-
- $this->settings->smtp_enabled = $this->smtpEnabled;
- $this->settings->smtp_from_address = $this->smtpFromAddress;
- $this->settings->smtp_from_name = $this->smtpFromName;
- $this->settings->smtp_host = $this->smtpHost;
- $this->settings->smtp_port = $this->smtpPort;
- $this->settings->smtp_encryption = $this->smtpEncryption;
- $this->settings->smtp_username = $this->smtpUsername;
- $this->settings->smtp_password = $this->smtpPassword;
- $this->settings->smtp_timeout = $this->smtpTimeout;
-
- $this->settings->save();
- $this->dispatch('success', 'SMTP settings updated.');
- } catch (\Throwable $e) {
- $this->smtpEnabled = false;
-
- return handleError($e);
- }
- }
-
- public function submitResend()
- {
- try {
- $this->resetErrorBag();
- $this->validate([
- 'resendEnabled' => 'boolean',
- 'resendApiKey' => 'required|string',
- 'smtpFromAddress' => 'required|email',
- 'smtpFromName' => 'required|string',
- ], [
- 'resendApiKey.required' => 'Resend API Key is required.',
- 'smtpFromAddress.required' => 'From Address is required.',
- 'smtpFromAddress.email' => 'Please enter a valid email address.',
- 'smtpFromName.required' => 'From Name is required.',
- ]);
-
- $this->settings->smtp_enabled = false;
- $this->settings->use_instance_email_settings = false;
- $this->smtpEnabled = false;
- $this->useInstanceEmailSettings = false;
-
- $this->settings->resend_enabled = $this->resendEnabled;
- $this->settings->resend_api_key = $this->resendApiKey;
- $this->settings->smtp_from_address = $this->smtpFromAddress;
- $this->settings->smtp_from_name = $this->smtpFromName;
-
- $this->settings->save();
- $this->dispatch('success', 'Resend settings updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function sendTestEmail()
- {
- try {
- $this->validate([
- 'testEmailAddress' => 'required|email',
- ], [
- 'testEmailAddress.required' => 'Test email address is required.',
- 'testEmailAddress.email' => 'Please enter a valid email address.',
- ]);
-
- $executed = RateLimiter::attempt(
- 'test-email:'.$this->team->id,
- $perMinute = 0,
- function () {
- $this->team?->notify(new Test($this->testEmailAddress, 'email'));
- $this->dispatch('success', 'Test Email sent.');
- },
- $decaySeconds = 10,
- );
-
- if (! $executed) {
- throw new \Exception('Too many messages sent!');
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function copyFromInstanceSettings()
- {
- $settings = instanceSettings();
-
- if ($settings->smtp_enabled) {
- $this->smtpEnabled = true;
- $this->smtpFromAddress = $settings->smtp_from_address;
- $this->smtpFromName = $settings->smtp_from_name;
- $this->smtpRecipients = $settings->smtp_recipients;
- $this->smtpHost = $settings->smtp_host;
- $this->smtpPort = $settings->smtp_port;
- $this->smtpEncryption = $settings->smtp_encryption;
- $this->smtpUsername = $settings->smtp_username;
- $this->smtpPassword = $settings->smtp_password;
- $this->smtpTimeout = $settings->smtp_timeout;
- $this->resendEnabled = false;
- $this->saveModel();
-
- return;
- }
- if ($settings->resend_enabled) {
- $this->resendEnabled = true;
- $this->resendApiKey = $settings->resend_api_key;
- $this->smtpEnabled = false;
- $this->saveModel();
-
- return;
- }
- $this->dispatch('error', 'Instance SMTP/Resend settings are not enabled.');
- }
-
- public function render()
- {
- return view('livewire.notifications.email');
- }
-}
diff --git a/app/Livewire/Notifications/Pushover.php b/app/Livewire/Notifications/Pushover.php
deleted file mode 100644
index f1e4c464da..0000000000
--- a/app/Livewire/Notifications/Pushover.php
+++ /dev/null
@@ -1,184 +0,0 @@
- '$refresh'];
-
- #[Locked]
- public Team $team;
-
- #[Locked]
- public PushoverNotificationSettings $settings;
-
- #[Validate(['boolean'])]
- public bool $pushoverEnabled = false;
-
- #[Validate(['nullable', 'string'])]
- public ?string $pushoverUserKey = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $pushoverApiToken = null;
-
- #[Validate(['boolean'])]
- public bool $deploymentSuccessPushoverNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $deploymentFailurePushoverNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $statusChangePushoverNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $backupSuccessPushoverNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $backupFailurePushoverNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $scheduledTaskSuccessPushoverNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $scheduledTaskFailurePushoverNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $dockerCleanupSuccessPushoverNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $dockerCleanupFailurePushoverNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $serverDiskUsagePushoverNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $serverReachablePushoverNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $serverUnreachablePushoverNotifications = true;
-
- public function mount()
- {
- try {
- $this->team = auth()->user()->currentTeam();
- $this->settings = $this->team->pushoverNotificationSettings;
- $this->syncData();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->settings->pushover_enabled = $this->pushoverEnabled;
- $this->settings->pushover_user_key = $this->pushoverUserKey;
- $this->settings->pushover_api_token = $this->pushoverApiToken;
-
- $this->settings->deployment_success_pushover_notifications = $this->deploymentSuccessPushoverNotifications;
- $this->settings->deployment_failure_pushover_notifications = $this->deploymentFailurePushoverNotifications;
- $this->settings->status_change_pushover_notifications = $this->statusChangePushoverNotifications;
- $this->settings->backup_success_pushover_notifications = $this->backupSuccessPushoverNotifications;
- $this->settings->backup_failure_pushover_notifications = $this->backupFailurePushoverNotifications;
- $this->settings->scheduled_task_success_pushover_notifications = $this->scheduledTaskSuccessPushoverNotifications;
- $this->settings->scheduled_task_failure_pushover_notifications = $this->scheduledTaskFailurePushoverNotifications;
- $this->settings->docker_cleanup_success_pushover_notifications = $this->dockerCleanupSuccessPushoverNotifications;
- $this->settings->docker_cleanup_failure_pushover_notifications = $this->dockerCleanupFailurePushoverNotifications;
- $this->settings->server_disk_usage_pushover_notifications = $this->serverDiskUsagePushoverNotifications;
- $this->settings->server_reachable_pushover_notifications = $this->serverReachablePushoverNotifications;
- $this->settings->server_unreachable_pushover_notifications = $this->serverUnreachablePushoverNotifications;
-
- $this->settings->save();
- refreshSession();
- } else {
- $this->pushoverEnabled = $this->settings->pushover_enabled;
- $this->pushoverUserKey = $this->settings->pushover_user_key;
- $this->pushoverApiToken = $this->settings->pushover_api_token;
-
- $this->deploymentSuccessPushoverNotifications = $this->settings->deployment_success_pushover_notifications;
- $this->deploymentFailurePushoverNotifications = $this->settings->deployment_failure_pushover_notifications;
- $this->statusChangePushoverNotifications = $this->settings->status_change_pushover_notifications;
- $this->backupSuccessPushoverNotifications = $this->settings->backup_success_pushover_notifications;
- $this->backupFailurePushoverNotifications = $this->settings->backup_failure_pushover_notifications;
- $this->scheduledTaskSuccessPushoverNotifications = $this->settings->scheduled_task_success_pushover_notifications;
- $this->scheduledTaskFailurePushoverNotifications = $this->settings->scheduled_task_failure_pushover_notifications;
- $this->dockerCleanupSuccessPushoverNotifications = $this->settings->docker_cleanup_success_pushover_notifications;
- $this->dockerCleanupFailurePushoverNotifications = $this->settings->docker_cleanup_failure_pushover_notifications;
- $this->serverDiskUsagePushoverNotifications = $this->settings->server_disk_usage_pushover_notifications;
- $this->serverReachablePushoverNotifications = $this->settings->server_reachable_pushover_notifications;
- $this->serverUnreachablePushoverNotifications = $this->settings->server_unreachable_pushover_notifications;
- }
- }
-
- public function instantSavePushoverEnabled()
- {
- try {
- $this->validate([
- 'pushoverUserKey' => 'required',
- 'pushoverApiToken' => 'required',
- ], [
- 'pushoverUserKey.required' => 'Pushover User Key is required.',
- 'pushoverApiToken.required' => 'Pushover API Token is required.',
- ]);
- $this->saveModel();
- } catch (\Throwable $e) {
- $this->pushoverEnabled = false;
-
- return handleError($e, $this);
- } finally {
- $this->dispatch('refresh');
- }
- }
-
- public function instantSave()
- {
- try {
- $this->syncData(true);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- $this->dispatch('refresh');
- }
- }
-
- public function submit()
- {
- try {
- $this->resetErrorBag();
- $this->syncData(true);
- $this->saveModel();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function saveModel()
- {
- $this->syncData(true);
- refreshSession();
- $this->dispatch('success', 'Settings saved.');
- }
-
- public function sendTestNotification()
- {
- try {
- $this->team->notify(new Test(channel: 'pushover'));
- $this->dispatch('success', 'Test notification sent.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.notifications.pushover');
- }
-}
diff --git a/app/Livewire/Notifications/Slack.php b/app/Livewire/Notifications/Slack.php
deleted file mode 100644
index f47ad8a979..0000000000
--- a/app/Livewire/Notifications/Slack.php
+++ /dev/null
@@ -1,177 +0,0 @@
- '$refresh'];
-
- #[Locked]
- public Team $team;
-
- #[Locked]
- public SlackNotificationSettings $settings;
-
- #[Validate(['boolean'])]
- public bool $slackEnabled = false;
-
- #[Validate(['url', 'nullable'])]
- public ?string $slackWebhookUrl = null;
-
- #[Validate(['boolean'])]
- public bool $deploymentSuccessSlackNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $deploymentFailureSlackNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $statusChangeSlackNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $backupSuccessSlackNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $backupFailureSlackNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $scheduledTaskSuccessSlackNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $scheduledTaskFailureSlackNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $dockerCleanupSuccessSlackNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $dockerCleanupFailureSlackNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $serverDiskUsageSlackNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $serverReachableSlackNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $serverUnreachableSlackNotifications = true;
-
- public function mount()
- {
- try {
- $this->team = auth()->user()->currentTeam();
- $this->settings = $this->team->slackNotificationSettings;
- $this->syncData();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->settings->slack_enabled = $this->slackEnabled;
- $this->settings->slack_webhook_url = $this->slackWebhookUrl;
-
- $this->settings->deployment_success_slack_notifications = $this->deploymentSuccessSlackNotifications;
- $this->settings->deployment_failure_slack_notifications = $this->deploymentFailureSlackNotifications;
- $this->settings->status_change_slack_notifications = $this->statusChangeSlackNotifications;
- $this->settings->backup_success_slack_notifications = $this->backupSuccessSlackNotifications;
- $this->settings->backup_failure_slack_notifications = $this->backupFailureSlackNotifications;
- $this->settings->scheduled_task_success_slack_notifications = $this->scheduledTaskSuccessSlackNotifications;
- $this->settings->scheduled_task_failure_slack_notifications = $this->scheduledTaskFailureSlackNotifications;
- $this->settings->docker_cleanup_success_slack_notifications = $this->dockerCleanupSuccessSlackNotifications;
- $this->settings->docker_cleanup_failure_slack_notifications = $this->dockerCleanupFailureSlackNotifications;
- $this->settings->server_disk_usage_slack_notifications = $this->serverDiskUsageSlackNotifications;
- $this->settings->server_reachable_slack_notifications = $this->serverReachableSlackNotifications;
- $this->settings->server_unreachable_slack_notifications = $this->serverUnreachableSlackNotifications;
-
- $this->settings->save();
- refreshSession();
- } else {
- $this->slackEnabled = $this->settings->slack_enabled;
- $this->slackWebhookUrl = $this->settings->slack_webhook_url;
-
- $this->deploymentSuccessSlackNotifications = $this->settings->deployment_success_slack_notifications;
- $this->deploymentFailureSlackNotifications = $this->settings->deployment_failure_slack_notifications;
- $this->statusChangeSlackNotifications = $this->settings->status_change_slack_notifications;
- $this->backupSuccessSlackNotifications = $this->settings->backup_success_slack_notifications;
- $this->backupFailureSlackNotifications = $this->settings->backup_failure_slack_notifications;
- $this->scheduledTaskSuccessSlackNotifications = $this->settings->scheduled_task_success_slack_notifications;
- $this->scheduledTaskFailureSlackNotifications = $this->settings->scheduled_task_failure_slack_notifications;
- $this->dockerCleanupSuccessSlackNotifications = $this->settings->docker_cleanup_success_slack_notifications;
- $this->dockerCleanupFailureSlackNotifications = $this->settings->docker_cleanup_failure_slack_notifications;
- $this->serverDiskUsageSlackNotifications = $this->settings->server_disk_usage_slack_notifications;
- $this->serverReachableSlackNotifications = $this->settings->server_reachable_slack_notifications;
- $this->serverUnreachableSlackNotifications = $this->settings->server_unreachable_slack_notifications;
- }
- }
-
- public function instantSaveSlackEnabled()
- {
- try {
- $this->validate([
- 'slackWebhookUrl' => 'required',
- ], [
- 'slackWebhookUrl.required' => 'Slack Webhook URL is required.',
- ]);
- $this->saveModel();
- } catch (\Throwable $e) {
- $this->slackEnabled = false;
-
- return handleError($e, $this);
- } finally {
- $this->dispatch('refresh');
- }
- }
-
- public function instantSave()
- {
- try {
- $this->syncData(true);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- $this->dispatch('refresh');
- }
- }
-
- public function submit()
- {
- try {
- $this->resetErrorBag();
- $this->syncData(true);
- $this->saveModel();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function saveModel()
- {
- $this->syncData(true);
- refreshSession();
- $this->dispatch('success', 'Settings saved.');
- }
-
- public function sendTestNotification()
- {
- try {
- $this->team->notify(new Test(channel: 'slack'));
- $this->dispatch('success', 'Test notification sent.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.notifications.slack');
- }
-}
diff --git a/app/Livewire/Notifications/Telegram.php b/app/Livewire/Notifications/Telegram.php
deleted file mode 100644
index 01afb4ac67..0000000000
--- a/app/Livewire/Notifications/Telegram.php
+++ /dev/null
@@ -1,245 +0,0 @@
- '$refresh'];
-
- #[Locked]
- public Team $team;
-
- #[Locked]
- public TelegramNotificationSettings $settings;
-
- #[Validate(['boolean'])]
- public bool $telegramEnabled = false;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramToken = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramChatId = null;
-
- #[Validate(['boolean'])]
- public bool $deploymentSuccessTelegramNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $deploymentFailureTelegramNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $statusChangeTelegramNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $backupSuccessTelegramNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $backupFailureTelegramNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $scheduledTaskSuccessTelegramNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $scheduledTaskFailureTelegramNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $dockerCleanupSuccessTelegramNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $dockerCleanupFailureTelegramNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $serverDiskUsageTelegramNotifications = true;
-
- #[Validate(['boolean'])]
- public bool $serverReachableTelegramNotifications = false;
-
- #[Validate(['boolean'])]
- public bool $serverUnreachableTelegramNotifications = true;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsDeploymentSuccessThreadId = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsDeploymentFailureThreadId = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsStatusChangeThreadId = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsBackupSuccessThreadId = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsBackupFailureThreadId = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsScheduledTaskSuccessThreadId = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsScheduledTaskFailureThreadId = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsDockerCleanupSuccessThreadId = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsDockerCleanupFailureThreadId = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsServerDiskUsageThreadId = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsServerReachableThreadId = null;
-
- #[Validate(['nullable', 'string'])]
- public ?string $telegramNotificationsServerUnreachableThreadId = null;
-
- public function mount()
- {
- try {
- $this->team = auth()->user()->currentTeam();
- $this->settings = $this->team->telegramNotificationSettings;
- $this->syncData();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->settings->telegram_enabled = $this->telegramEnabled;
- $this->settings->telegram_token = $this->telegramToken;
- $this->settings->telegram_chat_id = $this->telegramChatId;
-
- $this->settings->deployment_success_telegram_notifications = $this->deploymentSuccessTelegramNotifications;
- $this->settings->deployment_failure_telegram_notifications = $this->deploymentFailureTelegramNotifications;
- $this->settings->status_change_telegram_notifications = $this->statusChangeTelegramNotifications;
- $this->settings->backup_success_telegram_notifications = $this->backupSuccessTelegramNotifications;
- $this->settings->backup_failure_telegram_notifications = $this->backupFailureTelegramNotifications;
- $this->settings->scheduled_task_success_telegram_notifications = $this->scheduledTaskSuccessTelegramNotifications;
- $this->settings->scheduled_task_failure_telegram_notifications = $this->scheduledTaskFailureTelegramNotifications;
- $this->settings->docker_cleanup_success_telegram_notifications = $this->dockerCleanupSuccessTelegramNotifications;
- $this->settings->docker_cleanup_failure_telegram_notifications = $this->dockerCleanupFailureTelegramNotifications;
- $this->settings->server_disk_usage_telegram_notifications = $this->serverDiskUsageTelegramNotifications;
- $this->settings->server_reachable_telegram_notifications = $this->serverReachableTelegramNotifications;
- $this->settings->server_unreachable_telegram_notifications = $this->serverUnreachableTelegramNotifications;
-
- $this->settings->telegram_notifications_deployment_success_thread_id = $this->telegramNotificationsDeploymentSuccessThreadId;
- $this->settings->telegram_notifications_deployment_failure_thread_id = $this->telegramNotificationsDeploymentFailureThreadId;
- $this->settings->telegram_notifications_status_change_thread_id = $this->telegramNotificationsStatusChangeThreadId;
- $this->settings->telegram_notifications_backup_success_thread_id = $this->telegramNotificationsBackupSuccessThreadId;
- $this->settings->telegram_notifications_backup_failure_thread_id = $this->telegramNotificationsBackupFailureThreadId;
- $this->settings->telegram_notifications_scheduled_task_success_thread_id = $this->telegramNotificationsScheduledTaskSuccessThreadId;
- $this->settings->telegram_notifications_scheduled_task_failure_thread_id = $this->telegramNotificationsScheduledTaskFailureThreadId;
- $this->settings->telegram_notifications_docker_cleanup_success_thread_id = $this->telegramNotificationsDockerCleanupSuccessThreadId;
- $this->settings->telegram_notifications_docker_cleanup_failure_thread_id = $this->telegramNotificationsDockerCleanupFailureThreadId;
- $this->settings->telegram_notifications_server_disk_usage_thread_id = $this->telegramNotificationsServerDiskUsageThreadId;
- $this->settings->telegram_notifications_server_reachable_thread_id = $this->telegramNotificationsServerReachableThreadId;
- $this->settings->telegram_notifications_server_unreachable_thread_id = $this->telegramNotificationsServerUnreachableThreadId;
-
- $this->settings->save();
- } else {
- $this->telegramEnabled = $this->settings->telegram_enabled;
- $this->telegramToken = $this->settings->telegram_token;
- $this->telegramChatId = $this->settings->telegram_chat_id;
-
- $this->deploymentSuccessTelegramNotifications = $this->settings->deployment_success_telegram_notifications;
- $this->deploymentFailureTelegramNotifications = $this->settings->deployment_failure_telegram_notifications;
- $this->statusChangeTelegramNotifications = $this->settings->status_change_telegram_notifications;
- $this->backupSuccessTelegramNotifications = $this->settings->backup_success_telegram_notifications;
- $this->backupFailureTelegramNotifications = $this->settings->backup_failure_telegram_notifications;
- $this->scheduledTaskSuccessTelegramNotifications = $this->settings->scheduled_task_success_telegram_notifications;
- $this->scheduledTaskFailureTelegramNotifications = $this->settings->scheduled_task_failure_telegram_notifications;
- $this->dockerCleanupSuccessTelegramNotifications = $this->settings->docker_cleanup_success_telegram_notifications;
- $this->dockerCleanupFailureTelegramNotifications = $this->settings->docker_cleanup_failure_telegram_notifications;
- $this->serverDiskUsageTelegramNotifications = $this->settings->server_disk_usage_telegram_notifications;
- $this->serverReachableTelegramNotifications = $this->settings->server_reachable_telegram_notifications;
- $this->serverUnreachableTelegramNotifications = $this->settings->server_unreachable_telegram_notifications;
-
- $this->telegramNotificationsDeploymentSuccessThreadId = $this->settings->telegram_notifications_deployment_success_thread_id;
- $this->telegramNotificationsDeploymentFailureThreadId = $this->settings->telegram_notifications_deployment_failure_thread_id;
- $this->telegramNotificationsStatusChangeThreadId = $this->settings->telegram_notifications_status_change_thread_id;
- $this->telegramNotificationsBackupSuccessThreadId = $this->settings->telegram_notifications_backup_success_thread_id;
- $this->telegramNotificationsBackupFailureThreadId = $this->settings->telegram_notifications_backup_failure_thread_id;
- $this->telegramNotificationsScheduledTaskSuccessThreadId = $this->settings->telegram_notifications_scheduled_task_success_thread_id;
- $this->telegramNotificationsScheduledTaskFailureThreadId = $this->settings->telegram_notifications_scheduled_task_failure_thread_id;
- $this->telegramNotificationsDockerCleanupSuccessThreadId = $this->settings->telegram_notifications_docker_cleanup_success_thread_id;
- $this->telegramNotificationsDockerCleanupFailureThreadId = $this->settings->telegram_notifications_docker_cleanup_failure_thread_id;
- $this->telegramNotificationsServerDiskUsageThreadId = $this->settings->telegram_notifications_server_disk_usage_thread_id;
- $this->telegramNotificationsServerReachableThreadId = $this->settings->telegram_notifications_server_reachable_thread_id;
- $this->telegramNotificationsServerUnreachableThreadId = $this->settings->telegram_notifications_server_unreachable_thread_id;
- }
- }
-
- public function instantSave()
- {
- try {
- $this->syncData(true);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- $this->dispatch('refresh');
- }
- }
-
- public function submit()
- {
- try {
- $this->resetErrorBag();
- $this->syncData(true);
- $this->saveModel();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSaveTelegramEnabled()
- {
- try {
- $this->validate([
- 'telegramToken' => 'required',
- 'telegramChatId' => 'required',
- ], [
- 'telegramToken.required' => 'Telegram Token is required.',
- 'telegramChatId.required' => 'Telegram Chat ID is required.',
- ]);
- $this->saveModel();
- } catch (\Throwable $e) {
- $this->telegramEnabled = false;
-
- return handleError($e, $this);
- } finally {
- $this->dispatch('refresh');
- }
- }
-
- public function saveModel()
- {
- $this->syncData(true);
- refreshSession();
- $this->dispatch('success', 'Settings saved.');
- }
-
- public function sendTestNotification()
- {
- try {
- $this->team->notify(new Test(channel: 'telegram'));
- $this->dispatch('success', 'Test notification sent.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.notifications.telegram');
- }
-}
diff --git a/app/Livewire/Profile/Index.php b/app/Livewire/Profile/Index.php
deleted file mode 100644
index 53314cd5c3..0000000000
--- a/app/Livewire/Profile/Index.php
+++ /dev/null
@@ -1,82 +0,0 @@
-userId = Auth::id();
- $this->name = Auth::user()->name;
- $this->email = Auth::user()->email;
- }
-
- public function submit()
- {
- try {
- $this->validate([
- 'name' => 'required',
- ]);
- Auth::user()->update([
- 'name' => $this->name,
- ]);
-
- $this->dispatch('success', 'Profile updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function resetPassword()
- {
- try {
- $this->validate([
- 'current_password' => ['required'],
- 'new_password' => ['required', Password::defaults(), 'confirmed'],
- ]);
- if (! Hash::check($this->current_password, auth()->user()->password)) {
- $this->dispatch('error', 'Current password is incorrect.');
-
- return;
- }
- if ($this->new_password !== $this->new_password_confirmation) {
- $this->dispatch('error', 'The two new passwords does not match.');
-
- return;
- }
- auth()->user()->update([
- 'password' => Hash::make($this->new_password),
- ]);
- $this->dispatch('success', 'Password updated.');
- $this->current_password = '';
- $this->new_password = '';
- $this->new_password_confirmation = '';
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.profile.index');
- }
-}
diff --git a/app/Livewire/Project/AddEmpty.php b/app/Livewire/Project/AddEmpty.php
deleted file mode 100644
index 07873c059d..0000000000
--- a/app/Livewire/Project/AddEmpty.php
+++ /dev/null
@@ -1,34 +0,0 @@
-validate();
- $project = Project::create([
- 'name' => $this->name,
- 'description' => $this->description,
- 'team_id' => currentTeam()->id,
- 'uuid' => (string) new Cuid2,
- ]);
-
- return redirect()->route('project.show', $project->uuid);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Project/Application/Advanced.php b/app/Livewire/Project/Application/Advanced.php
deleted file mode 100644
index bd13888060..0000000000
--- a/app/Livewire/Project/Application/Advanced.php
+++ /dev/null
@@ -1,228 +0,0 @@
-syncData();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->application->settings->is_force_https_enabled = $this->isForceHttpsEnabled;
- $this->application->settings->is_git_submodules_enabled = $this->isGitSubmodulesEnabled;
- $this->application->settings->is_git_lfs_enabled = $this->isGitLfsEnabled;
- $this->application->settings->is_preview_deployments_enabled = $this->isPreviewDeploymentsEnabled;
- $this->application->settings->is_auto_deploy_enabled = $this->isAutoDeployEnabled;
- $this->application->settings->is_log_drain_enabled = $this->isLogDrainEnabled;
- $this->application->settings->is_gpu_enabled = $this->isGpuEnabled;
- $this->application->settings->gpu_driver = $this->gpuDriver;
- $this->application->settings->gpu_count = $this->gpuCount;
- $this->application->settings->gpu_device_ids = $this->gpuDeviceIds;
- $this->application->settings->gpu_options = $this->gpuOptions;
- $this->application->settings->is_build_server_enabled = $this->isBuildServerEnabled;
- $this->application->settings->is_consistent_container_name_enabled = $this->isConsistentContainerNameEnabled;
- $this->application->settings->custom_internal_name = $this->customInternalName;
- $this->application->settings->is_gzip_enabled = $this->isGzipEnabled;
- $this->application->settings->is_stripprefix_enabled = $this->isStripprefixEnabled;
- $this->application->settings->is_raw_compose_deployment_enabled = $this->isRawComposeDeploymentEnabled;
- $this->application->settings->connect_to_docker_network = $this->isConnectToDockerNetworkEnabled;
- $this->application->settings->disable_build_cache = $this->disableBuildCache;
- $this->application->settings->save();
- } else {
- $this->isForceHttpsEnabled = $this->application->isForceHttpsEnabled();
- $this->isGzipEnabled = $this->application->isGzipEnabled();
- $this->isStripprefixEnabled = $this->application->isStripprefixEnabled();
- $this->isLogDrainEnabled = $this->application->isLogDrainEnabled();
-
- $this->isGitSubmodulesEnabled = $this->application->settings->is_git_submodules_enabled;
- $this->isGitLfsEnabled = $this->application->settings->is_git_lfs_enabled;
- $this->isPreviewDeploymentsEnabled = $this->application->settings->is_preview_deployments_enabled;
- $this->isAutoDeployEnabled = $this->application->settings->is_auto_deploy_enabled;
- $this->isGpuEnabled = $this->application->settings->is_gpu_enabled;
- $this->gpuDriver = $this->application->settings->gpu_driver;
- $this->gpuCount = $this->application->settings->gpu_count;
- $this->gpuDeviceIds = $this->application->settings->gpu_device_ids;
- $this->gpuOptions = $this->application->settings->gpu_options;
- $this->isBuildServerEnabled = $this->application->settings->is_build_server_enabled;
- $this->isConsistentContainerNameEnabled = $this->application->settings->is_consistent_container_name_enabled;
- $this->customInternalName = $this->application->settings->custom_internal_name;
- $this->isRawComposeDeploymentEnabled = $this->application->settings->is_raw_compose_deployment_enabled;
- $this->isConnectToDockerNetworkEnabled = $this->application->settings->connect_to_docker_network;
- $this->disableBuildCache = $this->application->settings->disable_build_cache;
- }
- }
-
- private function resetDefaultLabels()
- {
- if ($this->application->settings->is_container_label_readonly_enabled === false) {
- return;
- }
- $customLabels = str(implode('|coolify|', generateLabelsApplication($this->application)))->replace('|coolify|', "\n");
- $this->application->custom_labels = base64_encode($customLabels);
- $this->application->save();
- }
-
- public function instantSave()
- {
- try {
- $reset = false;
- if ($this->isLogDrainEnabled) {
- if (! $this->application->destination->server->isLogDrainEnabled()) {
- $this->isLogDrainEnabled = false;
- $this->syncData(true);
- $this->dispatch('error', 'Log drain is not enabled on this server.');
-
- return;
- }
- }
- if ($this->application->isForceHttpsEnabled() !== $this->isForceHttpsEnabled ||
- $this->application->isGzipEnabled() !== $this->isGzipEnabled ||
- $this->application->isStripprefixEnabled() !== $this->isStripprefixEnabled
- ) {
- $reset = true;
- }
-
- if ($this->application->settings->is_raw_compose_deployment_enabled) {
- $this->application->oldRawParser();
- } else {
- $this->application->parse();
- }
- $this->syncData(true);
-
- if ($reset) {
- $this->resetDefaultLabels();
- }
-
- $this->dispatch('success', 'Settings saved.');
- $this->dispatch('configurationChanged');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- if ($this->gpuCount && $this->gpuDeviceIds) {
- $this->dispatch('error', 'You cannot set both GPU count and GPU device IDs.');
- $this->gpuCount = null;
- $this->gpuDeviceIds = null;
- $this->syncData(true);
-
- return;
- }
- $this->syncData(true);
- $this->dispatch('success', 'Settings saved.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function saveCustomName()
- {
- if (str($this->customInternalName)->isNotEmpty()) {
- $this->customInternalName = str($this->customInternalName)->slug()->value();
- } else {
- $this->customInternalName = null;
- }
- if (is_null($this->customInternalName)) {
- $this->syncData(true);
- $this->dispatch('success', 'Custom name saved.');
-
- return;
- }
- $customInternalName = $this->customInternalName;
- $server = $this->application->destination->server;
- $allApplications = $server->applications();
-
- $foundSameInternalName = $allApplications->filter(function ($application) {
- return $application->id !== $this->application->id && $application->settings->custom_internal_name === $this->customInternalName;
- });
- if ($foundSameInternalName->isNotEmpty()) {
- $this->dispatch('error', 'This custom container name is already in use by another application on this server.');
- $this->customInternalName = $customInternalName;
- $this->syncData(true);
-
- return;
- }
- $this->syncData(true);
- $this->dispatch('success', 'Custom name saved.');
- }
-
- public function render()
- {
- return view('livewire.project.application.advanced');
- }
-}
diff --git a/app/Livewire/Project/Application/Configuration.php b/app/Livewire/Project/Application/Configuration.php
deleted file mode 100644
index 56e0caf750..0000000000
--- a/app/Livewire/Project/Application/Configuration.php
+++ /dev/null
@@ -1,48 +0,0 @@
- '$refresh'];
-
- public function mount()
- {
- $this->currentRoute = request()->route()->getName();
- $project = currentTeam()
- ->projects()
- ->select('id', 'uuid', 'team_id')
- ->where('uuid', request()->route('project_uuid'))
- ->firstOrFail();
- $environment = $project->environments()
- ->select('id', 'uuid', 'name', 'project_id')
- ->where('uuid', request()->route('environment_uuid'))
- ->firstOrFail();
- $application = $environment->applications()
- ->with(['destination'])
- ->where('uuid', request()->route('application_uuid'))
- ->firstOrFail();
-
- $this->project = $project;
- $this->environment = $environment;
- $this->application = $application;
- }
-
- public function render()
- {
- return view('livewire.project.application.configuration');
- }
-}
diff --git a/app/Livewire/Project/Application/Deployment/Index.php b/app/Livewire/Project/Application/Deployment/Index.php
deleted file mode 100644
index 0567a6e8a6..0000000000
--- a/app/Livewire/Project/Application/Deployment/Index.php
+++ /dev/null
@@ -1,113 +0,0 @@
-load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
- if (! $project) {
- return redirect()->route('dashboard');
- }
- $environment = $project->load(['environments'])->environments->where('uuid', request()->route('environment_uuid'))->first()->load(['applications']);
- if (! $environment) {
- return redirect()->route('dashboard');
- }
- $application = $environment->applications->where('uuid', request()->route('application_uuid'))->first();
- if (! $application) {
- return redirect()->route('dashboard');
- }
- ['deployments' => $deployments, 'count' => $count] = $application->deployments(0, $this->default_take);
- $this->application = $application;
- $this->deployments = $deployments;
- $this->deployments_count = $count;
- $this->current_url = url()->current();
- $this->show_pull_request_only();
- $this->show_more();
- }
-
- private function show_pull_request_only()
- {
- if ($this->pull_request_id) {
- $this->deployments = $this->deployments->where('pull_request_id', $this->pull_request_id);
- }
- }
-
- private function show_more()
- {
- if ($this->deployments->count() !== 0) {
- $this->show_next = true;
- if ($this->deployments->count() < $this->default_take) {
- $this->show_next = false;
- }
-
- return;
- }
- }
-
- public function reload_deployments()
- {
- $this->load_deployments();
- }
-
- public function previous_page(?int $take = null)
- {
- if ($take) {
- $this->skip = $this->skip - $take;
- }
- $this->skip = $this->skip - $this->default_take;
- if ($this->skip < 0) {
- $this->show_prev = false;
- $this->skip = 0;
- }
- $this->load_deployments();
- }
-
- public function next_page(?int $take = null)
- {
- if ($take) {
- $this->skip = $this->skip + $take;
- }
- $this->show_prev = true;
- $this->load_deployments();
- }
-
- public function load_deployments()
- {
- ['deployments' => $deployments, 'count' => $count] = $this->application->deployments($this->skip, $this->default_take);
- $this->deployments = $deployments;
- $this->deployments_count = $count;
- $this->show_pull_request_only();
- $this->show_more();
- }
-
- public function render()
- {
- return view('livewire.project.application.deployment.index');
- }
-}
diff --git a/app/Livewire/Project/Application/Deployment/Show.php b/app/Livewire/Project/Application/Deployment/Show.php
deleted file mode 100644
index 7b2ac09d36..0000000000
--- a/app/Livewire/Project/Application/Deployment/Show.php
+++ /dev/null
@@ -1,94 +0,0 @@
-route('deployment_uuid');
-
- $project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
- if (! $project) {
- return redirect()->route('dashboard');
- }
- $environment = $project->load(['environments'])->environments->where('uuid', request()->route('environment_uuid'))->first()->load(['applications']);
- if (! $environment) {
- return redirect()->route('dashboard');
- }
- $application = $environment->applications->where('uuid', request()->route('application_uuid'))->first();
- if (! $application) {
- return redirect()->route('dashboard');
- }
- $application_deployment_queue = ApplicationDeploymentQueue::where('deployment_uuid', $deploymentUuid)->first();
- if (! $application_deployment_queue) {
- return redirect()->route('project.application.deployment.index', [
- 'project_uuid' => $project->uuid,
- 'environment_uuid' => $environment->uuid,
- 'application_uuid' => $application->uuid,
- ]);
- }
- $this->application = $application;
- $this->application_deployment_queue = $application_deployment_queue;
- $this->horizon_job_status = $this->application_deployment_queue->getHorizonJobStatus();
- $this->deployment_uuid = $deploymentUuid;
- $this->isKeepAliveOn();
- }
-
- public function refreshQueue()
- {
- $this->application_deployment_queue->refresh();
- }
-
- private function isKeepAliveOn()
- {
- if (data_get($this->application_deployment_queue, 'status') === 'finished' || data_get($this->application_deployment_queue, 'status') === 'failed') {
- $this->isKeepAliveOn = false;
- } else {
- $this->isKeepAliveOn = true;
- }
- }
-
- public function polling()
- {
- $this->dispatch('deploymentFinished');
- $this->application_deployment_queue->refresh();
- $this->horizon_job_status = $this->application_deployment_queue->getHorizonJobStatus();
- $this->isKeepAliveOn();
- }
-
- public function getLogLinesProperty()
- {
- return decode_remote_command_output($this->application_deployment_queue)->map(function ($logLine) {
- $logLine['line'] = e($logLine['line']);
- $logLine['line'] = preg_replace(
- '/(https?:\/\/[^\s]+)/',
- '$1 ',
- $logLine['line'],
- );
-
- return $logLine;
- });
- }
-
- public function render()
- {
- return view('livewire.project.application.deployment.show');
- }
-}
diff --git a/app/Livewire/Project/Application/DeploymentNavbar.php b/app/Livewire/Project/Application/DeploymentNavbar.php
deleted file mode 100644
index 66f387fcfa..0000000000
--- a/app/Livewire/Project/Application/DeploymentNavbar.php
+++ /dev/null
@@ -1,91 +0,0 @@
-application = Application::ownedByCurrentTeam()->find($this->application_deployment_queue->application_id);
- $this->server = $this->application->destination->server;
- $this->is_debug_enabled = $this->application->settings->is_debug_enabled;
- }
-
- public function deploymentFinished()
- {
- $this->application_deployment_queue->refresh();
- }
-
- public function show_debug()
- {
- $this->application->settings->is_debug_enabled = ! $this->application->settings->is_debug_enabled;
- $this->application->settings->save();
- $this->is_debug_enabled = $this->application->settings->is_debug_enabled;
- $this->dispatch('refreshQueue');
- }
-
- public function force_start()
- {
- try {
- force_start_deployment($this->application_deployment_queue);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function cancel()
- {
- $kill_command = "docker rm -f {$this->application_deployment_queue->deployment_uuid}";
- $build_server_id = $this->application_deployment_queue->build_server_id ?? $this->application->destination->server_id;
- $server_id = $this->application_deployment_queue->server_id ?? $this->application->destination->server_id;
- try {
- if ($this->application->settings->is_build_server_enabled) {
- $server = Server::ownedByCurrentTeam()->find($build_server_id);
- } else {
- $server = Server::ownedByCurrentTeam()->find($server_id);
- }
- if ($this->application_deployment_queue->logs) {
- $previous_logs = json_decode($this->application_deployment_queue->logs, associative: true, flags: JSON_THROW_ON_ERROR);
-
- $new_log_entry = [
- 'command' => $kill_command,
- 'output' => 'Deployment cancelled by user.',
- 'type' => 'stderr',
- 'order' => count($previous_logs) + 1,
- 'timestamp' => Carbon::now('UTC'),
- 'hidden' => false,
- ];
- $previous_logs[] = $new_log_entry;
- $this->application_deployment_queue->update([
- 'logs' => json_encode($previous_logs, flags: JSON_THROW_ON_ERROR),
- ]);
- }
- instant_remote_process([$kill_command], $server);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- $this->application_deployment_queue->update([
- 'current_process_id' => null,
- 'status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value,
- ]);
- next_after_cancel($server);
- }
- }
-}
diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php
deleted file mode 100644
index 08fff38c61..0000000000
--- a/app/Livewire/Project/Application/General.php
+++ /dev/null
@@ -1,458 +0,0 @@
- '$refresh',
- ];
-
- protected $rules = [
- 'application.name' => 'required',
- 'application.description' => 'nullable',
- 'application.fqdn' => 'nullable',
- 'application.git_repository' => 'required',
- 'application.git_branch' => 'required',
- 'application.git_commit_sha' => 'nullable',
- 'application.install_command' => 'nullable',
- 'application.build_command' => 'nullable',
- 'application.start_command' => 'nullable',
- 'application.build_pack' => 'required',
- 'application.static_image' => 'required',
- 'application.base_directory' => 'required',
- 'application.publish_directory' => 'nullable',
- 'application.ports_exposes' => 'required',
- 'application.ports_mappings' => 'nullable',
- 'application.dockerfile' => 'nullable',
- 'application.docker_registry_image_name' => 'nullable',
- 'application.docker_registry_image_tag' => 'nullable',
- 'application.dockerfile_location' => 'nullable',
- 'application.docker_compose_location' => 'nullable',
- 'application.docker_compose' => 'nullable',
- 'application.docker_compose_raw' => 'nullable',
- 'application.dockerfile_target_build' => 'nullable',
- 'application.docker_compose_custom_start_command' => 'nullable',
- 'application.docker_compose_custom_build_command' => 'nullable',
- 'application.custom_labels' => 'nullable',
- 'application.custom_docker_run_options' => 'nullable',
- 'application.pre_deployment_command' => 'nullable',
- 'application.pre_deployment_command_container' => 'nullable',
- 'application.post_deployment_command' => 'nullable',
- 'application.post_deployment_command_container' => 'nullable',
- 'application.custom_nginx_configuration' => 'nullable',
- 'application.settings.is_static' => 'boolean|required',
- 'application.settings.is_build_server_enabled' => 'boolean|required',
- 'application.settings.is_container_label_escape_enabled' => 'boolean|required',
- 'application.settings.is_container_label_readonly_enabled' => 'boolean|required',
- 'application.settings.is_preserve_repository_enabled' => 'boolean|required',
- 'application.watch_paths' => 'nullable',
- 'application.redirect' => 'string|required',
- ];
-
- protected $validationAttributes = [
- 'application.name' => 'name',
- 'application.description' => 'description',
- 'application.fqdn' => 'FQDN',
- 'application.git_repository' => 'Git repository',
- 'application.git_branch' => 'Git branch',
- 'application.git_commit_sha' => 'Git commit SHA',
- 'application.install_command' => 'Install command',
- 'application.build_command' => 'Build command',
- 'application.start_command' => 'Start command',
- 'application.build_pack' => 'Build pack',
- 'application.static_image' => 'Static image',
- 'application.base_directory' => 'Base directory',
- 'application.publish_directory' => 'Publish directory',
- 'application.ports_exposes' => 'Ports exposes',
- 'application.ports_mappings' => 'Ports mappings',
- 'application.dockerfile' => 'Dockerfile',
- 'application.docker_registry_image_name' => 'Docker registry image name',
- 'application.docker_registry_image_tag' => 'Docker registry image tag',
- 'application.dockerfile_location' => 'Dockerfile location',
- 'application.docker_compose_location' => 'Docker compose location',
- 'application.docker_compose' => 'Docker compose',
- 'application.docker_compose_raw' => 'Docker compose raw',
- 'application.custom_labels' => 'Custom labels',
- 'application.dockerfile_target_build' => 'Dockerfile target build',
- 'application.custom_docker_run_options' => 'Custom docker run commands',
- 'application.docker_compose_custom_start_command' => 'Docker compose custom start command',
- 'application.docker_compose_custom_build_command' => 'Docker compose custom build command',
- 'application.custom_nginx_configuration' => 'Custom Nginx configuration',
- 'application.settings.is_static' => 'Is static',
- 'application.settings.is_build_server_enabled' => 'Is build server enabled',
- 'application.settings.is_container_label_escape_enabled' => 'Is container label escape enabled',
- 'application.settings.is_container_label_readonly_enabled' => 'Is container label readonly',
- 'application.settings.is_preserve_repository_enabled' => 'Is preserve repository enabled',
- 'application.watch_paths' => 'Watch paths',
- 'application.redirect' => 'Redirect',
- ];
-
- public function mount()
- {
- try {
- $this->parsedServices = $this->application->parse();
- if (is_null($this->parsedServices) || empty($this->parsedServices)) {
- $this->dispatch('error', 'Failed to parse your docker-compose file. Please check the syntax and try again.');
-
- return;
- }
- } catch (\Throwable $e) {
- $this->dispatch('error', $e->getMessage());
- }
- if ($this->application->build_pack === 'dockercompose') {
- $this->application->fqdn = null;
- $this->application->settings->save();
- }
- $this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : [];
- $this->ports_exposes = $this->application->ports_exposes;
- $this->is_preserve_repository_enabled = $this->application->settings->is_preserve_repository_enabled;
- $this->is_container_label_escape_enabled = $this->application->settings->is_container_label_escape_enabled;
- $this->customLabels = $this->application->parseContainerLabels();
- if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && $this->application->settings->is_container_label_readonly_enabled === true) {
- $this->customLabels = str(implode('|coolify|', generateLabelsApplication($this->application)))->replace('|coolify|', "\n");
- $this->application->custom_labels = base64_encode($this->customLabels);
- $this->application->save();
- }
- $this->initialDockerComposeLocation = $this->application->docker_compose_location;
- if ($this->application->build_pack === 'dockercompose' && ! $this->application->docker_compose_raw) {
- $this->initLoadingCompose = true;
- $this->dispatch('info', 'Loading docker compose file.');
- }
-
- if (str($this->application->status)->startsWith('running') && is_null($this->application->config_hash)) {
- $this->dispatch('configurationChanged');
- }
- }
-
- public function instantSave()
- {
- $this->application->settings->save();
- $this->dispatch('success', 'Settings saved.');
- $this->application->refresh();
-
- // If port_exposes changed, reset default labels
- if ($this->ports_exposes !== $this->application->ports_exposes || $this->is_container_label_escape_enabled !== $this->application->settings->is_container_label_escape_enabled) {
- $this->resetDefaultLabels(false);
- }
- if ($this->is_preserve_repository_enabled !== $this->application->settings->is_preserve_repository_enabled) {
- if ($this->application->settings->is_preserve_repository_enabled === false) {
- $this->application->fileStorages->each(function ($storage) {
- $storage->is_based_on_git = $this->application->settings->is_preserve_repository_enabled;
- $storage->save();
- });
- }
- }
- if ($this->application->settings->is_container_label_readonly_enabled) {
- $this->resetDefaultLabels(false);
- }
- }
-
- public function loadComposeFile($isInit = false)
- {
- try {
- if ($isInit && $this->application->docker_compose_raw) {
- return;
- }
-
- // Must reload the application to get the latest database changes
- // Why? Not sure, but it works.
- // $this->application->refresh();
-
- ['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation] = $this->application->loadComposeFile($isInit);
- if (is_null($this->parsedServices)) {
- $this->dispatch('error', 'Failed to parse your docker-compose file. Please check the syntax and try again.');
-
- return;
- }
- $this->application->parse();
- $this->dispatch('success', 'Docker compose file loaded.');
- $this->dispatch('compose_loaded');
- $this->dispatch('refreshStorages');
- $this->dispatch('refreshEnvs');
- } catch (\Throwable $e) {
- $this->application->docker_compose_location = $this->initialDockerComposeLocation;
- $this->application->save();
-
- return handleError($e, $this);
- } finally {
- $this->initLoadingCompose = false;
- }
- }
-
- public function generateDomain(string $serviceName)
- {
- $uuid = new Cuid2;
- $domain = generateFqdn($this->application->destination->server, $uuid);
- $this->parsedServiceDomains[$serviceName]['domain'] = $domain;
- $this->application->docker_compose_domains = json_encode($this->parsedServiceDomains);
- $this->application->save();
- $this->dispatch('success', 'Domain generated.');
- if ($this->application->build_pack === 'dockercompose') {
- $this->loadComposeFile();
- }
-
- return $domain;
- }
-
- public function updatedApplicationBaseDirectory()
- {
- if ($this->application->build_pack === 'dockercompose') {
- $this->loadComposeFile();
- }
- }
-
- public function updatedApplicationSettingsIsStatic($value)
- {
- if ($value) {
- $this->generateNginxConfiguration();
- }
- }
-
- public function updatedApplicationBuildPack()
- {
- if ($this->application->build_pack !== 'nixpacks') {
- $this->application->settings->is_static = false;
- $this->application->settings->save();
- } else {
- $this->application->ports_exposes = $this->ports_exposes = 3000;
- $this->resetDefaultLabels(false);
- }
- if ($this->application->build_pack === 'dockercompose') {
- $this->application->fqdn = null;
- $this->application->settings->save();
- }
- if ($this->application->build_pack === 'static') {
- $this->application->ports_exposes = $this->ports_exposes = 80;
- $this->resetDefaultLabels(false);
- $this->generateNginxConfiguration();
- }
- $this->submit();
- $this->dispatch('buildPackUpdated');
- }
-
- public function getWildcardDomain()
- {
- $server = data_get($this->application, 'destination.server');
- if ($server) {
- $fqdn = generateFqdn($server, $this->application->uuid);
- $this->application->fqdn = $fqdn;
- $this->application->save();
- $this->resetDefaultLabels();
- $this->dispatch('success', 'Wildcard domain generated.');
- }
- }
-
- public function generateNginxConfiguration()
- {
- $this->application->custom_nginx_configuration = defaultNginxConfiguration();
- $this->application->save();
- $this->dispatch('success', 'Nginx configuration generated.');
- }
-
- public function resetDefaultLabels($manualReset = false)
- {
- try {
- if (! $this->application->settings->is_container_label_readonly_enabled && ! $manualReset) {
- return;
- }
- $this->customLabels = str(implode('|coolify|', generateLabelsApplication($this->application)))->replace('|coolify|', "\n");
- $this->ports_exposes = $this->application->ports_exposes;
- $this->is_container_label_escape_enabled = $this->application->settings->is_container_label_escape_enabled;
- $this->application->custom_labels = base64_encode($this->customLabels);
- $this->application->save();
- if ($this->application->build_pack === 'dockercompose') {
- $this->loadComposeFile();
- }
- $this->dispatch('configurationChanged');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function checkFqdns($showToaster = true)
- {
- if (data_get($this->application, 'fqdn')) {
- $domains = str($this->application->fqdn)->trim()->explode(',');
- if ($this->application->additional_servers->count() === 0) {
- foreach ($domains as $domain) {
- if (! validate_dns_entry($domain, $this->application->destination->server)) {
- $showToaster && $this->dispatch('error', 'Validating DNS failed.', "Make sure you have added the DNS records correctly. $domain->{$this->application->destination->server->ip} Check this documentation for further help.");
- }
- }
- }
- check_domain_usage(resource: $this->application);
- $this->application->fqdn = $domains->implode(',');
- $this->resetDefaultLabels(false);
- }
- }
-
- public function setRedirect()
- {
- try {
- $has_www = collect($this->application->fqdns)->filter(fn ($fqdn) => str($fqdn)->contains('www.'))->count();
- if ($has_www === 0 && $this->application->redirect === 'www') {
- $this->dispatch('error', 'You want to redirect to www, but you do not have a www domain set. Please add www to your domain list and as an A DNS record (if applicable).');
-
- return;
- }
- $this->application->save();
- $this->resetDefaultLabels();
- $this->dispatch('success', 'Redirect updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit($showToaster = true)
- {
- try {
- $this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
- $this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim();
- $this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
- Url::fromString($domain, ['http', 'https']);
-
- return str($domain)->trim()->lower();
- });
-
- $this->application->fqdn = $this->application->fqdn->unique()->implode(',');
- $warning = sslipDomainWarning($this->application->fqdn);
- if ($warning) {
- $this->dispatch('warning', __('warning.sslipdomain'));
- }
- // $this->resetDefaultLabels();
-
- if ($this->application->isDirty('redirect')) {
- $this->setRedirect();
- }
-
- $this->checkFqdns();
-
- $this->application->save();
- if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && ! $this->application->settings->is_container_label_readonly_enabled) {
- $this->customLabels = str(implode('|coolify|', generateLabelsApplication($this->application)))->replace('|coolify|', "\n");
- $this->application->custom_labels = base64_encode($this->customLabels);
- $this->application->save();
- }
-
- if ($this->application->build_pack === 'dockercompose' && $this->initialDockerComposeLocation !== $this->application->docker_compose_location) {
- $compose_return = $this->loadComposeFile();
- if ($compose_return instanceof \Livewire\Features\SupportEvents\Event) {
- return;
- }
- }
- $this->validate();
-
- if ($this->ports_exposes !== $this->application->ports_exposes || $this->is_container_label_escape_enabled !== $this->application->settings->is_container_label_escape_enabled) {
- $this->resetDefaultLabels();
- }
- if (data_get($this->application, 'build_pack') === 'dockerimage') {
- $this->validate([
- 'application.docker_registry_image_name' => 'required',
- ]);
- }
-
- if (data_get($this->application, 'custom_docker_run_options')) {
- $this->application->custom_docker_run_options = str($this->application->custom_docker_run_options)->trim();
- }
- if (data_get($this->application, 'dockerfile')) {
- $port = get_port_from_dockerfile($this->application->dockerfile);
- if ($port && ! $this->application->ports_exposes) {
- $this->application->ports_exposes = $port;
- }
- }
- if ($this->application->base_directory && $this->application->base_directory !== '/') {
- $this->application->base_directory = rtrim($this->application->base_directory, '/');
- }
- if ($this->application->publish_directory && $this->application->publish_directory !== '/') {
- $this->application->publish_directory = rtrim($this->application->publish_directory, '/');
- }
- if ($this->application->build_pack === 'dockercompose') {
- $this->application->docker_compose_domains = json_encode($this->parsedServiceDomains);
-
- foreach ($this->parsedServiceDomains as $serviceName => $service) {
- $domain = data_get($service, 'domain');
- if ($domain) {
- if (! validate_dns_entry($domain, $this->application->destination->server)) {
- $showToaster && $this->dispatch('error', 'Validating DNS failed.', "Make sure you have added the DNS records correctly. $domain->{$this->application->destination->server->ip} Check this documentation for further help.");
- }
- check_domain_usage(resource: $this->application);
- }
- }
- if ($this->application->isDirty('docker_compose_domains')) {
- $this->resetDefaultLabels();
- }
- }
- $this->application->custom_labels = base64_encode($this->customLabels);
- $this->application->save();
- $showToaster && ! $warning && $this->dispatch('success', 'Application settings updated!');
- } catch (\Throwable $e) {
- $originalFqdn = $this->application->getOriginal('fqdn');
- if ($originalFqdn !== $this->application->fqdn) {
- $this->application->fqdn = $originalFqdn;
- }
-
- return handleError($e, $this);
- } finally {
- $this->dispatch('configurationChanged');
- }
- }
-
- public function downloadConfig()
- {
- $config = GenerateConfig::run($this->application, true);
- $fileName = str($this->application->name)->slug()->append('_config.json');
- dd($config);
-
- return response()->streamDownload(function () use ($config) {
- echo $config;
- }, $fileName, [
- 'Content-Type' => 'application/json',
- 'Content-Disposition' => 'attachment; filename='.$fileName,
- ]);
- }
-}
diff --git a/app/Livewire/Project/Application/Heading.php b/app/Livewire/Project/Application/Heading.php
deleted file mode 100644
index 0d7d7755f4..0000000000
--- a/app/Livewire/Project/Application/Heading.php
+++ /dev/null
@@ -1,151 +0,0 @@
-user()->currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},ApplicationStatusChanged" => 'check_status',
- 'compose_loaded' => '$refresh',
- 'update_links' => '$refresh',
- ];
- }
-
- public function mount()
- {
- $this->parameters = [
- 'project_uuid' => $this->application->project()->uuid,
- 'environment_uuid' => $this->application->environment->uuid,
- 'application_uuid' => $this->application->uuid,
- ];
- $lastDeployment = $this->application->get_last_successful_deployment();
- $this->lastDeploymentInfo = data_get_str($lastDeployment, 'commit')->limit(7).' '.data_get($lastDeployment, 'commit_message');
- $this->lastDeploymentLink = $this->application->gitCommitLink(data_get($lastDeployment, 'commit'));
- }
-
- public function check_status($showNotification = false)
- {
- if ($this->application->destination->server->isFunctional()) {
- GetContainersStatus::dispatch($this->application->destination->server);
- }
- if ($showNotification) {
- $this->dispatch('success', 'Success', 'Application status updated.');
- }
- }
-
- public function force_deploy_without_cache()
- {
- $this->deploy(force_rebuild: true);
- }
-
- public function deploy(bool $force_rebuild = false)
- {
- if ($this->application->build_pack === 'dockercompose' && is_null($this->application->docker_compose_raw)) {
- $this->dispatch('error', 'Failed to deploy', 'Please load a Compose file first.');
-
- return;
- }
- if ($this->application->destination->server->isSwarm() && str($this->application->docker_registry_image_name)->isEmpty()) {
- $this->dispatch('error', 'Failed to deploy.', 'To deploy to a Swarm cluster you must set a Docker image name first.');
-
- return;
- }
- if (data_get($this->application, 'settings.is_build_server_enabled') && str($this->application->docker_registry_image_name)->isEmpty()) {
- $this->dispatch('error', 'Failed to deploy.', 'To use a build server, you must first set a Docker image. More information here: documentation ');
-
- return;
- }
- if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
- $this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab. More information here: documentation ');
-
- return;
- }
- $this->setDeploymentUuid();
- queue_application_deployment(
- application: $this->application,
- deployment_uuid: $this->deploymentUuid,
- force_rebuild: $force_rebuild,
- );
-
- return $this->redirectRoute('project.application.deployment.show', [
- 'project_uuid' => $this->parameters['project_uuid'],
- 'application_uuid' => $this->parameters['application_uuid'],
- 'deployment_uuid' => $this->deploymentUuid,
- 'environment_uuid' => $this->parameters['environment_uuid'],
- ], navigate: true);
- }
-
- protected function setDeploymentUuid()
- {
- $this->deploymentUuid = new Cuid2;
- $this->parameters['deployment_uuid'] = $this->deploymentUuid;
- }
-
- public function stop()
- {
- StopApplication::run($this->application, false, $this->docker_cleanup);
- $this->application->status = 'exited';
- $this->application->save();
- if ($this->application->additional_servers->count() > 0) {
- $this->application->additional_servers->each(function ($server) {
- $server->pivot->status = 'exited:unhealthy';
- $server->pivot->save();
- });
- }
- ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
- }
-
- public function restart()
- {
- if ($this->application->additional_servers->count() > 0 && str($this->application->docker_registry_image_name)->isEmpty()) {
- $this->dispatch('error', 'Failed to deploy', 'Before deploying to multiple servers, you must first set a Docker image in the General tab. More information here: documentation ');
-
- return;
- }
- $this->setDeploymentUuid();
- queue_application_deployment(
- application: $this->application,
- deployment_uuid: $this->deploymentUuid,
- restart_only: true,
- );
-
- return $this->redirectRoute('project.application.deployment.show', [
- 'project_uuid' => $this->parameters['project_uuid'],
- 'application_uuid' => $this->parameters['application_uuid'],
- 'deployment_uuid' => $this->deploymentUuid,
- 'environment_uuid' => $this->parameters['environment_uuid'],
- ], navigate: true);
- }
-
- public function render()
- {
- return view('livewire.project.application.heading', [
- 'checkboxes' => [
- ['id' => 'docker_cleanup', 'label' => __('resource.docker_cleanup')],
- ],
- ]);
- }
-}
diff --git a/app/Livewire/Project/Application/Preview/Form.php b/app/Livewire/Project/Application/Preview/Form.php
deleted file mode 100644
index edcab44c88..0000000000
--- a/app/Livewire/Project/Application/Preview/Form.php
+++ /dev/null
@@ -1,63 +0,0 @@
-previewUrlTemplate = $this->application->preview_url_template;
- $this->generateRealUrl();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- $this->resetErrorBag();
- $this->validate();
- $this->application->preview_url_template = str_replace(' ', '', $this->previewUrlTemplate);
- $this->application->save();
- $this->dispatch('success', 'Preview url template updated.');
- $this->generateRealUrl();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function resetToDefault()
- {
- try {
- $this->application->preview_url_template = '{{pr_id}}.{{domain}}';
- $this->previewUrlTemplate = $this->application->preview_url_template;
- $this->application->save();
- $this->generateRealUrl();
- $this->dispatch('success', 'Preview url template updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function generateRealUrl()
- {
- if (data_get($this->application, 'fqdn')) {
- $firstFqdn = str($this->application->fqdn)->before(',');
- $url = Url::fromString($firstFqdn);
- $host = $url->getHost();
- $this->previewUrlTemplate = str($this->application->preview_url_template)->replace('{{domain}}', $host);
- }
- }
-}
diff --git a/app/Livewire/Project/Application/Previews.php b/app/Livewire/Project/Application/Previews.php
deleted file mode 100644
index bdf62706c3..0000000000
--- a/app/Livewire/Project/Application/Previews.php
+++ /dev/null
@@ -1,279 +0,0 @@
- 'string|nullable',
- ];
-
- public function mount()
- {
- $this->pull_requests = collect();
- $this->parameters = get_route_parameters();
- }
-
- public function load_prs()
- {
- try {
- ['rate_limit_remaining' => $rate_limit_remaining, 'data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/pulls");
- $this->rate_limit_remaining = $rate_limit_remaining;
- $this->pull_requests = $data->sortBy('number')->values();
- } catch (\Throwable $e) {
- $this->rate_limit_remaining = 0;
-
- return handleError($e, $this);
- }
- }
-
- public function save_preview($preview_id)
- {
- try {
- $success = true;
- $preview = $this->application->previews->find($preview_id);
- if (data_get_str($preview, 'fqdn')->isNotEmpty()) {
- $preview->fqdn = str($preview->fqdn)->replaceEnd(',', '')->trim();
- $preview->fqdn = str($preview->fqdn)->replaceStart(',', '')->trim();
- $preview->fqdn = str($preview->fqdn)->trim()->lower();
- if (! validate_dns_entry($preview->fqdn, $this->application->destination->server)) {
- $this->dispatch('error', 'Validating DNS failed.', "Make sure you have added the DNS records correctly. $preview->fqdn->{$this->application->destination->server->ip} Check this documentation for further help.");
- $success = false;
- }
- check_domain_usage(resource: $this->application, domain: $preview->fqdn);
- }
-
- if (! $preview) {
- throw new \Exception('Preview not found');
- }
- $success && $preview->save();
- $success && $this->dispatch('success', 'Preview saved. Do not forget to redeploy the preview to apply the changes.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function generate_preview($preview_id)
- {
- $preview = $this->application->previews->find($preview_id);
- if (! $preview) {
- $this->dispatch('error', 'Preview not found.');
-
- return;
- }
- if ($this->application->build_pack === 'dockercompose') {
- $preview->generate_preview_fqdn_compose();
- $this->application->refresh();
- $this->dispatch('success', 'Domain generated.');
-
- return;
- }
-
- $fqdn = generateFqdn($this->application->destination->server, $this->application->uuid);
- $url = Url::fromString($fqdn);
- $template = $this->application->preview_url_template;
- $host = $url->getHost();
- $schema = $url->getScheme();
- $random = new Cuid2;
- $preview_fqdn = str_replace('{{random}}', $random, $template);
- $preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
- $preview_fqdn = str_replace('{{pr_id}}', $preview->pull_request_id, $preview_fqdn);
- $preview_fqdn = "$schema://$preview_fqdn";
- $preview->fqdn = $preview_fqdn;
- $preview->save();
- $this->dispatch('success', 'Domain generated.');
- }
-
- public function add(int $pull_request_id, ?string $pull_request_html_url = null)
- {
- try {
- if ($this->application->build_pack === 'dockercompose') {
- $this->setDeploymentUuid();
- $found = ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first();
- if (! $found && ! is_null($pull_request_html_url)) {
- $found = ApplicationPreview::create([
- 'application_id' => $this->application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- 'docker_compose_domains' => $this->application->docker_compose_domains,
- ]);
- }
- $found->generate_preview_fqdn_compose();
- $this->application->refresh();
- } else {
- $this->setDeploymentUuid();
- $found = ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first();
- if (! $found && ! is_null($pull_request_html_url)) {
- $found = ApplicationPreview::create([
- 'application_id' => $this->application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- ]);
- }
- $this->application->generate_preview_fqdn($pull_request_id);
- $this->application->refresh();
- $this->dispatch('update_links');
- $this->dispatch('success', 'Preview added.');
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function add_and_deploy(int $pull_request_id, ?string $pull_request_html_url = null)
- {
- $this->add($pull_request_id, $pull_request_html_url);
- $this->deploy($pull_request_id, $pull_request_html_url);
- }
-
- public function deploy(int $pull_request_id, ?string $pull_request_html_url = null)
- {
- try {
- $this->setDeploymentUuid();
- $found = ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first();
- if (! $found && ! is_null($pull_request_html_url)) {
- ApplicationPreview::create([
- 'application_id' => $this->application->id,
- 'pull_request_id' => $pull_request_id,
- 'pull_request_html_url' => $pull_request_html_url,
- ]);
- }
- queue_application_deployment(
- application: $this->application,
- deployment_uuid: $this->deployment_uuid,
- force_rebuild: false,
- pull_request_id: $pull_request_id,
- git_type: $found->git_type ?? null,
- );
-
- return redirect()->route('project.application.deployment.show', [
- 'project_uuid' => $this->parameters['project_uuid'],
- 'application_uuid' => $this->parameters['application_uuid'],
- 'deployment_uuid' => $this->deployment_uuid,
- 'environment_uuid' => $this->parameters['environment_uuid'],
- ]);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- protected function setDeploymentUuid()
- {
- $this->deployment_uuid = new Cuid2;
- $this->parameters['deployment_uuid'] = $this->deployment_uuid;
- }
-
- public function stop(int $pull_request_id)
- {
- try {
- $server = $this->application->destination->server;
- $timeout = 300;
-
- if ($this->application->destination->server->isSwarm()) {
- instant_remote_process(["docker stack rm {$this->application->uuid}-{$pull_request_id}"], $server);
- } else {
- $containers = getCurrentApplicationContainerStatus($server, $this->application->id, $pull_request_id)->toArray();
- $this->stopContainers($containers, $server, $timeout);
- }
-
- GetContainersStatus::run($server);
- $this->application->refresh();
- $this->dispatch('containerStatusUpdated');
- $this->dispatch('success', 'Preview Deployment stopped.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function delete(int $pull_request_id)
- {
- try {
- $server = $this->application->destination->server;
- $timeout = 300;
-
- if ($this->application->destination->server->isSwarm()) {
- instant_remote_process(["docker stack rm {$this->application->uuid}-{$pull_request_id}"], $server);
- } else {
- $containers = getCurrentApplicationContainerStatus($server, $this->application->id, $pull_request_id)->toArray();
- $this->stopContainers($containers, $server, $timeout);
- }
-
- ApplicationPreview::where('application_id', $this->application->id)
- ->where('pull_request_id', $pull_request_id)
- ->first()
- ->delete();
-
- $this->application->refresh();
- $this->dispatch('update_links');
- $this->dispatch('success', 'Preview deleted.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- private function stopContainers(array $containers, $server, int $timeout)
- {
- $processes = [];
- foreach ($containers as $container) {
- $containerName = str_replace('/', '', $container['Names']);
- $processes[$containerName] = $this->stopContainer($containerName, $timeout);
- }
-
- $startTime = Carbon::now()->getTimestamp();
- while (count($processes) > 0) {
- $finishedProcesses = array_filter($processes, function ($process) {
- return ! $process->running();
- });
- foreach (array_keys($finishedProcesses) as $containerName) {
- unset($processes[$containerName]);
- $this->removeContainer($containerName, $server);
- }
-
- if (Carbon::now()->getTimestamp() - $startTime >= $timeout) {
- $this->forceStopRemainingContainers(array_keys($processes), $server);
- break;
- }
-
- usleep(100000);
- }
- }
-
- private function stopContainer(string $containerName, int $timeout): InvokedProcess
- {
- return Process::timeout($timeout)->start("docker stop --time=$timeout $containerName");
- }
-
- private function removeContainer(string $containerName, $server)
- {
- instant_remote_process(["docker rm -f $containerName"], $server, throwError: false);
- }
-
- private function forceStopRemainingContainers(array $containerNames, $server)
- {
- foreach ($containerNames as $containerName) {
- instant_remote_process(["docker kill $containerName"], $server, throwError: false);
- $this->removeContainer($containerName, $server);
- }
- }
-}
diff --git a/app/Livewire/Project/Application/PreviewsCompose.php b/app/Livewire/Project/Application/PreviewsCompose.php
deleted file mode 100644
index b3e838bb3f..0000000000
--- a/app/Livewire/Project/Application/PreviewsCompose.php
+++ /dev/null
@@ -1,61 +0,0 @@
-service, 'domain');
- $docker_compose_domains = data_get($this->preview, 'docker_compose_domains');
- $docker_compose_domains = json_decode($docker_compose_domains, true);
- $docker_compose_domains[$this->serviceName]['domain'] = $domain;
- $this->preview->docker_compose_domains = json_encode($docker_compose_domains);
- $this->preview->save();
- $this->dispatch('update_links');
- $this->dispatch('success', 'Domain saved.');
- }
-
- public function generate()
- {
- $domains = collect(json_decode($this->preview->application->docker_compose_domains)) ?? collect();
- $domain = $domains->first(function ($_, $key) {
- return $key === $this->serviceName;
- });
- if ($domain) {
- $domain = data_get($domain, 'domain');
- $url = Url::fromString($domain);
- $template = $this->preview->application->preview_url_template;
- $host = $url->getHost();
- $schema = $url->getScheme();
- $random = new Cuid2;
- $preview_fqdn = str_replace('{{random}}', $random, $template);
- $preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
- $preview_fqdn = str_replace('{{pr_id}}', $this->preview->pull_request_id, $preview_fqdn);
- $preview_fqdn = "$schema://$preview_fqdn";
- $docker_compose_domains = data_get($this->preview, 'docker_compose_domains');
- $docker_compose_domains = json_decode($docker_compose_domains, true);
- $docker_compose_domains[$this->serviceName]['domain'] = $this->service->domain = $preview_fqdn;
- $this->preview->docker_compose_domains = json_encode($docker_compose_domains);
- $this->preview->save();
- }
- $this->dispatch('update_links');
- $this->dispatch('success', 'Domain generated.');
- }
-}
diff --git a/app/Livewire/Project/Application/Rollback.php b/app/Livewire/Project/Application/Rollback.php
deleted file mode 100644
index ff5db1e08c..0000000000
--- a/app/Livewire/Project/Application/Rollback.php
+++ /dev/null
@@ -1,80 +0,0 @@
-parameters = get_route_parameters();
- }
-
- public function rollbackImage($commit)
- {
- $deployment_uuid = new Cuid2;
-
- queue_application_deployment(
- application: $this->application,
- deployment_uuid: $deployment_uuid,
- commit: $commit,
- rollback: true,
- force_rebuild: false,
- );
-
- return redirect()->route('project.application.deployment.show', [
- 'project_uuid' => $this->parameters['project_uuid'],
- 'application_uuid' => $this->parameters['application_uuid'],
- 'deployment_uuid' => $deployment_uuid,
- 'environment_uuid' => $this->parameters['environment_uuid'],
- ]);
- }
-
- public function loadImages($showToast = false)
- {
- try {
- $image = $this->application->docker_registry_image_name ?? $this->application->uuid;
- if ($this->application->destination->server->isFunctional()) {
- $output = instant_remote_process([
- "docker inspect --format='{{.Config.Image}}' {$this->application->uuid}",
- ], $this->application->destination->server, throwError: false);
- $current_tag = str($output)->trim()->explode(':');
- $this->current = data_get($current_tag, 1);
-
- $output = instant_remote_process([
- "docker images --format '{{.Repository}}#{{.Tag}}#{{.CreatedAt}}'",
- ], $this->application->destination->server);
- $this->images = str($output)->trim()->explode("\n")->filter(function ($item) use ($image) {
- return str($item)->contains($image);
- })->map(function ($item) {
- $item = str($item)->explode('#');
- if ($item[1] === $this->current) {
- // $is_current = true;
- }
-
- return [
- 'tag' => $item[1],
- 'created_at' => $item[2],
- 'is_current' => $is_current ?? null,
- ];
- })->toArray();
- }
- $showToast && $this->dispatch('success', 'Images loaded.');
-
- return [];
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Project/Application/Source.php b/app/Livewire/Project/Application/Source.php
deleted file mode 100644
index ade297d501..0000000000
--- a/app/Livewire/Project/Application/Source.php
+++ /dev/null
@@ -1,95 +0,0 @@
-syncData();
- $this->getPrivateKeys();
- } catch (\Throwable $e) {
- handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->application->update([
- 'git_repository' => $this->gitRepository,
- 'git_branch' => $this->gitBranch,
- 'git_commit_sha' => $this->gitCommitSha,
- 'private_key_id' => $this->privateKeyId,
- ]);
- } else {
- $this->gitRepository = $this->application->git_repository;
- $this->gitBranch = $this->application->git_branch;
- $this->gitCommitSha = $this->application->git_commit_sha;
- $this->privateKeyId = $this->application->private_key_id;
- $this->privateKeyName = data_get($this->application, 'private_key.name');
- }
- }
-
- private function getPrivateKeys()
- {
- $this->privateKeys = PrivateKey::whereTeamId(currentTeam()->id)->get()->reject(function ($key) {
- return $key->id == $this->privateKeyId;
- });
- }
-
- public function setPrivateKey(int $privateKeyId)
- {
- try {
- $this->privateKeyId = $privateKeyId;
- $this->syncData(true);
- $this->getPrivateKeys();
- $this->application->refresh();
- $this->privateKeyName = $this->application->private_key->name;
- $this->dispatch('success', 'Private key updated!');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- if (str($this->gitCommitSha)->isEmpty()) {
- $this->gitCommitSha = 'HEAD';
- }
- $this->syncData(true);
- $this->dispatch('success', 'Application source updated!');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Project/Application/Swarm.php b/app/Livewire/Project/Application/Swarm.php
deleted file mode 100644
index 197dc41ed3..0000000000
--- a/app/Livewire/Project/Application/Swarm.php
+++ /dev/null
@@ -1,75 +0,0 @@
-syncData();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->application->swarm_replicas = $this->swarmReplicas;
- $this->application->swarm_placement_constraints = $this->swarmPlacementConstraints ? base64_encode($this->swarmPlacementConstraints) : null;
- $this->application->settings->is_swarm_only_worker_nodes = $this->isSwarmOnlyWorkerNodes;
- $this->application->save();
- $this->application->settings->save();
- } else {
- $this->swarmReplicas = $this->application->swarm_replicas;
- if ($this->application->swarm_placement_constraints) {
- $this->swarmPlacementConstraints = base64_decode($this->application->swarm_placement_constraints);
- } else {
- $this->swarmPlacementConstraints = null;
- }
- $this->isSwarmOnlyWorkerNodes = $this->application->settings->is_swarm_only_worker_nodes;
- }
- }
-
- public function instantSave()
- {
- try {
- $this->syncData(true);
- $this->dispatch('success', 'Swarm settings updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- $this->syncData(true);
- $this->dispatch('success', 'Swarm settings updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.project.application.swarm');
- }
-}
diff --git a/app/Livewire/Project/CloneMe.php b/app/Livewire/Project/CloneMe.php
deleted file mode 100644
index c71f6db64f..0000000000
--- a/app/Livewire/Project/CloneMe.php
+++ /dev/null
@@ -1,568 +0,0 @@
- 'Please select a server.',
- 'selectedDestination' => 'Please select a server & destination.',
- 'newName' => 'Please enter a name for the new project or environment.',
- ];
-
- public function mount($project_uuid)
- {
- $this->project_uuid = $project_uuid;
- $this->project = Project::where('uuid', $project_uuid)->firstOrFail();
- $this->environment = $this->project->environments->where('uuid', $this->environment_uuid)->first();
- $this->project_id = $this->project->id;
- $this->servers = currentTeam()->servers;
- $this->newName = str($this->project->name.'-clone-'.(string) new Cuid2)->slug();
- }
-
- public function toggleVolumeCloning(bool $value)
- {
- $this->cloneVolumeData = $value;
- }
-
- public function render()
- {
- return view('livewire.project.clone-me');
- }
-
- public function selectServer($server_id, $destination_id)
- {
- if ($server_id == $this->selectedServer && $destination_id == $this->selectedDestination) {
- $this->selectedServer = null;
- $this->selectedDestination = null;
- $this->server = null;
-
- return;
- }
- $this->selectedServer = $server_id;
- $this->selectedDestination = $destination_id;
- $this->server = $this->servers->where('id', $server_id)->first();
- }
-
- public function clone(string $type)
- {
- try {
- $this->validate([
- 'selectedDestination' => 'required',
- 'newName' => 'required',
- ]);
- if ($type === 'project') {
- $foundProject = Project::where('name', $this->newName)->first();
- if ($foundProject) {
- throw new \Exception('Project with the same name already exists.');
- }
- $project = Project::create([
- 'name' => $this->newName,
- 'team_id' => currentTeam()->id,
- 'description' => $this->project->description.' (clone)',
- ]);
- if ($this->environment->name !== 'production') {
- $project->environments()->create([
- 'name' => $this->environment->name,
- 'uuid' => (string) new Cuid2,
- ]);
- }
- $environment = $project->environments->where('name', $this->environment->name)->first();
- } else {
- $foundEnv = $this->project->environments()->where('name', $this->newName)->first();
- if ($foundEnv) {
- throw new \Exception('Environment with the same name already exists.');
- }
- $project = $this->project;
- $environment = $this->project->environments()->create([
- 'name' => $this->newName,
- 'uuid' => (string) new Cuid2,
- ]);
- }
- $applications = $this->environment->applications;
- $databases = $this->environment->databases();
- $services = $this->environment->services;
- foreach ($applications as $application) {
- $applicationSettings = $application->settings;
-
- $uuid = (string) new Cuid2;
- $url = $application->fqdn;
- if ($this->server->proxyType() !== 'NONE' && $applicationSettings->is_container_label_readonly_enabled === true) {
- $url = generateFqdn($this->server, $uuid);
- }
-
- $newApplication = $application->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- 'additional_servers_count',
- 'additional_networks_count',
- ])->fill([
- 'uuid' => $uuid,
- 'fqdn' => $url,
- 'status' => 'exited',
- 'environment_id' => $environment->id,
- 'destination_id' => $this->selectedDestination,
- ]);
- $newApplication->save();
-
- if ($newApplication->destination->server->proxyType() !== 'NONE' && $applicationSettings->is_container_label_readonly_enabled === true) {
- $customLabels = str(implode('|coolify|', generateLabelsApplication($newApplication)))->replace('|coolify|', "\n");
- $newApplication->custom_labels = base64_encode($customLabels);
- $newApplication->save();
- }
-
- $newApplication->settings()->delete();
- if ($applicationSettings) {
- $newApplicationSettings = $applicationSettings->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'application_id' => $newApplication->id,
- ]);
- $newApplicationSettings->save();
- }
-
- $tags = $application->tags;
- foreach ($tags as $tag) {
- $newApplication->tags()->attach($tag->id);
- }
-
- $scheduledTasks = $application->scheduled_tasks()->get();
- foreach ($scheduledTasks as $task) {
- $newTask = $task->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'uuid' => (string) new Cuid2,
- 'application_id' => $newApplication->id,
- 'team_id' => currentTeam()->id,
- ]);
- $newTask->save();
- }
-
- $applicationPreviews = $application->previews()->get();
- foreach ($applicationPreviews as $preview) {
- $newPreview = $preview->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'application_id' => $newApplication->id,
- 'status' => 'exited',
- ]);
- $newPreview->save();
- }
-
- $persistentVolumes = $application->persistentStorages()->get();
- foreach ($persistentVolumes as $volume) {
- $newName = '';
- if (str_starts_with($volume->name, $application->uuid)) {
- $newName = str($volume->name)->replace($application->uuid, $newApplication->uuid);
- } else {
- $newName = $newApplication->uuid.'-'.$volume->name;
- }
-
- $newPersistentVolume = $volume->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'name' => $newName,
- 'resource_id' => $newApplication->id,
- ]);
- $newPersistentVolume->save();
-
- if ($this->cloneVolumeData) {
- try {
- StopApplication::dispatch($application, false, false);
- $sourceVolume = $volume->name;
- $targetVolume = $newPersistentVolume->name;
- $sourceServer = $application->destination->server;
- $targetServer = $newApplication->destination->server;
-
- VolumeCloneJob::dispatch($sourceVolume, $targetVolume, $sourceServer, $targetServer, $newPersistentVolume);
-
- queue_application_deployment(
- deployment_uuid: (string) new Cuid2,
- application: $application,
- server: $sourceServer,
- destination: $application->destination,
- no_questions_asked: true
- );
- } catch (\Exception $e) {
- \Log::error('Failed to copy volume data for '.$volume->name.': '.$e->getMessage());
- }
- }
- }
-
- $fileStorages = $application->fileStorages()->get();
- foreach ($fileStorages as $storage) {
- $newStorage = $storage->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'resource_id' => $newApplication->id,
- ]);
- $newStorage->save();
- }
-
- $environmentVaribles = $application->environment_variables()->get();
- foreach ($environmentVaribles as $environmentVarible) {
- $newEnvironmentVariable = $environmentVarible->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'resourceable_id' => $newApplication->id,
- ]);
- $newEnvironmentVariable->save();
- }
- }
-
- foreach ($databases as $database) {
- $uuid = (string) new Cuid2;
- $newDatabase = $database->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'uuid' => $uuid,
- 'status' => 'exited',
- 'started_at' => null,
- 'environment_id' => $environment->id,
- 'destination_id' => $this->selectedDestination,
- ]);
- $newDatabase->save();
-
- $tags = $database->tags;
- foreach ($tags as $tag) {
- $newDatabase->tags()->attach($tag->id);
- }
-
- $newDatabase->persistentStorages()->delete();
- $persistentVolumes = $database->persistentStorages()->get();
- foreach ($persistentVolumes as $volume) {
- $originalName = $volume->name;
- $newName = '';
-
- if (str_starts_with($originalName, 'postgres-data-')) {
- $newName = 'postgres-data-'.$newDatabase->uuid;
- } elseif (str_starts_with($originalName, 'mysql-data-')) {
- $newName = 'mysql-data-'.$newDatabase->uuid;
- } elseif (str_starts_with($originalName, 'redis-data-')) {
- $newName = 'redis-data-'.$newDatabase->uuid;
- } elseif (str_starts_with($originalName, 'clickhouse-data-')) {
- $newName = 'clickhouse-data-'.$newDatabase->uuid;
- } elseif (str_starts_with($originalName, 'mariadb-data-')) {
- $newName = 'mariadb-data-'.$newDatabase->uuid;
- } elseif (str_starts_with($originalName, 'mongodb-data-')) {
- $newName = 'mongodb-data-'.$newDatabase->uuid;
- } elseif (str_starts_with($originalName, 'keydb-data-')) {
- $newName = 'keydb-data-'.$newDatabase->uuid;
- } elseif (str_starts_with($originalName, 'dragonfly-data-')) {
- $newName = 'dragonfly-data-'.$newDatabase->uuid;
- } else {
- if (str_starts_with($volume->name, $database->uuid)) {
- $newName = str($volume->name)->replace($database->uuid, $newDatabase->uuid);
- } else {
- $newName = $newDatabase->uuid.'-'.$volume->name;
- }
- }
-
- $newPersistentVolume = $volume->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'name' => $newName,
- 'resource_id' => $newDatabase->id,
- ]);
- $newPersistentVolume->save();
-
- if ($this->cloneVolumeData) {
- try {
- StopDatabase::dispatch($database);
- $sourceVolume = $volume->name;
- $targetVolume = $newPersistentVolume->name;
- $sourceServer = $database->destination->server;
- $targetServer = $newDatabase->destination->server;
-
- VolumeCloneJob::dispatch($sourceVolume, $targetVolume, $sourceServer, $targetServer, $newPersistentVolume);
-
- StartDatabase::dispatch($database);
- } catch (\Exception $e) {
- \Log::error('Failed to copy volume data for '.$volume->name.': '.$e->getMessage());
- }
- }
- }
-
- $fileStorages = $database->fileStorages()->get();
- foreach ($fileStorages as $storage) {
- $newStorage = $storage->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'resource_id' => $newDatabase->id,
- ]);
- $newStorage->save();
- }
-
- $scheduledBackups = $database->scheduledBackups()->get();
- foreach ($scheduledBackups as $backup) {
- $uuid = (string) new Cuid2;
- $newBackup = $backup->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'uuid' => $uuid,
- 'database_id' => $newDatabase->id,
- 'database_type' => $newDatabase->getMorphClass(),
- 'team_id' => currentTeam()->id,
- ]);
- $newBackup->save();
- }
-
- $environmentVaribles = $database->environment_variables()->get();
- foreach ($environmentVaribles as $environmentVarible) {
- $payload = [];
- $payload['resourceable_id'] = $newDatabase->id;
- $payload['resourceable_type'] = $newDatabase->getMorphClass();
- $newEnvironmentVariable = $environmentVarible->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill($payload);
- $newEnvironmentVariable->save();
- }
- }
-
- foreach ($services as $service) {
- $uuid = (string) new Cuid2;
- $newService = $service->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'uuid' => $uuid,
- 'environment_id' => $environment->id,
- 'destination_id' => $this->selectedDestination,
- ]);
- $newService->save();
-
- $tags = $service->tags;
- foreach ($tags as $tag) {
- $newService->tags()->attach($tag->id);
- }
-
- $scheduledTasks = $service->scheduled_tasks()->get();
- foreach ($scheduledTasks as $task) {
- $newTask = $task->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'uuid' => (string) new Cuid2,
- 'service_id' => $newService->id,
- 'team_id' => currentTeam()->id,
- ]);
- $newTask->save();
- }
-
- $environmentVariables = $service->environment_variables()->get();
- foreach ($environmentVariables as $environmentVariable) {
- $newEnvironmentVariable = $environmentVariable->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'resourceable_id' => $newService->id,
- 'resourceable_type' => $newService->getMorphClass(),
- ]);
- $newEnvironmentVariable->save();
- }
-
- foreach ($newService->applications() as $application) {
- $application->update([
- 'status' => 'exited',
- ]);
-
- $persistentVolumes = $application->persistentStorages()->get();
- foreach ($persistentVolumes as $volume) {
- $newName = '';
- if (str_starts_with($volume->name, $application->uuid)) {
- $newName = str($volume->name)->replace($application->uuid, $application->uuid);
- } else {
- $newName = $application->uuid.'-'.$volume->name;
- }
-
- $newPersistentVolume = $volume->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'name' => $newName,
- 'resource_id' => $application->id,
- ]);
- $newPersistentVolume->save();
-
- if ($this->cloneVolumeData) {
- try {
- StopService::dispatch($application, false, false);
- $sourceVolume = $volume->name;
- $targetVolume = $newPersistentVolume->name;
- $sourceServer = $application->service->destination->server;
- $targetServer = $newService->destination->server;
-
- VolumeCloneJob::dispatch($sourceVolume, $targetVolume, $sourceServer, $targetServer, $newPersistentVolume);
-
- StartService::dispatch($application);
- } catch (\Exception $e) {
- \Log::error('Failed to copy volume data for '.$volume->name.': '.$e->getMessage());
- }
- }
- }
-
- $fileStorages = $application->fileStorages()->get();
- foreach ($fileStorages as $storage) {
- $newStorage = $storage->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'resource_id' => $application->id,
- ]);
- $newStorage->save();
- }
- }
-
- foreach ($newService->databases() as $database) {
- $database->update([
- 'status' => 'exited',
- ]);
-
- $persistentVolumes = $database->persistentStorages()->get();
- foreach ($persistentVolumes as $volume) {
- $newName = '';
- if (str_starts_with($volume->name, $database->uuid)) {
- $newName = str($volume->name)->replace($database->uuid, $database->uuid);
- } else {
- $newName = $database->uuid.'-'.$volume->name;
- }
-
- $newPersistentVolume = $volume->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'name' => $newName,
- 'resource_id' => $database->id,
- ]);
- $newPersistentVolume->save();
-
- if ($this->cloneVolumeData) {
- try {
- StopService::dispatch($database->service, false, false);
- $sourceVolume = $volume->name;
- $targetVolume = $newPersistentVolume->name;
- $sourceServer = $database->service->destination->server;
- $targetServer = $newService->destination->server;
-
- VolumeCloneJob::dispatch($sourceVolume, $targetVolume, $sourceServer, $targetServer, $newPersistentVolume);
-
- StartService::dispatch($database->service);
- } catch (\Exception $e) {
- \Log::error('Failed to copy volume data for '.$volume->name.': '.$e->getMessage());
- }
- }
- }
-
- $fileStorages = $database->fileStorages()->get();
- foreach ($fileStorages as $storage) {
- $newStorage = $storage->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'resource_id' => $database->id,
- ]);
- $newStorage->save();
- }
-
- $scheduledBackups = $database->scheduledBackups()->get();
- foreach ($scheduledBackups as $backup) {
- $uuid = (string) new Cuid2;
- $newBackup = $backup->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'uuid' => $uuid,
- 'database_id' => $database->id,
- 'database_type' => $database->getMorphClass(),
- 'team_id' => currentTeam()->id,
- ]);
- $newBackup->save();
- }
- }
-
- $newService->parse();
- }
-
- } catch (\Exception $e) {
- handleError($e, $this);
-
- return;
- } finally {
- if (! isset($e)) {
- return redirect()->route('project.resource.index', [
- 'project_uuid' => $project->uuid,
- 'environment_uuid' => $environment->uuid,
- ]);
- }
- }
- }
-}
diff --git a/app/Livewire/Project/Database/Backup/Execution.php b/app/Livewire/Project/Database/Backup/Execution.php
deleted file mode 100644
index 4ac3b2e2c5..0000000000
--- a/app/Livewire/Project/Database/Backup/Execution.php
+++ /dev/null
@@ -1,48 +0,0 @@
-route('backup_uuid');
- $project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
- if (! $project) {
- return redirect()->route('dashboard');
- }
- $environment = $project->load(['environments'])->environments->where('uuid', request()->route('environment_uuid'))->first()->load(['applications']);
- if (! $environment) {
- return redirect()->route('dashboard');
- }
- $database = $environment->databases()->where('uuid', request()->route('database_uuid'))->first();
- if (! $database) {
- return redirect()->route('dashboard');
- }
- $backup = $database->scheduledBackups->where('uuid', $backup_uuid)->first();
- if (! $backup) {
- return redirect()->route('dashboard');
- }
- $executions = collect($backup->executions)->sortByDesc('created_at');
- $this->database = $database;
- $this->backup = $backup;
- $this->executions = $executions;
- $this->s3s = currentTeam()->s3s;
- }
-
- public function render()
- {
- return view('livewire.project.database.backup.execution');
- }
-}
diff --git a/app/Livewire/Project/Database/Backup/Index.php b/app/Livewire/Project/Database/Backup/Index.php
deleted file mode 100644
index 2df32ec7bf..0000000000
--- a/app/Livewire/Project/Database/Backup/Index.php
+++ /dev/null
@@ -1,45 +0,0 @@
-load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
- if (! $project) {
- return redirect()->route('dashboard');
- }
- $environment = $project->load(['environments'])->environments->where('uuid', request()->route('environment_uuid'))->first()->load(['applications']);
- if (! $environment) {
- return redirect()->route('dashboard');
- }
- $database = $environment->databases()->where('uuid', request()->route('database_uuid'))->first();
- if (! $database) {
- return redirect()->route('dashboard');
- }
- // No backups
- if (
- $database->getMorphClass() === \App\Models\StandaloneRedis::class ||
- $database->getMorphClass() === \App\Models\StandaloneKeydb::class ||
- $database->getMorphClass() === \App\Models\StandaloneDragonfly::class ||
- $database->getMorphClass() === \App\Models\StandaloneClickhouse::class
- ) {
- return redirect()->route('project.database.configuration', [
- 'project_uuid' => $project->uuid,
- 'environment_uuid' => $environment->uuid,
- 'database_uuid' => $database->uuid,
- ]);
- }
- $this->database = $database;
- }
-
- public function render()
- {
- return view('livewire.project.database.backup.index');
- }
-}
diff --git a/app/Livewire/Project/Database/BackupEdit.php b/app/Livewire/Project/Database/BackupEdit.php
deleted file mode 100644
index 0d363e9832..0000000000
--- a/app/Livewire/Project/Database/BackupEdit.php
+++ /dev/null
@@ -1,218 +0,0 @@
-parameters = get_route_parameters();
- $this->syncData();
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->backup->enabled = $this->backupEnabled;
- $this->backup->frequency = $this->frequency;
- $this->backup->database_backup_retention_amount_locally = $this->databaseBackupRetentionAmountLocally;
- $this->backup->database_backup_retention_days_locally = $this->databaseBackupRetentionDaysLocally;
- $this->backup->database_backup_retention_max_storage_locally = $this->databaseBackupRetentionMaxStorageLocally;
- $this->backup->database_backup_retention_amount_s3 = $this->databaseBackupRetentionAmountS3;
- $this->backup->database_backup_retention_days_s3 = $this->databaseBackupRetentionDaysS3;
- $this->backup->database_backup_retention_max_storage_s3 = $this->databaseBackupRetentionMaxStorageS3;
- $this->backup->save_s3 = $this->saveS3;
- $this->backup->s3_storage_id = $this->s3StorageId;
- $this->backup->databases_to_backup = $this->databasesToBackup;
- $this->backup->dump_all = $this->dumpAll;
- $this->customValidate();
- $this->backup->save();
- } else {
- $this->backupEnabled = $this->backup->enabled;
- $this->frequency = $this->backup->frequency;
- $this->timezone = data_get($this->backup->server(), 'settings.server_timezone', 'Instance timezone');
- $this->databaseBackupRetentionAmountLocally = $this->backup->database_backup_retention_amount_locally;
- $this->databaseBackupRetentionDaysLocally = $this->backup->database_backup_retention_days_locally;
- $this->databaseBackupRetentionMaxStorageLocally = $this->backup->database_backup_retention_max_storage_locally;
- $this->databaseBackupRetentionAmountS3 = $this->backup->database_backup_retention_amount_s3;
- $this->databaseBackupRetentionDaysS3 = $this->backup->database_backup_retention_days_s3;
- $this->databaseBackupRetentionMaxStorageS3 = $this->backup->database_backup_retention_max_storage_s3;
- $this->saveS3 = $this->backup->save_s3;
- $this->s3StorageId = $this->backup->s3_storage_id;
- $this->databasesToBackup = $this->backup->databases_to_backup;
- $this->dumpAll = $this->backup->dump_all;
- }
- }
-
- public function delete($password)
- {
- if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return;
- }
- }
-
- try {
- $server = null;
- if ($this->backup->database instanceof \App\Models\ServiceDatabase) {
- $server = $this->backup->database->service->destination->server;
- } elseif ($this->backup->database->destination && $this->backup->database->destination->server) {
- $server = $this->backup->database->destination->server;
- }
-
- $filenames = $this->backup->executions()
- ->whereNotNull('filename')
- ->where('filename', '!=', '')
- ->where('scheduled_database_backup_id', $this->backup->id)
- ->pluck('filename')
- ->filter()
- ->all();
-
- if (! empty($filenames)) {
- if ($this->delete_associated_backups_locally && $server) {
- deleteBackupsLocally($filenames, $server);
- }
-
- if ($this->delete_associated_backups_s3 && $this->backup->s3) {
- deleteBackupsS3($filenames, $this->backup->s3);
- }
- }
-
- $this->backup->delete();
-
- if ($this->backup->database->getMorphClass() === \App\Models\ServiceDatabase::class) {
- $previousUrl = url()->previous();
- $url = Url::fromString($previousUrl);
- $url = $url->withoutQueryParameter('selectedBackupId');
- $url = $url->withFragment('backups');
- $url = $url->getPath()."#{$url->getFragment()}";
-
- return redirect($url);
- } else {
- return redirect()->route('project.database.backup.index', $this->parameters);
- }
- } catch (\Exception $e) {
- $this->dispatch('error', 'Failed to delete backup: '.$e->getMessage());
-
- return handleError($e, $this);
- }
- }
-
- public function instantSave()
- {
- try {
- $this->syncData(true);
- $this->dispatch('success', 'Backup updated successfully.');
- } catch (\Throwable $e) {
- $this->dispatch('error', $e->getMessage());
- }
- }
-
- private function customValidate()
- {
- if (! is_numeric($this->backup->s3_storage_id)) {
- $this->backup->s3_storage_id = null;
- }
- $isValid = validate_cron_expression($this->backup->frequency);
- if (! $isValid) {
- throw new \Exception('Invalid Cron / Human expression');
- }
- $this->validate();
- }
-
- public function submit()
- {
- try {
- $this->syncData(true);
- $this->dispatch('success', 'Backup updated successfully.');
- } catch (\Throwable $e) {
- $this->dispatch('error', $e->getMessage());
- }
- }
-
- public function render()
- {
- return view('livewire.project.database.backup-edit', [
- 'checkboxes' => [
- ['id' => 'delete_associated_backups_locally', 'label' => __('database.delete_backups_locally')],
- ['id' => 'delete_associated_backups_s3', 'label' => 'All backups will be permanently deleted (associated with this backup job) from the selected S3 Storage.'],
- // ['id' => 'delete_associated_backups_sftp', 'label' => 'All backups associated with this backup job from this database will be permanently deleted from the selected SFTP Storage.']
- ],
- ]);
- }
-}
diff --git a/app/Livewire/Project/Database/BackupExecutions.php b/app/Livewire/Project/Database/BackupExecutions.php
deleted file mode 100644
index 3fc721fda3..0000000000
--- a/app/Livewire/Project/Database/BackupExecutions.php
+++ /dev/null
@@ -1,129 +0,0 @@
- 'refreshBackupExecutions',
- ];
- }
-
- public function cleanupFailed()
- {
- if ($this->backup) {
- $this->backup->executions()->where('status', 'failed')->delete();
- $this->refreshBackupExecutions();
- $this->dispatch('success', 'Failed backups cleaned up.');
- }
- }
-
- public function deleteBackup($executionId, $password)
- {
- if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return;
- }
- }
-
- $execution = $this->backup->executions()->where('id', $executionId)->first();
- if (is_null($execution)) {
- $this->dispatch('error', 'Backup execution not found.');
-
- return;
- }
-
- $server = $execution->scheduledDatabaseBackup->database->getMorphClass() === \App\Models\ServiceDatabase::class
- ? $execution->scheduledDatabaseBackup->database->service->destination->server
- : $execution->scheduledDatabaseBackup->database->destination->server;
-
- try {
- if ($execution->filename) {
- deleteBackupsLocally($execution->filename, $server);
-
- if ($this->delete_backup_s3 && $execution->scheduledDatabaseBackup->s3) {
- deleteBackupsS3($execution->filename, $execution->scheduledDatabaseBackup->s3);
- }
- }
-
- $execution->delete();
- $this->dispatch('success', 'Backup deleted.');
- $this->refreshBackupExecutions();
- } catch (\Exception $e) {
- $this->dispatch('error', 'Failed to delete backup: '.$e->getMessage());
- }
- }
-
- public function download_file($exeuctionId)
- {
- return redirect()->route('download.backup', $exeuctionId);
- }
-
- public function refreshBackupExecutions(): void
- {
- if ($this->backup && $this->backup->exists) {
- $this->executions = $this->backup->executions()->get()->toArray();
- } else {
- $this->executions = [];
- }
- }
-
- public function mount(ScheduledDatabaseBackup $backup)
- {
- $this->backup = $backup;
- $this->database = $backup->database;
- $this->refreshBackupExecutions();
- }
-
- public function server()
- {
- if ($this->database) {
- $server = null;
-
- if ($this->database instanceof \App\Models\ServiceDatabase) {
- $server = $this->database->service->destination->server;
- } elseif ($this->database->destination && $this->database->destination->server) {
- $server = $this->database->destination->server;
- }
- if ($server) {
- return $server;
- }
- }
-
- return null;
- }
-
- public function render()
- {
- return view('livewire.project.database.backup-executions', [
- 'checkboxes' => [
- ['id' => 'delete_backup_s3', 'label' => 'Delete the selected backup permanently form S3 Storage'],
- // ['id' => 'delete_backup_sftp', 'label' => 'Delete the selected backup permanently form SFTP Storage'],
- ],
- ]);
- }
-}
diff --git a/app/Livewire/Project/Database/BackupNow.php b/app/Livewire/Project/Database/BackupNow.php
deleted file mode 100644
index 3cd3605623..0000000000
--- a/app/Livewire/Project/Database/BackupNow.php
+++ /dev/null
@@ -1,17 +0,0 @@
-backup);
- $this->dispatch('success', 'Backup queued. It will be available in a few minutes.');
- }
-}
diff --git a/app/Livewire/Project/Database/Clickhouse/General.php b/app/Livewire/Project/Database/Clickhouse/General.php
deleted file mode 100644
index 2d39c5151f..0000000000
--- a/app/Livewire/Project/Database/Clickhouse/General.php
+++ /dev/null
@@ -1,182 +0,0 @@
-currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},DatabaseProxyStopped" => 'databaseProxyStopped',
- ];
- }
-
- public function mount()
- {
- try {
- $this->syncData();
- $this->server = data_get($this->database, 'destination.server');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->database->name = $this->name;
- $this->database->description = $this->description;
- $this->database->clickhouse_admin_user = $this->clickhouseAdminUser;
- $this->database->clickhouse_admin_password = $this->clickhouseAdminPassword;
- $this->database->image = $this->image;
- $this->database->ports_mappings = $this->portsMappings;
- $this->database->is_public = $this->isPublic;
- $this->database->public_port = $this->publicPort;
- $this->database->custom_docker_run_options = $this->customDockerRunOptions;
- $this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
- $this->database->save();
-
- $this->dbUrl = $this->database->internal_db_url;
- $this->dbUrlPublic = $this->database->external_db_url;
- } else {
- $this->name = $this->database->name;
- $this->description = $this->database->description;
- $this->clickhouseAdminUser = $this->database->clickhouse_admin_user;
- $this->clickhouseAdminPassword = $this->database->clickhouse_admin_password;
- $this->image = $this->database->image;
- $this->portsMappings = $this->database->ports_mappings;
- $this->isPublic = $this->database->is_public;
- $this->publicPort = $this->database->public_port;
- $this->customDockerRunOptions = $this->database->custom_docker_run_options;
- $this->isLogDrainEnabled = $this->database->is_log_drain_enabled;
- $this->dbUrl = $this->database->internal_db_url;
- $this->dbUrlPublic = $this->database->external_db_url;
- }
- }
-
- public function instantSaveAdvanced()
- {
- try {
- if (! $this->server->isLogDrainEnabled()) {
- $this->isLogDrainEnabled = false;
- $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
-
- return;
- }
- $this->syncData(true);
-
- $this->dispatch('success', 'Database updated.');
- $this->dispatch('success', 'You need to restart the service for the changes to take effect.');
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSave()
- {
- try {
- if ($this->isPublic && ! $this->publicPort) {
- $this->dispatch('error', 'Public port is required.');
- $this->isPublic = false;
-
- return;
- }
- if ($this->isPublic) {
- if (! str($this->database->status)->startsWith('running')) {
- $this->dispatch('error', 'Database must be started to be publicly accessible.');
- $this->isPublic = false;
-
- return;
- }
- StartDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is now publicly accessible.');
- } else {
- StopDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is no longer publicly accessible.');
- }
- $this->dbUrlPublic = $this->database->external_db_url;
- $this->syncData(true);
- } catch (\Throwable $e) {
- $this->isPublic = ! $this->isPublic;
- $this->syncData(true);
-
- return handleError($e, $this);
- }
- }
-
- public function databaseProxyStopped()
- {
- $this->syncData();
- }
-
- public function submit()
- {
- try {
- if (str($this->publicPort)->isEmpty()) {
- $this->publicPort = null;
- }
- $this->syncData(true);
- $this->dispatch('success', 'Database updated.');
- } catch (Exception $e) {
- return handleError($e, $this);
- } finally {
- if (is_null($this->database->config_hash)) {
- $this->database->isConfigurationChanged(true);
- } else {
- $this->dispatch('configurationChanged');
- }
- }
- }
-}
diff --git a/app/Livewire/Project/Database/Configuration.php b/app/Livewire/Project/Database/Configuration.php
deleted file mode 100644
index 938abba549..0000000000
--- a/app/Livewire/Project/Database/Configuration.php
+++ /dev/null
@@ -1,47 +0,0 @@
-currentRoute = request()->route()->getName();
-
- $project = currentTeam()
- ->projects()
- ->select('id', 'uuid', 'team_id')
- ->where('uuid', request()->route('project_uuid'))
- ->firstOrFail();
- $environment = $project->environments()
- ->select('id', 'name', 'project_id', 'uuid')
- ->where('uuid', request()->route('environment_uuid'))
- ->firstOrFail();
- $database = $environment->databases()
- ->where('uuid', request()->route('database_uuid'))
- ->firstOrFail();
-
- $this->database = $database;
- $this->project = $project;
- $this->environment = $environment;
- if (str($this->database->status)->startsWith('running') && is_null($this->database->config_hash)) {
- $this->database->isConfigurationChanged(true);
- $this->dispatch('configurationChanged');
- }
- }
-
- public function render()
- {
- return view('livewire.project.database.configuration');
- }
-}
diff --git a/app/Livewire/Project/Database/CreateScheduledBackup.php b/app/Livewire/Project/Database/CreateScheduledBackup.php
deleted file mode 100644
index 01108c2900..0000000000
--- a/app/Livewire/Project/Database/CreateScheduledBackup.php
+++ /dev/null
@@ -1,84 +0,0 @@
-definedS3s = currentTeam()->s3s;
- if ($this->definedS3s->count() > 0) {
- $this->s3StorageId = $this->definedS3s->first()->id;
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- $this->validate();
-
- $isValid = validate_cron_expression($this->frequency);
- if (! $isValid) {
- $this->dispatch('error', 'Invalid Cron / Human expression.');
-
- return;
- }
-
- $payload = [
- 'enabled' => true,
- 'frequency' => $this->frequency,
- 'save_s3' => $this->saveToS3,
- 's3_storage_id' => $this->s3StorageId,
- 'database_id' => $this->database->id,
- 'database_type' => $this->database->getMorphClass(),
- 'team_id' => currentTeam()->id,
- ];
-
- if ($this->database->type() === 'standalone-postgresql') {
- $payload['databases_to_backup'] = $this->database->postgres_db;
- } elseif ($this->database->type() === 'standalone-mysql') {
- $payload['databases_to_backup'] = $this->database->mysql_database;
- } elseif ($this->database->type() === 'standalone-mariadb') {
- $payload['databases_to_backup'] = $this->database->mariadb_database;
- }
-
- $databaseBackup = ScheduledDatabaseBackup::create($payload);
- if ($this->database->getMorphClass() === \App\Models\ServiceDatabase::class) {
- $this->dispatch('refreshScheduledBackups', $databaseBackup->id);
- } else {
- $this->dispatch('refreshScheduledBackups');
- }
-
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- $this->frequency = '';
- }
- }
-}
diff --git a/app/Livewire/Project/Database/Dragonfly/General.php b/app/Livewire/Project/Database/Dragonfly/General.php
deleted file mode 100644
index ea6cd46b04..0000000000
--- a/app/Livewire/Project/Database/Dragonfly/General.php
+++ /dev/null
@@ -1,177 +0,0 @@
-currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},DatabaseProxyStopped" => 'databaseProxyStopped',
- ];
- }
-
- public function mount()
- {
- try {
- $this->syncData();
- $this->server = data_get($this->database, 'destination.server');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->database->name = $this->name;
- $this->database->description = $this->description;
- $this->database->dragonfly_password = $this->dragonflyPassword;
- $this->database->image = $this->image;
- $this->database->ports_mappings = $this->portsMappings;
- $this->database->is_public = $this->isPublic;
- $this->database->public_port = $this->publicPort;
- $this->database->custom_docker_run_options = $this->customDockerRunOptions;
- $this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
- $this->database->save();
-
- $this->dbUrl = $this->database->internal_db_url;
- $this->dbUrlPublic = $this->database->external_db_url;
- } else {
- $this->name = $this->database->name;
- $this->description = $this->database->description;
- $this->dragonflyPassword = $this->database->dragonfly_password;
- $this->image = $this->database->image;
- $this->portsMappings = $this->database->ports_mappings;
- $this->isPublic = $this->database->is_public;
- $this->publicPort = $this->database->public_port;
- $this->customDockerRunOptions = $this->database->custom_docker_run_options;
- $this->isLogDrainEnabled = $this->database->is_log_drain_enabled;
- $this->dbUrl = $this->database->internal_db_url;
- $this->dbUrlPublic = $this->database->external_db_url;
- }
- }
-
- public function instantSaveAdvanced()
- {
- try {
- if (! $this->server->isLogDrainEnabled()) {
- $this->isLogDrainEnabled = false;
- $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
-
- return;
- }
- $this->syncData(true);
-
- $this->dispatch('success', 'Database updated.');
- $this->dispatch('success', 'You need to restart the service for the changes to take effect.');
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSave()
- {
- try {
- if ($this->isPublic && ! $this->publicPort) {
- $this->dispatch('error', 'Public port is required.');
- $this->isPublic = false;
-
- return;
- }
- if ($this->isPublic) {
- if (! str($this->database->status)->startsWith('running')) {
- $this->dispatch('error', 'Database must be started to be publicly accessible.');
- $this->isPublic = false;
-
- return;
- }
- StartDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is now publicly accessible.');
- } else {
- StopDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is no longer publicly accessible.');
- }
- $this->dbUrlPublic = $this->database->external_db_url;
- $this->syncData(true);
- } catch (\Throwable $e) {
- $this->isPublic = ! $this->isPublic;
- $this->syncData(true);
-
- return handleError($e, $this);
- }
- }
-
- public function databaseProxyStopped()
- {
- $this->syncData();
- }
-
- public function submit()
- {
- try {
- if (str($this->publicPort)->isEmpty()) {
- $this->publicPort = null;
- }
- $this->syncData(true);
- $this->dispatch('success', 'Database updated.');
- } catch (Exception $e) {
- return handleError($e, $this);
- } finally {
- if (is_null($this->database->config_hash)) {
- $this->database->isConfigurationChanged(true);
- } else {
- $this->dispatch('configurationChanged');
- }
- }
- }
-}
diff --git a/app/Livewire/Project/Database/Heading.php b/app/Livewire/Project/Database/Heading.php
deleted file mode 100644
index c3b57b9f4d..0000000000
--- a/app/Livewire/Project/Database/Heading.php
+++ /dev/null
@@ -1,88 +0,0 @@
- 'activityFinished',
- ];
- }
-
- public function activityFinished()
- {
- $this->database->update([
- 'started_at' => now(),
- ]);
- $this->dispatch('refresh');
- $this->check_status();
- if (is_null($this->database->config_hash) || $this->database->isConfigurationChanged()) {
- $this->database->isConfigurationChanged(true);
- $this->dispatch('configurationChanged');
- } else {
- $this->dispatch('configurationChanged');
- }
- }
-
- public function check_status($showNotification = false)
- {
- if ($this->database->destination->server->isFunctional()) {
- GetContainersStatus::dispatch($this->database->destination->server);
- }
-
- if ($showNotification) {
- $this->dispatch('success', 'Database status updated.');
- }
- }
-
- public function mount()
- {
- $this->parameters = get_route_parameters();
- }
-
- public function stop()
- {
- StopDatabase::run($this->database, false, $this->docker_cleanup);
- $this->database->status = 'exited';
- $this->database->save();
- $this->check_status();
- }
-
- public function restart()
- {
- $activity = RestartDatabase::run($this->database);
- $this->dispatch('activityMonitor', $activity->id);
- }
-
- public function start()
- {
- $activity = StartDatabase::run($this->database);
- $this->dispatch('activityMonitor', $activity->id);
- }
-
- public function render()
- {
- return view('livewire.project.database.heading', [
- 'checkboxes' => [
- ['id' => 'docker_cleanup', 'label' => __('resource.docker_cleanup')],
- ],
- ]);
- }
-}
diff --git a/app/Livewire/Project/Database/Import.php b/app/Livewire/Project/Database/Import.php
deleted file mode 100644
index eb80ca6f6f..0000000000
--- a/app/Livewire/Project/Database/Import.php
+++ /dev/null
@@ -1,253 +0,0 @@
- '$refresh',
- ];
- }
-
- public function mount()
- {
- if (isDev()) {
- $this->customLocation = '/data/coolify/pg-dump-all-1736245863.gz';
- }
- $this->parameters = get_route_parameters();
- $this->getContainers();
- }
-
- public function updatedDumpAll($value)
- {
- switch ($this->resource->getMorphClass()) {
- case \App\Models\StandaloneMariadb::class:
- if ($value === true) {
- $this->mariadbRestoreCommand = <<<'EOD'
-for pid in $(mariadb -u root -p$MARIADB_ROOT_PASSWORD -N -e "SELECT id FROM information_schema.processlist WHERE user != 'root';"); do
- mariadb -u root -p$MARIADB_ROOT_PASSWORD -e "KILL $pid" 2>/dev/null || true
-done && \
-mariadb -u root -p$MARIADB_ROOT_PASSWORD -N -e "SELECT CONCAT('DROP DATABASE IF EXISTS \`',schema_name,'\`;') FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql','performance_schema','sys');" | mariadb -u root -p$MARIADB_ROOT_PASSWORD && \
-mariadb -u root -p$MARIADB_ROOT_PASSWORD -e "CREATE DATABASE IF NOT EXISTS \`default\`;" && \
-(gunzip -cf $tmpPath 2>/dev/null || cat $tmpPath) | sed -e '/^CREATE DATABASE/d' -e '/^USE \`mysql\`/d' | mariadb -u root -p$MARIADB_ROOT_PASSWORD default
-EOD;
- $this->restoreCommandText = $this->mariadbRestoreCommand.' && (gunzip -cf 2>/dev/null || cat ) | mariadb -u root -p$MARIADB_ROOT_PASSWORD default';
- } else {
- $this->mariadbRestoreCommand = 'mariadb -u $MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE';
- }
- break;
- case \App\Models\StandaloneMysql::class:
- if ($value === true) {
- $this->mysqlRestoreCommand = <<<'EOD'
-for pid in $(mysql -u root -p$MYSQL_ROOT_PASSWORD -N -e "SELECT id FROM information_schema.processlist WHERE user != 'root';"); do
- mysql -u root -p$MYSQL_ROOT_PASSWORD -e "KILL $pid" 2>/dev/null || true
-done && \
-mysql -u root -p$MYSQL_ROOT_PASSWORD -N -e "SELECT CONCAT('DROP DATABASE IF EXISTS \`',schema_name,'\`;') FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql','performance_schema','sys');" | mysql -u root -p$MYSQL_ROOT_PASSWORD && \
-mysql -u root -p$MYSQL_ROOT_PASSWORD -e "CREATE DATABASE IF NOT EXISTS \`default\`;" && \
-(gunzip -cf $tmpPath 2>/dev/null || cat $tmpPath) | sed -e '/^CREATE DATABASE/d' -e '/^USE \`mysql\`/d' | mysql -u root -p$MYSQL_ROOT_PASSWORD default
-EOD;
- $this->restoreCommandText = $this->mysqlRestoreCommand.' && (gunzip -cf 2>/dev/null || cat ) | mysql -u root -p$MYSQL_ROOT_PASSWORD default';
- } else {
- $this->mysqlRestoreCommand = 'mysql -u $MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE';
- }
- break;
- case \App\Models\StandalonePostgresql::class:
- if ($value === true) {
- $this->postgresqlRestoreCommand = <<<'EOD'
-psql -U $POSTGRES_USER -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname IS NOT NULL AND pid <> pg_backend_pid()" && \
-psql -U $POSTGRES_USER -t -c "SELECT datname FROM pg_database WHERE NOT datistemplate" | xargs -I {} dropdb -U $POSTGRES_USER --if-exists {} && \
-createdb -U $POSTGRES_USER postgres
-EOD;
- $this->restoreCommandText = $this->postgresqlRestoreCommand.' && (gunzip -cf 2>/dev/null || cat ) | psql -U $POSTGRES_USER postgres';
- } else {
- $this->postgresqlRestoreCommand = 'pg_restore -U $POSTGRES_USER -d $POSTGRES_DB';
- }
- break;
- }
-
- }
-
- public function getContainers()
- {
- $this->containers = collect();
- if (! data_get($this->parameters, 'database_uuid')) {
- abort(404);
- }
- $resource = getResourceByUuid($this->parameters['database_uuid'], data_get(auth()->user()->currentTeam(), 'id'));
- if (is_null($resource)) {
- abort(404);
- }
- $this->resource = $resource;
- $this->server = $this->resource->destination->server;
- $this->container = $this->resource->uuid;
- if (str(data_get($this, 'resource.status'))->startsWith('running')) {
- $this->containers->push($this->container);
- }
-
- if (
- $this->resource->getMorphClass() === \App\Models\StandaloneRedis::class ||
- $this->resource->getMorphClass() === \App\Models\StandaloneKeydb::class ||
- $this->resource->getMorphClass() === \App\Models\StandaloneDragonfly::class ||
- $this->resource->getMorphClass() === \App\Models\StandaloneClickhouse::class
- ) {
- $this->unsupported = true;
- }
- }
-
- public function checkFile()
- {
- if (filled($this->customLocation)) {
- try {
- $result = instant_remote_process(["ls -l {$this->customLocation}"], $this->server, throwError: false);
- if (blank($result)) {
- $this->dispatch('error', 'The file does not exist or has been deleted.');
-
- return;
- }
- $this->filename = $this->customLocation;
- $this->dispatch('success', 'The file exists.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
- }
-
- public function runImport()
- {
- if ($this->filename === '') {
- $this->dispatch('error', 'Please select a file to import.');
-
- return;
- }
- try {
- $this->importCommands = [];
- if (filled($this->customLocation)) {
- $backupFileName = '/tmp/restore_'.$this->resource->uuid;
- $this->importCommands[] = "docker cp {$this->customLocation} {$this->container}:{$backupFileName}";
- $tmpPath = $backupFileName;
- } else {
- $backupFileName = "upload/{$this->resource->uuid}/restore";
- $path = Storage::path($backupFileName);
- if (! Storage::exists($backupFileName)) {
- $this->dispatch('error', 'The file does not exist or has been deleted.');
-
- return;
- }
- $tmpPath = '/tmp/'.basename($backupFileName).'_'.$this->resource->uuid;
- instant_scp($path, $tmpPath, $this->server);
- Storage::delete($backupFileName);
- $this->importCommands[] = "docker cp {$tmpPath} {$this->container}:{$tmpPath}";
- }
-
- // Copy the restore command to a script file
- $scriptPath = "/tmp/restore_{$this->resource->uuid}.sh";
-
- switch ($this->resource->getMorphClass()) {
- case \App\Models\StandaloneMariadb::class:
- $restoreCommand = $this->mariadbRestoreCommand;
- if ($this->dumpAll) {
- $restoreCommand .= " && (gunzip -cf {$tmpPath} 2>/dev/null || cat {$tmpPath}) | mariadb -u root -p\$MARIADB_ROOT_PASSWORD";
- } else {
- $restoreCommand .= " < {$tmpPath}";
- }
- break;
- case \App\Models\StandaloneMysql::class:
- $restoreCommand = $this->mysqlRestoreCommand;
- if ($this->dumpAll) {
- $restoreCommand .= " && (gunzip -cf {$tmpPath} 2>/dev/null || cat {$tmpPath}) | mysql -u root -p\$MYSQL_ROOT_PASSWORD";
- } else {
- $restoreCommand .= " < {$tmpPath}";
- }
- break;
- case \App\Models\StandalonePostgresql::class:
- $restoreCommand = $this->postgresqlRestoreCommand;
- if ($this->dumpAll) {
- $restoreCommand .= " && (gunzip -cf {$tmpPath} 2>/dev/null || cat {$tmpPath}) | psql -U \$POSTGRES_USER postgres";
- } else {
- $restoreCommand .= " {$tmpPath}";
- }
- break;
- case \App\Models\StandaloneMongodb::class:
- $restoreCommand = $this->mongodbRestoreCommand;
- if ($this->dumpAll === false) {
- $restoreCommand .= "{$tmpPath}";
- }
- break;
- }
-
- $restoreCommandBase64 = base64_encode($restoreCommand);
- $this->importCommands[] = "echo \"{$restoreCommandBase64}\" | base64 -d > {$scriptPath}";
- $this->importCommands[] = "chmod +x {$scriptPath}";
- $this->importCommands[] = "docker cp {$scriptPath} {$this->container}:{$scriptPath}";
-
- $this->importCommands[] = "docker exec {$this->container} sh -c '{$scriptPath}'";
- $this->importCommands[] = "docker exec {$this->container} sh -c 'echo \"Import finished with exit code $?\"'";
-
- if (! empty($this->importCommands)) {
- $activity = remote_process($this->importCommands, $this->server, ignore_errors: true, callEventOnFinish: 'RestoreJobFinished', callEventData: [
- 'scriptPath' => $scriptPath,
- 'tmpPath' => $tmpPath,
- 'container' => $this->container,
- 'serverId' => $this->server->id,
- ]);
- $this->dispatch('activityMonitor', $activity->id);
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- $this->filename = null;
- $this->importCommands = [];
- }
- }
-}
diff --git a/app/Livewire/Project/Database/InitScript.php b/app/Livewire/Project/Database/InitScript.php
deleted file mode 100644
index e3baa1c8ee..0000000000
--- a/app/Livewire/Project/Database/InitScript.php
+++ /dev/null
@@ -1,56 +0,0 @@
-index = data_get($this->script, 'index');
- $this->filename = data_get($this->script, 'filename');
- $this->content = data_get($this->script, 'content');
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- $this->validate();
- $this->script['index'] = $this->index;
- $this->script['content'] = $this->content;
- $this->script['filename'] = $this->filename;
- $this->dispatch('save_init_script', $this->script);
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function delete()
- {
- try {
- $this->dispatch('delete_init_script', $this->script);
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Project/Database/Keydb/General.php b/app/Livewire/Project/Database/Keydb/General.php
deleted file mode 100644
index e768495eb8..0000000000
--- a/app/Livewire/Project/Database/Keydb/General.php
+++ /dev/null
@@ -1,182 +0,0 @@
-currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},DatabaseProxyStopped" => 'databaseProxyStopped',
- ];
- }
-
- public function mount()
- {
- try {
- $this->syncData();
- $this->server = data_get($this->database, 'destination.server');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->database->name = $this->name;
- $this->database->description = $this->description;
- $this->database->keydb_conf = $this->keydbConf;
- $this->database->keydb_password = $this->keydbPassword;
- $this->database->image = $this->image;
- $this->database->ports_mappings = $this->portsMappings;
- $this->database->is_public = $this->isPublic;
- $this->database->public_port = $this->publicPort;
- $this->database->custom_docker_run_options = $this->customDockerRunOptions;
- $this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
- $this->database->save();
-
- $this->dbUrl = $this->database->internal_db_url;
- $this->dbUrlPublic = $this->database->external_db_url;
- } else {
- $this->name = $this->database->name;
- $this->description = $this->database->description;
- $this->keydbConf = $this->database->keydb_conf;
- $this->keydbPassword = $this->database->keydb_password;
- $this->image = $this->database->image;
- $this->portsMappings = $this->database->ports_mappings;
- $this->isPublic = $this->database->is_public;
- $this->publicPort = $this->database->public_port;
- $this->customDockerRunOptions = $this->database->custom_docker_run_options;
- $this->isLogDrainEnabled = $this->database->is_log_drain_enabled;
- $this->dbUrl = $this->database->internal_db_url;
- $this->dbUrlPublic = $this->database->external_db_url;
- }
- }
-
- public function instantSaveAdvanced()
- {
- try {
- if (! $this->server->isLogDrainEnabled()) {
- $this->isLogDrainEnabled = false;
- $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
-
- return;
- }
- $this->syncData(true);
-
- $this->dispatch('success', 'Database updated.');
- $this->dispatch('success', 'You need to restart the service for the changes to take effect.');
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSave()
- {
- try {
- if ($this->isPublic && ! $this->publicPort) {
- $this->dispatch('error', 'Public port is required.');
- $this->isPublic = false;
-
- return;
- }
- if ($this->isPublic) {
- if (! str($this->database->status)->startsWith('running')) {
- $this->dispatch('error', 'Database must be started to be publicly accessible.');
- $this->isPublic = false;
-
- return;
- }
- StartDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is now publicly accessible.');
- } else {
- StopDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is no longer publicly accessible.');
- }
- $this->dbUrlPublic = $this->database->external_db_url;
- $this->syncData(true);
- } catch (\Throwable $e) {
- $this->isPublic = ! $this->isPublic;
- $this->syncData(true);
-
- return handleError($e, $this);
- }
- }
-
- public function databaseProxyStopped()
- {
- $this->syncData();
- }
-
- public function submit()
- {
- try {
- if (str($this->publicPort)->isEmpty()) {
- $this->publicPort = null;
- }
- $this->syncData(true);
- $this->dispatch('success', 'Database updated.');
- } catch (Exception $e) {
- return handleError($e, $this);
- } finally {
- if (is_null($this->database->config_hash)) {
- $this->database->isConfigurationChanged(true);
- } else {
- $this->dispatch('configurationChanged');
- }
- }
- }
-}
diff --git a/app/Livewire/Project/Database/Mariadb/General.php b/app/Livewire/Project/Database/Mariadb/General.php
deleted file mode 100644
index c9d473223f..0000000000
--- a/app/Livewire/Project/Database/Mariadb/General.php
+++ /dev/null
@@ -1,139 +0,0 @@
- 'required',
- 'database.description' => 'nullable',
- 'database.mariadb_root_password' => 'required',
- 'database.mariadb_user' => 'required',
- 'database.mariadb_password' => 'required',
- 'database.mariadb_database' => 'required',
- 'database.mariadb_conf' => 'nullable',
- 'database.image' => 'required',
- 'database.ports_mappings' => 'nullable',
- 'database.is_public' => 'nullable|boolean',
- 'database.public_port' => 'nullable|integer',
- 'database.is_log_drain_enabled' => 'nullable|boolean',
- 'database.custom_docker_run_options' => 'nullable',
- ];
-
- protected $validationAttributes = [
- 'database.name' => 'Name',
- 'database.description' => 'Description',
- 'database.mariadb_root_password' => 'Root Password',
- 'database.mariadb_user' => 'User',
- 'database.mariadb_password' => 'Password',
- 'database.mariadb_database' => 'Database',
- 'database.mariadb_conf' => 'MariaDB Configuration',
- 'database.image' => 'Image',
- 'database.ports_mappings' => 'Port Mapping',
- 'database.is_public' => 'Is Public',
- 'database.public_port' => 'Public Port',
- 'database.custom_docker_run_options' => 'Custom Docker Options',
- ];
-
- public function mount()
- {
- $this->db_url = $this->database->internal_db_url;
- $this->db_url_public = $this->database->external_db_url;
- $this->server = data_get($this->database, 'destination.server');
- }
-
- public function instantSaveAdvanced()
- {
- try {
- if (! $this->server->isLogDrainEnabled()) {
- $this->database->is_log_drain_enabled = false;
- $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
-
- return;
- }
- $this->database->save();
- $this->dispatch('success', 'Database updated.');
- $this->dispatch('success', 'You need to restart the service for the changes to take effect.');
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- if (str($this->database->public_port)->isEmpty()) {
- $this->database->public_port = null;
- }
- $this->validate();
- $this->database->save();
- $this->dispatch('success', 'Database updated.');
- } catch (Exception $e) {
- return handleError($e, $this);
- } finally {
- if (is_null($this->database->config_hash)) {
- $this->database->isConfigurationChanged(true);
- } else {
- $this->dispatch('configurationChanged');
- }
- }
- }
-
- public function instantSave()
- {
- try {
- if ($this->database->is_public && ! $this->database->public_port) {
- $this->dispatch('error', 'Public port is required.');
- $this->database->is_public = false;
-
- return;
- }
- if ($this->database->is_public) {
- if (! str($this->database->status)->startsWith('running')) {
- $this->dispatch('error', 'Database must be started to be publicly accessible.');
- $this->database->is_public = false;
-
- return;
- }
- StartDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is now publicly accessible.');
- } else {
- StopDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is no longer publicly accessible.');
- }
- $this->db_url_public = $this->database->external_db_url;
- $this->database->save();
- } catch (\Throwable $e) {
- $this->database->is_public = ! $this->database->is_public;
-
- return handleError($e, $this);
- }
- }
-
- public function refresh(): void
- {
- $this->database->refresh();
- }
-
- public function render()
- {
- return view('livewire.project.database.mariadb.general');
- }
-}
diff --git a/app/Livewire/Project/Database/Mongodb/General.php b/app/Livewire/Project/Database/Mongodb/General.php
deleted file mode 100644
index e19895dae6..0000000000
--- a/app/Livewire/Project/Database/Mongodb/General.php
+++ /dev/null
@@ -1,140 +0,0 @@
- 'required',
- 'database.description' => 'nullable',
- 'database.mongo_conf' => 'nullable',
- 'database.mongo_initdb_root_username' => 'required',
- 'database.mongo_initdb_root_password' => 'required',
- 'database.mongo_initdb_database' => 'required',
- 'database.image' => 'required',
- 'database.ports_mappings' => 'nullable',
- 'database.is_public' => 'nullable|boolean',
- 'database.public_port' => 'nullable|integer',
- 'database.is_log_drain_enabled' => 'nullable|boolean',
- 'database.custom_docker_run_options' => 'nullable',
- ];
-
- protected $validationAttributes = [
- 'database.name' => 'Name',
- 'database.description' => 'Description',
- 'database.mongo_conf' => 'Mongo Configuration',
- 'database.mongo_initdb_root_username' => 'Root Username',
- 'database.mongo_initdb_root_password' => 'Root Password',
- 'database.mongo_initdb_database' => 'Database',
- 'database.image' => 'Image',
- 'database.ports_mappings' => 'Port Mapping',
- 'database.is_public' => 'Is Public',
- 'database.public_port' => 'Public Port',
- 'database.custom_docker_run_options' => 'Custom Docker Run Options',
- ];
-
- public function mount()
- {
- $this->db_url = $this->database->internal_db_url;
- $this->db_url_public = $this->database->external_db_url;
- $this->server = data_get($this->database, 'destination.server');
- }
-
- public function instantSaveAdvanced()
- {
- try {
- if (! $this->server->isLogDrainEnabled()) {
- $this->database->is_log_drain_enabled = false;
- $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
-
- return;
- }
- $this->database->save();
- $this->dispatch('success', 'Database updated.');
- $this->dispatch('success', 'You need to restart the service for the changes to take effect.');
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- if (str($this->database->public_port)->isEmpty()) {
- $this->database->public_port = null;
- }
- if (str($this->database->mongo_conf)->isEmpty()) {
- $this->database->mongo_conf = null;
- }
- $this->validate();
- $this->database->save();
- $this->dispatch('success', 'Database updated.');
- } catch (Exception $e) {
- return handleError($e, $this);
- } finally {
- if (is_null($this->database->config_hash)) {
- $this->database->isConfigurationChanged(true);
- } else {
- $this->dispatch('configurationChanged');
- }
- }
- }
-
- public function instantSave()
- {
- try {
- if ($this->database->is_public && ! $this->database->public_port) {
- $this->dispatch('error', 'Public port is required.');
- $this->database->is_public = false;
-
- return;
- }
- if ($this->database->is_public) {
- if (! str($this->database->status)->startsWith('running')) {
- $this->dispatch('error', 'Database must be started to be publicly accessible.');
- $this->database->is_public = false;
-
- return;
- }
- StartDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is now publicly accessible.');
- } else {
- StopDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is no longer publicly accessible.');
- }
- $this->db_url_public = $this->database->external_db_url;
- $this->database->save();
- } catch (\Throwable $e) {
- $this->database->is_public = ! $this->database->is_public;
-
- return handleError($e, $this);
- }
- }
-
- public function refresh(): void
- {
- $this->database->refresh();
- }
-
- public function render()
- {
- return view('livewire.project.database.mongodb.general');
- }
-}
diff --git a/app/Livewire/Project/Database/Mysql/General.php b/app/Livewire/Project/Database/Mysql/General.php
deleted file mode 100644
index 7d5270ddf5..0000000000
--- a/app/Livewire/Project/Database/Mysql/General.php
+++ /dev/null
@@ -1,139 +0,0 @@
- 'required',
- 'database.description' => 'nullable',
- 'database.mysql_root_password' => 'required',
- 'database.mysql_user' => 'required',
- 'database.mysql_password' => 'required',
- 'database.mysql_database' => 'required',
- 'database.mysql_conf' => 'nullable',
- 'database.image' => 'required',
- 'database.ports_mappings' => 'nullable',
- 'database.is_public' => 'nullable|boolean',
- 'database.public_port' => 'nullable|integer',
- 'database.is_log_drain_enabled' => 'nullable|boolean',
- 'database.custom_docker_run_options' => 'nullable',
- ];
-
- protected $validationAttributes = [
- 'database.name' => 'Name',
- 'database.description' => 'Description',
- 'database.mysql_root_password' => 'Root Password',
- 'database.mysql_user' => 'User',
- 'database.mysql_password' => 'Password',
- 'database.mysql_database' => 'Database',
- 'database.mysql_conf' => 'MySQL Configuration',
- 'database.image' => 'Image',
- 'database.ports_mappings' => 'Port Mapping',
- 'database.is_public' => 'Is Public',
- 'database.public_port' => 'Public Port',
- 'database.custom_docker_run_options' => 'Custom Docker Run Options',
- ];
-
- public function mount()
- {
- $this->db_url = $this->database->internal_db_url;
- $this->db_url_public = $this->database->external_db_url;
- $this->server = data_get($this->database, 'destination.server');
- }
-
- public function instantSaveAdvanced()
- {
- try {
- if (! $this->server->isLogDrainEnabled()) {
- $this->database->is_log_drain_enabled = false;
- $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
-
- return;
- }
- $this->database->save();
- $this->dispatch('success', 'Database updated.');
- $this->dispatch('success', 'You need to restart the service for the changes to take effect.');
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- if (str($this->database->public_port)->isEmpty()) {
- $this->database->public_port = null;
- }
- $this->validate();
- $this->database->save();
- $this->dispatch('success', 'Database updated.');
- } catch (Exception $e) {
- return handleError($e, $this);
- } finally {
- if (is_null($this->database->config_hash)) {
- $this->database->isConfigurationChanged(true);
- } else {
- $this->dispatch('configurationChanged');
- }
- }
- }
-
- public function instantSave()
- {
- try {
- if ($this->database->is_public && ! $this->database->public_port) {
- $this->dispatch('error', 'Public port is required.');
- $this->database->is_public = false;
-
- return;
- }
- if ($this->database->is_public) {
- if (! str($this->database->status)->startsWith('running')) {
- $this->dispatch('error', 'Database must be started to be publicly accessible.');
- $this->database->is_public = false;
-
- return;
- }
- StartDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is now publicly accessible.');
- } else {
- StopDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is no longer publicly accessible.');
- }
- $this->db_url_public = $this->database->external_db_url;
- $this->database->save();
- } catch (\Throwable $e) {
- $this->database->is_public = ! $this->database->is_public;
-
- return handleError($e, $this);
- }
- }
-
- public function refresh(): void
- {
- $this->database->refresh();
- }
-
- public function render()
- {
- return view('livewire.project.database.mysql.general');
- }
-}
diff --git a/app/Livewire/Project/Database/Postgresql/General.php b/app/Livewire/Project/Database/Postgresql/General.php
deleted file mode 100644
index 88dd5c1a86..0000000000
--- a/app/Livewire/Project/Database/Postgresql/General.php
+++ /dev/null
@@ -1,261 +0,0 @@
- 'required',
- 'database.description' => 'nullable',
- 'database.postgres_user' => 'required',
- 'database.postgres_password' => 'required',
- 'database.postgres_db' => 'required',
- 'database.postgres_initdb_args' => 'nullable',
- 'database.postgres_host_auth_method' => 'nullable',
- 'database.postgres_conf' => 'nullable',
- 'database.init_scripts' => 'nullable',
- 'database.image' => 'required',
- 'database.ports_mappings' => 'nullable',
- 'database.is_public' => 'nullable|boolean',
- 'database.public_port' => 'nullable|integer',
- 'database.is_log_drain_enabled' => 'nullable|boolean',
- 'database.custom_docker_run_options' => 'nullable',
- ];
-
- protected $validationAttributes = [
- 'database.name' => 'Name',
- 'database.description' => 'Description',
- 'database.postgres_user' => 'Postgres User',
- 'database.postgres_password' => 'Postgres Password',
- 'database.postgres_db' => 'Postgres DB',
- 'database.postgres_initdb_args' => 'Postgres Initdb Args',
- 'database.postgres_host_auth_method' => 'Postgres Host Auth Method',
- 'database.postgres_conf' => 'Postgres Configuration',
- 'database.init_scripts' => 'Init Scripts',
- 'database.image' => 'Image',
- 'database.ports_mappings' => 'Port Mapping',
- 'database.is_public' => 'Is Public',
- 'database.public_port' => 'Public Port',
- 'database.custom_docker_run_options' => 'Custom Docker Run Options',
- ];
-
- public function mount()
- {
- $this->db_url = $this->database->internal_db_url;
- $this->db_url_public = $this->database->external_db_url;
- $this->server = data_get($this->database, 'destination.server');
- }
-
- public function instantSaveAdvanced()
- {
- try {
- if (! $this->server->isLogDrainEnabled()) {
- $this->database->is_log_drain_enabled = false;
- $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
-
- return;
- }
- $this->database->save();
- $this->dispatch('success', 'Database updated.');
- $this->dispatch('success', 'You need to restart the service for the changes to take effect.');
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSave()
- {
- try {
- if ($this->database->is_public && ! $this->database->public_port) {
- $this->dispatch('error', 'Public port is required.');
- $this->database->is_public = false;
-
- return;
- }
- if ($this->database->is_public) {
- if (! str($this->database->status)->startsWith('running')) {
- $this->dispatch('error', 'Database must be started to be publicly accessible.');
- $this->database->is_public = false;
-
- return;
- }
- StartDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is now publicly accessible.');
- } else {
- StopDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is no longer publicly accessible.');
- }
- $this->db_url_public = $this->database->external_db_url;
- $this->database->save();
- } catch (\Throwable $e) {
- $this->database->is_public = ! $this->database->is_public;
-
- return handleError($e, $this);
- }
- }
-
- public function save_init_script($script)
- {
- $initScripts = collect($this->database->init_scripts ?? []);
-
- $existingScript = $initScripts->firstWhere('filename', $script['filename']);
- $oldScript = $initScripts->firstWhere('index', $script['index']);
-
- if ($existingScript && $existingScript['index'] !== $script['index']) {
- $this->dispatch('error', 'A script with this filename already exists.');
-
- return;
- }
-
- $container_name = $this->database->uuid;
- $configuration_dir = database_configuration_dir().'/'.$container_name;
-
- if ($oldScript && $oldScript['filename'] !== $script['filename']) {
- $old_file_path = "$configuration_dir/docker-entrypoint-initdb.d/{$oldScript['filename']}";
- $delete_command = "rm -f $old_file_path";
- try {
- instant_remote_process([$delete_command], $this->server);
- } catch (\Exception $e) {
- $this->dispatch('error', 'Failed to remove old init script from server: '.$e->getMessage());
-
- return;
- }
- }
-
- $index = $initScripts->search(function ($item) use ($script) {
- return $item['index'] === $script['index'];
- });
-
- if ($index !== false) {
- $initScripts[$index] = $script;
- } else {
- $initScripts->push($script);
- }
-
- $this->database->init_scripts = $initScripts->values()
- ->map(function ($item, $index) {
- $item['index'] = $index;
-
- return $item;
- })
- ->all();
-
- $this->database->save();
- $this->dispatch('success', 'Init script saved and updated.');
- }
-
- public function delete_init_script($script)
- {
- $collection = collect($this->database->init_scripts);
- $found = $collection->firstWhere('filename', $script['filename']);
- if ($found) {
- $container_name = $this->database->uuid;
- $configuration_dir = database_configuration_dir().'/'.$container_name;
- $file_path = "$configuration_dir/docker-entrypoint-initdb.d/{$script['filename']}";
-
- $command = "rm -f $file_path";
- try {
- instant_remote_process([$command], $this->server);
- } catch (\Exception $e) {
- $this->dispatch('error', 'Failed to remove init script from server: '.$e->getMessage());
-
- return;
- }
-
- $updatedScripts = $collection->filter(fn ($s) => $s['filename'] !== $script['filename'])
- ->values()
- ->map(function ($item, $index) {
- $item['index'] = $index;
-
- return $item;
- })
- ->all();
-
- $this->database->init_scripts = $updatedScripts;
- $this->database->save();
- $this->refresh();
- $this->dispatch('success', 'Init script deleted from the database and the server.');
- }
- }
-
- public function refresh(): void
- {
- $this->database->refresh();
- }
-
- public function save_new_init_script()
- {
- $this->validate([
- 'new_filename' => 'required|string',
- 'new_content' => 'required|string',
- ]);
- $found = collect($this->database->init_scripts)->firstWhere('filename', $this->new_filename);
- if ($found) {
- $this->dispatch('error', 'Filename already exists.');
-
- return;
- }
- if (! isset($this->database->init_scripts)) {
- $this->database->init_scripts = [];
- }
- $this->database->init_scripts = array_merge($this->database->init_scripts, [
- [
- 'index' => count($this->database->init_scripts),
- 'filename' => $this->new_filename,
- 'content' => $this->new_content,
- ],
- ]);
- $this->database->save();
- $this->dispatch('success', 'Init script added.');
- $this->new_content = '';
- $this->new_filename = '';
- }
-
- public function submit()
- {
- try {
- if (str($this->database->public_port)->isEmpty()) {
- $this->database->public_port = null;
- }
- $this->validate();
- $this->database->save();
- $this->dispatch('success', 'Database updated.');
- } catch (Exception $e) {
- return handleError($e, $this);
- } finally {
- if (is_null($this->database->config_hash)) {
- $this->database->isConfigurationChanged(true);
- } else {
- $this->dispatch('configurationChanged');
- }
- }
- }
-}
diff --git a/app/Livewire/Project/Database/Redis/General.php b/app/Livewire/Project/Database/Redis/General.php
deleted file mode 100644
index 05babeaec7..0000000000
--- a/app/Livewire/Project/Database/Redis/General.php
+++ /dev/null
@@ -1,163 +0,0 @@
- 'refresh',
- 'refresh',
- ];
-
- public Server $server;
-
- public StandaloneRedis $database;
-
- public string $redis_username;
-
- public string $redis_password;
-
- public string $redis_version;
-
- public ?string $db_url = null;
-
- public ?string $db_url_public = null;
-
- protected $rules = [
- 'database.name' => 'required',
- 'database.description' => 'nullable',
- 'database.redis_conf' => 'nullable',
- 'database.image' => 'required',
- 'database.ports_mappings' => 'nullable',
- 'database.is_public' => 'nullable|boolean',
- 'database.public_port' => 'nullable|integer',
- 'database.is_log_drain_enabled' => 'nullable|boolean',
- 'database.custom_docker_run_options' => 'nullable',
- 'redis_username' => 'required',
- 'redis_password' => 'required',
- ];
-
- protected $validationAttributes = [
- 'database.name' => 'Name',
- 'database.description' => 'Description',
- 'database.redis_conf' => 'Redis Configuration',
- 'database.image' => 'Image',
- 'database.ports_mappings' => 'Port Mapping',
- 'database.is_public' => 'Is Public',
- 'database.public_port' => 'Public Port',
- 'database.custom_docker_run_options' => 'Custom Docker Options',
- 'redis_username' => 'Redis Username',
- 'redis_password' => 'Redis Password',
- ];
-
- public function mount()
- {
- $this->server = data_get($this->database, 'destination.server');
- $this->refreshView();
- }
-
- public function instantSaveAdvanced()
- {
- try {
- if (! $this->server->isLogDrainEnabled()) {
- $this->database->is_log_drain_enabled = false;
- $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
-
- return;
- }
- $this->database->save();
- $this->dispatch('success', 'Database updated.');
- $this->dispatch('success', 'You need to restart the service for the changes to take effect.');
- } catch (Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- $this->validate();
-
- if (version_compare($this->redis_version, '6.0', '>=')) {
- $this->database->runtime_environment_variables()->updateOrCreate(
- ['key' => 'REDIS_USERNAME'],
- ['value' => $this->redis_username, 'resourceable_id' => $this->database->id]
- );
- }
- $this->database->runtime_environment_variables()->updateOrCreate(
- ['key' => 'REDIS_PASSWORD'],
- ['value' => $this->redis_password, 'resourceable_id' => $this->database->id]
- );
-
- $this->database->save();
- $this->dispatch('success', 'Database updated.');
- } catch (Exception $e) {
- return handleError($e, $this);
- } finally {
- $this->dispatch('refreshEnvs');
- }
- }
-
- public function instantSave()
- {
- try {
- if ($this->database->is_public && ! $this->database->public_port) {
- $this->dispatch('error', 'Public port is required.');
- $this->database->is_public = false;
-
- return;
- }
- if ($this->database->is_public) {
- if (! str($this->database->status)->startsWith('running')) {
- $this->dispatch('error', 'Database must be started to be publicly accessible.');
- $this->database->is_public = false;
-
- return;
- }
- StartDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is now publicly accessible.');
- } else {
- StopDatabaseProxy::run($this->database);
- $this->dispatch('success', 'Database is no longer publicly accessible.');
- }
- $this->db_url_public = $this->database->external_db_url;
- $this->database->save();
- } catch (\Throwable $e) {
- $this->database->is_public = ! $this->database->is_public;
-
- return handleError($e, $this);
- }
- }
-
- public function refresh(): void
- {
- $this->database->refresh();
- $this->refreshView();
- }
-
- private function refreshView()
- {
- $this->db_url = $this->database->internal_db_url;
- $this->db_url_public = $this->database->external_db_url;
- $this->redis_version = $this->database->getRedisVersion();
- $this->redis_username = $this->database->redis_username;
- $this->redis_password = $this->database->redis_password;
- }
-
- public function render()
- {
- return view('livewire.project.database.redis.general');
- }
-
- public function isSharedVariable($name)
- {
- return $this->database->runtime_environment_variables()->where('key', $name)->where('is_shared', true)->exists();
- }
-}
diff --git a/app/Livewire/Project/Database/ScheduledBackups.php b/app/Livewire/Project/Database/ScheduledBackups.php
deleted file mode 100644
index 412240bd4e..0000000000
--- a/app/Livewire/Project/Database/ScheduledBackups.php
+++ /dev/null
@@ -1,66 +0,0 @@
-selectedBackupId) {
- $this->setSelectedBackup($this->selectedBackupId, true);
- }
- $this->parameters = get_route_parameters();
- if ($this->database->getMorphClass() === \App\Models\ServiceDatabase::class) {
- $this->type = 'service-database';
- } else {
- $this->type = 'database';
- }
- $this->s3s = currentTeam()->s3s;
- }
-
- public function setSelectedBackup($backupId, $force = false)
- {
- if ($this->selectedBackupId === $backupId && ! $force) {
- return;
- }
- $this->selectedBackupId = $backupId;
- $this->selectedBackup = $this->database->scheduledBackups->find($backupId);
- if (is_null($this->selectedBackup)) {
- $this->selectedBackupId = null;
- }
- }
-
- public function delete($scheduled_backup_id): void
- {
- $this->database->scheduledBackups->find($scheduled_backup_id)->delete();
- $this->dispatch('success', 'Scheduled backup deleted.');
- $this->refreshScheduledBackups();
- }
-
- public function refreshScheduledBackups(?int $id = null): void
- {
- $this->database->refresh();
- if ($id) {
- $this->setSelectedBackup($id);
- }
- }
-}
diff --git a/app/Livewire/Project/DeleteEnvironment.php b/app/Livewire/Project/DeleteEnvironment.php
deleted file mode 100644
index 1ee5de2691..0000000000
--- a/app/Livewire/Project/DeleteEnvironment.php
+++ /dev/null
@@ -1,42 +0,0 @@
-environmentName = Environment::findOrFail($this->environment_id)->name;
- $this->parameters = get_route_parameters();
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function delete()
- {
- $this->validate([
- 'environment_id' => 'required|int',
- ]);
- $environment = Environment::findOrFail($this->environment_id);
- if ($environment->isEmpty()) {
- $environment->delete();
-
- return redirect()->route('project.show', parameters: ['project_uuid' => $this->parameters['project_uuid']]);
- }
-
- return $this->dispatch('error', "Environment {$environment->name} has defined resources, please delete them first.");
- }
-}
diff --git a/app/Livewire/Project/DeleteProject.php b/app/Livewire/Project/DeleteProject.php
deleted file mode 100644
index f320a19b0f..0000000000
--- a/app/Livewire/Project/DeleteProject.php
+++ /dev/null
@@ -1,38 +0,0 @@
-parameters = get_route_parameters();
- $this->projectName = Project::findOrFail($this->project_id)->name;
- }
-
- public function delete()
- {
- $this->validate([
- 'project_id' => 'required|int',
- ]);
- $project = Project::findOrFail($this->project_id);
- if ($project->isEmpty()) {
- $project->delete();
-
- return redirect()->route('project.index');
- }
-
- return $this->dispatch('error', "Project {$project->name} has resources defined, please delete them first.");
- }
-}
diff --git a/app/Livewire/Project/Edit.php b/app/Livewire/Project/Edit.php
deleted file mode 100644
index 463febb10d..0000000000
--- a/app/Livewire/Project/Edit.php
+++ /dev/null
@@ -1,52 +0,0 @@
-project = Project::where('team_id', currentTeam()->id)->where('uuid', $project_uuid)->firstOrFail();
- $this->syncData();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->project->update([
- 'name' => $this->name,
- 'description' => $this->description,
- ]);
- } else {
- $this->name = $this->project->name;
- $this->description = $this->project->description;
- }
- }
-
- public function submit()
- {
- try {
- $this->syncData(true);
- $this->dispatch('success', 'Project updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Project/EnvironmentEdit.php b/app/Livewire/Project/EnvironmentEdit.php
deleted file mode 100644
index e98b088ecf..0000000000
--- a/app/Livewire/Project/EnvironmentEdit.php
+++ /dev/null
@@ -1,68 +0,0 @@
-project = Project::ownedByCurrentTeam()->where('uuid', $project_uuid)->firstOrFail();
- $this->environment = $this->project->environments()->where('uuid', $environment_uuid)->firstOrFail();
- $this->syncData();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->environment->update([
- 'name' => $this->name,
- 'description' => $this->description,
- ]);
- } else {
- $this->name = $this->environment->name;
- $this->description = $this->environment->description;
- }
- }
-
- public function submit()
- {
- try {
- $this->syncData(true);
- $this->redirectRoute('project.environment.edit', [
- 'environment_uuid' => $this->environment->uuid,
- 'project_uuid' => $this->project->uuid,
- ]);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.project.environment-edit');
- }
-}
diff --git a/app/Livewire/Project/Index.php b/app/Livewire/Project/Index.php
deleted file mode 100644
index 8bf511a66a..0000000000
--- a/app/Livewire/Project/Index.php
+++ /dev/null
@@ -1,40 +0,0 @@
-private_keys = PrivateKey::ownedByCurrentTeam()->get();
- $this->projects = Project::ownedByCurrentTeam()->get()->map(function ($project) {
- $project->settingsRoute = route('project.edit', ['project_uuid' => $project->uuid]);
-
- return $project;
- });
- $this->servers = Server::ownedByCurrentTeam()->count();
- }
-
- public function render()
- {
- return view('livewire.project.index');
- }
-
- public function navigateToProject($projectUuid)
- {
- $project = collect($this->projects)->firstWhere('uuid', $projectUuid);
-
- return $this->redirect($project->navigateTo(), true);
- }
-}
diff --git a/app/Livewire/Project/New/DockerCompose.php b/app/Livewire/Project/New/DockerCompose.php
deleted file mode 100644
index 2f51094d10..0000000000
--- a/app/Livewire/Project/New/DockerCompose.php
+++ /dev/null
@@ -1,101 +0,0 @@
-parameters = get_route_parameters();
- $this->query = request()->query();
- if (isDev()) {
- $this->dockerComposeRaw = 'services:
- appsmith:
- build:
- context: .
- dockerfile_inline: |
- FROM nginx
- ARG GIT_COMMIT
- ARG GIT_BRANCH
- RUN echo "Hello World ${GIT_COMMIT} ${GIT_BRANCH}"
- args:
- - GIT_COMMIT=cdc3b19
- - GIT_BRANCH=${GIT_BRANCH}
- environment:
- - APPSMITH_MAIL_ENABLED=${APPSMITH_MAIL_ENABLED}
- ';
- }
- }
-
- public function submit()
- {
- $server_id = $this->query['server_id'];
- try {
- $this->validate([
- 'dockerComposeRaw' => 'required',
- ]);
- $this->dockerComposeRaw = Yaml::dump(Yaml::parse($this->dockerComposeRaw), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
- $project = Project::where('uuid', $this->parameters['project_uuid'])->first();
- $environment = $project->load(['environments'])->environments->where('uuid', $this->parameters['environment_uuid'])->first();
-
- $destination_uuid = $this->query['destination'];
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
- if (! $destination) {
- $destination = SwarmDocker::where('uuid', $destination_uuid)->first();
- }
- if (! $destination) {
- throw new \Exception('Destination not found. What?!');
- }
- $destination_class = $destination->getMorphClass();
-
- $service = Service::create([
- 'name' => 'service'.Str::random(10),
- 'docker_compose_raw' => $this->dockerComposeRaw,
- 'environment_id' => $environment->id,
- 'server_id' => (int) $server_id,
- 'destination_id' => $destination->id,
- 'destination_type' => $destination_class,
- ]);
-
- $variables = parseEnvFormatToArray($this->envFile);
- foreach ($variables as $key => $variable) {
- EnvironmentVariable::create([
- 'key' => $key,
- 'value' => $variable,
- 'is_build_time' => false,
- 'is_preview' => false,
- 'resourceable_id' => $service->id,
- 'resourceable_type' => $service->getMorphClass(),
- ]);
- }
- $service->name = "service-$service->uuid";
-
- $service->parse(isNew: true);
-
- return redirect()->route('project.service.configuration', [
- 'service_uuid' => $service->uuid,
- 'environment_uuid' => $environment->uuid,
- 'project_uuid' => $project->uuid,
- ]);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Project/New/DockerImage.php b/app/Livewire/Project/New/DockerImage.php
deleted file mode 100644
index 7d68ce0684..0000000000
--- a/app/Livewire/Project/New/DockerImage.php
+++ /dev/null
@@ -1,80 +0,0 @@
-parameters = get_route_parameters();
- $this->query = request()->query();
- }
-
- public function submit()
- {
- $this->validate([
- 'dockerImage' => 'required',
- ]);
-
- $parser = new DockerImageParser;
- $parser->parse($this->dockerImage);
-
- $destination_uuid = $this->query['destination'];
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
- if (! $destination) {
- $destination = SwarmDocker::where('uuid', $destination_uuid)->first();
- }
- if (! $destination) {
- throw new \Exception('Destination not found. What?!');
- }
- $destination_class = $destination->getMorphClass();
-
- $project = Project::where('uuid', $this->parameters['project_uuid'])->first();
- $environment = $project->load(['environments'])->environments->where('uuid', $this->parameters['environment_uuid'])->first();
- $application = Application::create([
- 'name' => 'docker-image-'.new Cuid2,
- 'repository_project_id' => 0,
- 'git_repository' => 'coollabsio/coolify',
- 'git_branch' => 'main',
- 'build_pack' => 'dockerimage',
- 'ports_exposes' => 80,
- 'docker_registry_image_name' => $parser->getFullImageNameWithoutTag(),
- 'docker_registry_image_tag' => $parser->getTag(),
- 'environment_id' => $environment->id,
- 'destination_id' => $destination->id,
- 'destination_type' => $destination_class,
- 'health_check_enabled' => false,
- ]);
-
- $fqdn = generateFqdn($destination->server, $application->uuid);
- $application->update([
- 'name' => 'docker-image-'.$application->uuid,
- 'fqdn' => $fqdn,
- ]);
-
- return redirect()->route('project.application.configuration', [
- 'application_uuid' => $application->uuid,
- 'environment_uuid' => $environment->uuid,
- 'project_uuid' => $project->uuid,
- ]);
- }
-
- public function render()
- {
- return view('livewire.project.new.docker-image');
- }
-}
diff --git a/app/Livewire/Project/New/EmptyProject.php b/app/Livewire/Project/New/EmptyProject.php
deleted file mode 100644
index 54cfc4b4d8..0000000000
--- a/app/Livewire/Project/New/EmptyProject.php
+++ /dev/null
@@ -1,21 +0,0 @@
- generate_random_name(),
- 'team_id' => currentTeam()->id,
- 'uuid' => (string) new Cuid2,
- ]);
-
- return redirect()->route('project.show', ['project_uuid' => $project->uuid, 'environment_uuid' => $project->environments->first()->uuid]);
- }
-}
diff --git a/app/Livewire/Project/New/GithubPrivateRepository.php b/app/Livewire/Project/New/GithubPrivateRepository.php
deleted file mode 100644
index 4a81d841f2..0000000000
--- a/app/Livewire/Project/New/GithubPrivateRepository.php
+++ /dev/null
@@ -1,233 +0,0 @@
-currentRoute = Route::currentRouteName();
- $this->parameters = get_route_parameters();
- $this->query = request()->query();
- $this->repositories = $this->branches = collect();
- $this->github_apps = GithubApp::private();
- }
-
- public function updatedBaseDirectory()
- {
- if ($this->base_directory) {
- $this->base_directory = rtrim($this->base_directory, '/');
- if (! str($this->base_directory)->startsWith('/')) {
- $this->base_directory = '/'.$this->base_directory;
- }
- }
- }
-
- public function updatedBuildPack()
- {
- if ($this->build_pack === 'nixpacks') {
- $this->show_is_static = true;
- $this->port = 3000;
- } elseif ($this->build_pack === 'static') {
- $this->show_is_static = false;
- $this->is_static = false;
- $this->port = 80;
- } else {
- $this->show_is_static = false;
- $this->is_static = false;
- }
- }
-
- public function loadRepositories($github_app_id)
- {
- $this->repositories = collect();
- $this->page = 1;
- $this->selected_github_app_id = $github_app_id;
- $this->github_app = GithubApp::where('id', $github_app_id)->first();
- $this->token = generateGithubInstallationToken($this->github_app);
- $this->loadRepositoryByPage();
- if ($this->repositories->count() < $this->total_repositories_count) {
- while ($this->repositories->count() < $this->total_repositories_count) {
- $this->page++;
- $this->loadRepositoryByPage();
- }
- }
- $this->repositories = $this->repositories->sortBy('name');
- if ($this->repositories->count() > 0) {
- $this->selected_repository_id = data_get($this->repositories->first(), 'id');
- }
- $this->current_step = 'repository';
- }
-
- protected function loadRepositoryByPage()
- {
- $response = Http::withToken($this->token)->get("{$this->github_app->api_url}/installation/repositories?per_page=100&page={$this->page}");
- $json = $response->json();
- if ($response->status() !== 200) {
- return $this->dispatch('error', $json['message']);
- }
-
- if ($json['total_count'] === 0) {
- return;
- }
- $this->total_repositories_count = $json['total_count'];
- $this->repositories = $this->repositories->concat(collect($json['repositories']));
- }
-
- public function loadBranches()
- {
- $this->selected_repository_owner = $this->repositories->where('id', $this->selected_repository_id)->first()['owner']['login'];
- $this->selected_repository_repo = $this->repositories->where('id', $this->selected_repository_id)->first()['name'];
- $this->branches = collect();
- $this->page = 1;
- $this->loadBranchByPage();
- if ($this->total_branches_count === 100) {
- while ($this->total_branches_count === 100) {
- $this->page++;
- $this->loadBranchByPage();
- }
- }
- $this->selected_branch_name = data_get($this->branches, '0.name', 'main');
- }
-
- protected function loadBranchByPage()
- {
- $response = Http::withToken($this->token)->get("{$this->github_app->api_url}/repos/{$this->selected_repository_owner}/{$this->selected_repository_repo}/branches?per_page=100&page={$this->page}");
- $json = $response->json();
- if ($response->status() !== 200) {
- return $this->dispatch('error', $json['message']);
- }
-
- $this->total_branches_count = count($json);
- $this->branches = $this->branches->concat(collect($json));
- }
-
- public function submit()
- {
- try {
- $destination_uuid = $this->query['destination'];
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
- if (! $destination) {
- $destination = SwarmDocker::where('uuid', $destination_uuid)->first();
- }
- if (! $destination) {
- throw new \Exception('Destination not found. What?!');
- }
- $destination_class = $destination->getMorphClass();
-
- $project = Project::where('uuid', $this->parameters['project_uuid'])->first();
- $environment = $project->load(['environments'])->environments->where('uuid', $this->parameters['environment_uuid'])->first();
-
- $application = Application::create([
- 'name' => generate_application_name($this->selected_repository_owner.'/'.$this->selected_repository_repo, $this->selected_branch_name),
- 'repository_project_id' => $this->selected_repository_id,
- 'git_repository' => "{$this->selected_repository_owner}/{$this->selected_repository_repo}",
- 'git_branch' => $this->selected_branch_name,
- 'build_pack' => $this->build_pack,
- 'ports_exposes' => $this->port,
- 'publish_directory' => $this->publish_directory,
- 'environment_id' => $environment->id,
- 'destination_id' => $destination->id,
- 'destination_type' => $destination_class,
- 'source_id' => $this->github_app->id,
- 'source_type' => $this->github_app->getMorphClass(),
- ]);
- $application->settings->is_static = $this->is_static;
- $application->settings->save();
-
- if ($this->build_pack === 'dockerfile' || $this->build_pack === 'dockerimage') {
- $application->health_check_enabled = false;
- }
- if ($this->build_pack === 'dockercompose') {
- $application['docker_compose_location'] = $this->docker_compose_location;
- $application['base_directory'] = $this->base_directory;
- }
- $fqdn = generateFqdn($destination->server, $application->uuid);
- $application->fqdn = $fqdn;
-
- $application->name = generate_application_name($this->selected_repository_owner.'/'.$this->selected_repository_repo, $this->selected_branch_name, $application->uuid);
- $application->save();
-
- return redirect()->route('project.application.configuration', [
- 'application_uuid' => $application->uuid,
- 'environment_uuid' => $environment->uuid,
- 'project_uuid' => $project->uuid,
- ]);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSave()
- {
- if ($this->is_static) {
- $this->port = 80;
- $this->publish_directory = '/dist';
- } else {
- $this->port = 3000;
- $this->publish_directory = null;
- }
- $this->dispatch('success', 'Application settings updated!');
- }
-}
diff --git a/app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php b/app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
deleted file mode 100644
index 01b0c9ae85..0000000000
--- a/app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
+++ /dev/null
@@ -1,215 +0,0 @@
- 'required',
- 'branch' => 'required|string',
- 'port' => 'required|numeric',
- 'is_static' => 'required|boolean',
- 'publish_directory' => 'nullable|string',
- 'build_pack' => 'required|string',
- ];
-
- protected $validationAttributes = [
- 'repository_url' => 'Repository',
- 'branch' => 'Branch',
- 'port' => 'Port',
- 'is_static' => 'Is static',
- 'publish_directory' => 'Publish directory',
- 'build_pack' => 'Build pack',
- ];
-
- public function mount()
- {
- if (isDev()) {
- $this->repository_url = 'https://github.com/coollabsio/coolify-examples';
- }
- $this->parameters = get_route_parameters();
- $this->query = request()->query();
- if (isDev()) {
- $this->private_keys = PrivateKey::where('team_id', currentTeam()->id)->get();
- } else {
- $this->private_keys = PrivateKey::where('team_id', currentTeam()->id)->where('id', '!=', 0)->get();
- }
- }
-
- public function updatedBuildPack()
- {
- if ($this->build_pack === 'nixpacks') {
- $this->show_is_static = true;
- $this->port = 3000;
- } elseif ($this->build_pack === 'static') {
- $this->show_is_static = false;
- $this->is_static = false;
- $this->port = 80;
- } else {
- $this->show_is_static = false;
- $this->is_static = false;
- }
- }
-
- public function instantSave()
- {
- if ($this->is_static) {
- $this->port = 80;
- $this->publish_directory = '/dist';
- } else {
- $this->port = 3000;
- $this->publish_directory = null;
- }
- }
-
- public function setPrivateKey($private_key_id)
- {
- $this->private_key_id = $private_key_id;
- $this->current_step = 'repository';
- }
-
- public function submit()
- {
- $this->validate();
- try {
- $destination_uuid = $this->query['destination'];
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
- if (! $destination) {
- $destination = SwarmDocker::where('uuid', $destination_uuid)->first();
- }
- if (! $destination) {
- throw new \Exception('Destination not found. What?!');
- }
- $destination_class = $destination->getMorphClass();
-
- $this->get_git_source();
-
- $project = Project::where('uuid', $this->parameters['project_uuid'])->first();
- $environment = $project->load(['environments'])->environments->where('uuid', $this->parameters['environment_uuid'])->first();
- if ($this->git_source === 'other') {
- $application_init = [
- 'name' => generate_random_name(),
- 'git_repository' => $this->git_repository,
- 'git_branch' => $this->branch,
- 'build_pack' => $this->build_pack,
- 'ports_exposes' => $this->port,
- 'publish_directory' => $this->publish_directory,
- 'environment_id' => $environment->id,
- 'destination_id' => $destination->id,
- 'destination_type' => $destination_class,
- 'private_key_id' => $this->private_key_id,
- ];
- } else {
- $application_init = [
- 'name' => generate_random_name(),
- 'git_repository' => $this->git_repository,
- 'git_branch' => $this->branch,
- 'build_pack' => $this->build_pack,
- 'ports_exposes' => $this->port,
- 'publish_directory' => $this->publish_directory,
- 'environment_id' => $environment->id,
- 'destination_id' => $destination->id,
- 'destination_type' => $destination_class,
- 'private_key_id' => $this->private_key_id,
- 'source_id' => $this->git_source->id,
- 'source_type' => $this->git_source->getMorphClass(),
- ];
- }
- if ($this->build_pack === 'dockerfile' || $this->build_pack === 'dockerimage') {
- $application_init['health_check_enabled'] = false;
- }
- if ($this->build_pack === 'dockercompose') {
- $application_init['docker_compose_location'] = $this->docker_compose_location;
- $application_init['base_directory'] = $this->base_directory;
- }
- $application = Application::create($application_init);
- $application->settings->is_static = $this->is_static;
- $application->settings->save();
-
- $fqdn = generateFqdn($destination->server, $application->uuid);
- $application->fqdn = $fqdn;
- $application->name = generate_random_name($application->uuid);
- $application->save();
-
- return redirect()->route('project.application.configuration', [
- 'application_uuid' => $application->uuid,
- 'environment_uuid' => $environment->uuid,
- 'project_uuid' => $project->uuid,
- ]);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- private function get_git_source()
- {
- $this->repository_url_parsed = Url::fromString($this->repository_url);
- $this->git_host = $this->repository_url_parsed->getHost();
- $this->git_repository = $this->repository_url_parsed->getSegment(1).'/'.$this->repository_url_parsed->getSegment(2);
-
- if ($this->git_host === 'github.com') {
- $this->git_source = GithubApp::where('name', 'Public GitHub')->first();
-
- return;
- }
- if (str($this->repository_url)->startsWith('http')) {
- $this->git_host = $this->repository_url_parsed->getHost();
- $this->git_repository = $this->repository_url_parsed->getSegment(1).'/'.$this->repository_url_parsed->getSegment(2);
- $this->git_repository = Str::finish("git@$this->git_host:$this->git_repository", '.git');
- } else {
- $this->git_repository = $this->repository_url;
- }
- $this->git_source = 'other';
- }
-}
diff --git a/app/Livewire/Project/New/PublicGitRepository.php b/app/Livewire/Project/New/PublicGitRepository.php
deleted file mode 100644
index 45b3b57261..0000000000
--- a/app/Livewire/Project/New/PublicGitRepository.php
+++ /dev/null
@@ -1,340 +0,0 @@
- 'required|url',
- 'port' => 'required|numeric',
- 'isStatic' => 'required|boolean',
- 'publish_directory' => 'nullable|string',
- 'build_pack' => 'required|string',
- 'base_directory' => 'nullable|string',
- 'docker_compose_location' => 'nullable|string',
- ];
-
- protected $validationAttributes = [
- 'repository_url' => 'repository',
- 'port' => 'port',
- 'isStatic' => 'static',
- 'publish_directory' => 'publish directory',
- 'build_pack' => 'build pack',
- 'base_directory' => 'base directory',
- 'docker_compose_location' => 'docker compose location',
- ];
-
- public function mount()
- {
- if (isDev()) {
- $this->repository_url = 'https://github.com/coollabsio/coolify-examples';
- $this->port = 3000;
- }
- $this->parameters = get_route_parameters();
- $this->query = request()->query();
- }
-
- public function updatedBaseDirectory()
- {
- if ($this->base_directory) {
- $this->base_directory = rtrim($this->base_directory, '/');
- if (! str($this->base_directory)->startsWith('/')) {
- $this->base_directory = '/'.$this->base_directory;
- }
- }
- }
-
- public function updatedDockerComposeLocation()
- {
- if ($this->docker_compose_location) {
- $this->docker_compose_location = rtrim($this->docker_compose_location, '/');
- if (! str($this->docker_compose_location)->startsWith('/')) {
- $this->docker_compose_location = '/'.$this->docker_compose_location;
- }
- }
- }
-
- public function updatedBuildPack()
- {
- if ($this->build_pack === 'nixpacks') {
- $this->show_is_static = true;
- $this->port = 3000;
- } elseif ($this->build_pack === 'static') {
- $this->show_is_static = false;
- $this->isStatic = false;
- $this->port = 80;
- } else {
- $this->show_is_static = false;
- $this->isStatic = false;
- }
- }
-
- public function instantSave()
- {
- if ($this->isStatic) {
- $this->port = 80;
- $this->publish_directory = '/dist';
- } else {
- $this->port = 3000;
- $this->publish_directory = null;
- }
- $this->dispatch('success', 'Application settings updated!');
- }
-
- public function loadBranch()
- {
- try {
- if (str($this->repository_url)->startsWith('git@')) {
- $github_instance = str($this->repository_url)->after('git@')->before(':');
- $repository = str($this->repository_url)->after(':')->before('.git');
- $this->repository_url = 'https://'.str($github_instance).'/'.$repository;
- }
- if (
- (str($this->repository_url)->startsWith('https://') ||
- str($this->repository_url)->startsWith('http://')) &&
- ! str($this->repository_url)->endsWith('.git') &&
- (! str($this->repository_url)->contains('github.com') ||
- ! str($this->repository_url)->contains('git.sr.ht'))
- ) {
- $this->repository_url = $this->repository_url.'.git';
- }
- if (str($this->repository_url)->contains('github.com') && str($this->repository_url)->endsWith('.git')) {
- $this->repository_url = str($this->repository_url)->beforeLast('.git')->value();
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- try {
- $this->branchFound = false;
- $this->getGitSource();
- $this->getBranch();
- $this->selectedBranch = $this->git_branch;
- } catch (\Throwable $e) {
- if ($this->rate_limit_remaining == 0) {
- $this->selectedBranch = $this->git_branch;
- $this->branchFound = true;
-
- return;
- }
- if (! $this->branchFound && $this->git_branch === 'main') {
- try {
- $this->git_branch = 'master';
- $this->getBranch();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- } else {
- return handleError($e, $this);
- }
- }
- }
-
- private function getGitSource()
- {
- $this->git_branch = 'main';
- $this->base_directory = '/';
-
- $this->repository_url_parsed = Url::fromString($this->repository_url);
- $this->git_host = $this->repository_url_parsed->getHost();
- $this->git_repository = $this->repository_url_parsed->getSegment(1).'/'.$this->repository_url_parsed->getSegment(2);
-
- if ($this->repository_url_parsed->getSegment(3) === 'tree') {
- $path = str($this->repository_url_parsed->getPath())->trim('/');
- $this->git_branch = str($path)->after('tree/')->before('/')->value();
- $this->base_directory = str($path)->after($this->git_branch)->after('/')->value();
- if (filled($this->base_directory)) {
- $this->base_directory = '/'.$this->base_directory;
- } else {
- $this->base_directory = '/';
- }
- } else {
- $this->git_branch = 'main';
- }
- if ($this->git_host === 'github.com') {
- $this->git_source = GithubApp::where('name', 'Public GitHub')->first();
-
- return;
- }
- $this->git_repository = $this->repository_url;
- $this->git_source = 'other';
- }
-
- private function getBranch()
- {
- if ($this->git_source === 'other') {
- $this->branchFound = true;
-
- return;
- }
- if ($this->git_source->getMorphClass() === \App\Models\GithubApp::class) {
- ['rate_limit_remaining' => $this->rate_limit_remaining, 'rate_limit_reset' => $this->rate_limit_reset] = githubApi(source: $this->git_source, endpoint: "/repos/{$this->git_repository}/branches/{$this->git_branch}");
- $this->rate_limit_reset = Carbon::parse((int) $this->rate_limit_reset)->format('Y-M-d H:i:s');
- $this->branchFound = true;
- }
- }
-
- public function submit()
- {
- try {
- $this->validate();
- $destination_uuid = $this->query['destination'];
- $project_uuid = $this->parameters['project_uuid'];
- $environment_uuid = $this->parameters['environment_uuid'];
-
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
- if (! $destination) {
- $destination = SwarmDocker::where('uuid', $destination_uuid)->first();
- }
- if (! $destination) {
- throw new \Exception('Destination not found. What?!');
- }
- $destination_class = $destination->getMorphClass();
-
- $project = Project::where('uuid', $project_uuid)->first();
- $environment = $project->load(['environments'])->environments->where('uuid', $environment_uuid)->first();
-
- if ($this->build_pack === 'dockercompose' && isDev() && $this->new_compose_services) {
- $server = $destination->server;
- $new_service = [
- 'name' => 'service'.str()->random(10),
- 'docker_compose_raw' => 'coolify',
- 'environment_id' => $environment->id,
- 'server_id' => $server->id,
- ];
- if ($this->git_source === 'other') {
- $new_service['git_repository'] = $this->git_repository;
- $new_service['git_branch'] = $this->git_branch;
- } else {
- $new_service['git_repository'] = $this->git_repository;
- $new_service['git_branch'] = $this->git_branch;
- $new_service['source_id'] = $this->git_source->id;
- $new_service['source_type'] = $this->git_source->getMorphClass();
- }
- $service = Service::create($new_service);
-
- return redirect()->route('project.service.configuration', [
- 'service_uuid' => $service->uuid,
- 'environment_uuid' => $environment->uuid,
- 'project_uuid' => $project->uuid,
- ]);
-
- return;
- }
- if ($this->git_source === 'other') {
- $application_init = [
- 'name' => generate_random_name(),
- 'git_repository' => $this->git_repository,
- 'git_branch' => $this->git_branch,
- 'ports_exposes' => $this->port,
- 'publish_directory' => $this->publish_directory,
- 'environment_id' => $environment->id,
- 'destination_id' => $destination->id,
- 'destination_type' => $destination_class,
- 'build_pack' => $this->build_pack,
- 'base_directory' => $this->base_directory,
- ];
- } else {
- $application_init = [
- 'name' => generate_application_name($this->git_repository, $this->git_branch),
- 'git_repository' => $this->git_repository,
- 'git_branch' => $this->git_branch,
- 'ports_exposes' => $this->port,
- 'publish_directory' => $this->publish_directory,
- 'environment_id' => $environment->id,
- 'destination_id' => $destination->id,
- 'destination_type' => $destination_class,
- 'source_id' => $this->git_source->id,
- 'source_type' => $this->git_source->getMorphClass(),
- 'build_pack' => $this->build_pack,
- 'base_directory' => $this->base_directory,
- ];
- }
-
- if ($this->build_pack === 'dockerfile' || $this->build_pack === 'dockerimage') {
- $application_init['health_check_enabled'] = false;
- }
- if ($this->build_pack === 'dockercompose') {
- $application_init['docker_compose_location'] = $this->docker_compose_location;
- $application_init['base_directory'] = $this->base_directory;
- }
- $application = Application::create($application_init);
-
- $application->settings->is_static = $this->isStatic;
- $application->settings->save();
- $fqdn = generateFqdn($destination->server, $application->uuid);
- $application->fqdn = $fqdn;
- $application->save();
- if ($this->checkCoolifyConfig) {
- // $config = loadConfigFromGit($this->repository_url, $this->git_branch, $this->base_directory, $this->query['server_id'], auth()->user()->currentTeam()->id);
- // if ($config) {
- // $application->setConfig($config);
- // }
- }
-
- return redirect()->route('project.application.configuration', [
- 'application_uuid' => $application->uuid,
- 'environment_uuid' => $environment->uuid,
- 'project_uuid' => $project->uuid,
- ]);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Project/New/Select.php b/app/Livewire/Project/New/Select.php
deleted file mode 100644
index 396930c403..0000000000
--- a/app/Livewire/Project/New/Select.php
+++ /dev/null
@@ -1,337 +0,0 @@
-parameters = get_route_parameters();
- if (isDev()) {
- $this->existingPostgresqlUrl = 'postgres://coolify:password@coolify-db:5432';
- }
- $projectUuid = data_get($this->parameters, 'project_uuid');
- $this->environments = Project::whereUuid($projectUuid)->first()->environments;
- $this->selectedEnvironment = data_get($this->parameters, 'environment_uuid');
- }
-
- public function render()
- {
- return view('livewire.project.new.select');
- }
-
- public function updatedSelectedEnvironment()
- {
- return redirect()->route('project.resource.create', [
- 'project_uuid' => $this->parameters['project_uuid'],
- 'environment_uuid' => $this->selectedEnvironment,
- ]);
- }
-
- public function loadServices()
- {
- $services = get_service_templates();
- $services = collect($services)->map(function ($service, $key) {
- $default_logo = 'images/default.webp';
- $logo = data_get($service, 'logo', $default_logo);
- $local_logo_path = public_path($logo);
-
- return [
- 'name' => str($key)->headline(),
- 'logo' => asset($logo),
- 'logo_github_url' => file_exists($local_logo_path)
- ? 'https://raw.githubusercontent.com/coollabsio/coolify/refs/heads/main/public/'.$logo
- : asset($default_logo),
- ] + (array) $service;
- })->all();
- $gitBasedApplications = [
- [
- 'id' => 'public',
- 'name' => 'Public Repository',
- 'description' => 'You can deploy any kind of public repositories from the supported git providers.',
- 'logo' => asset('svgs/git.svg'),
- ],
- [
- 'id' => 'private-gh-app',
- 'name' => 'Private Repository (with GitHub App)',
- 'description' => 'You can deploy public & private repositories through your GitHub Apps.',
- 'logo' => asset('svgs/github.svg'),
- ],
- [
- 'id' => 'private-deploy-key',
- 'name' => 'Private Repository (with Deploy Key)',
- 'description' => 'You can deploy private repositories with a deploy key.',
- 'logo' => asset('svgs/git.svg'),
- ],
- ];
- $dockerBasedApplications = [
- [
- 'id' => 'dockerfile',
- 'name' => 'Dockerfile',
- 'description' => 'You can deploy a simple Dockerfile, without Git.',
- 'logo' => asset('svgs/docker.svg'),
- ],
- [
- 'id' => 'docker-compose-empty',
- 'name' => 'Docker Compose Empty',
- 'description' => 'You can deploy complex application easily with Docker Compose, without Git.',
- 'logo' => asset('svgs/docker.svg'),
- ],
- [
- 'id' => 'docker-image',
- 'name' => 'Docker Image',
- 'description' => 'You can deploy an existing Docker Image from any Registry, without Git.',
- 'logo' => asset('svgs/docker.svg'),
- ],
- ];
- $databases = [
- [
- 'id' => 'postgresql',
- 'name' => 'PostgreSQL',
- 'description' => 'PostgreSQL is an object-relational database known for its robustness, advanced features, and strong standards compliance.',
- 'logo' => '
-',
- ],
- [
- 'id' => 'mysql',
- 'name' => 'MySQL',
- 'description' => 'MySQL is an open-source relational database management system. ',
- 'logo' => '
-
-
-
- ',
-
- ],
- [
- 'id' => 'mariadb',
- 'name' => 'MariaDB',
- 'description' => 'MariaDB is a community-developed, commercially supported fork of the MySQL relational database management system, intended to remain free and open-source.',
- 'logo' => ' ',
- ],
- [
- 'id' => 'redis',
- 'name' => 'Redis',
- 'description' => 'Redis is a source-available, in-memory storage, used as a distributed, in-memory key–value database, cache and message broker, with optional durability.',
- 'logo' => ' ',
- ],
- [
- 'id' => 'keydb',
- 'name' => 'KeyDB',
- 'description' => 'KeyDB is a database that offers high performance, low latency, and scalability for various data structures and workloads.',
- 'logo' => ' ',
- ],
- [
- 'id' => 'dragonfly',
- 'name' => 'Dragonfly',
- 'description' => 'Dragonfly DB is a drop-in Redis replacement that delivers 25x more throughput and 12x faster snapshotting than Redis.',
- 'logo' => '',
- ],
- [
- 'id' => 'mongodb',
- 'name' => 'MongoDB',
- 'description' => 'MongoDB is a source-available, cross-platform, document-oriented database program.',
- 'logo' => ' ',
- ],
- [
- 'id' => 'clickhouse',
- 'name' => 'ClickHouse',
- 'description' => 'ClickHouse is a column-oriented database that supports real-time analytics, business intelligence, observability, ML and GenAI, and more.',
- 'logo' => '
',
- ],
-
- ];
-
- return [
- 'services' => $services,
- 'gitBasedApplications' => $gitBasedApplications,
- 'dockerBasedApplications' => $dockerBasedApplications,
- 'databases' => $databases,
- ];
- }
-
- public function instantSave()
- {
- if ($this->includeSwarm) {
- $this->servers = $this->allServers;
- } else {
- if ($this->allServers instanceof Collection) {
- $this->servers = $this->allServers->where('settings.is_swarm_worker', false)->where('settings.is_swarm_manager', false)->where('settings.is_build_server', false);
- } else {
- $this->servers = $this->allServers;
- }
- }
- }
-
- public function setType(string $type)
- {
- $type = str($type)->lower()->slug()->value();
- if ($this->loading) {
- return;
- }
- $this->loading = true;
- $this->type = $type;
- switch ($type) {
- case 'postgresql':
- case 'mysql':
- case 'mariadb':
- case 'redis':
- case 'keydb':
- case 'dragonfly':
- case 'clickhouse':
- case 'mongodb':
- $this->isDatabase = true;
- $this->includeSwarm = false;
- if ($this->allServers instanceof Collection) {
- $this->servers = $this->allServers->where('settings.is_swarm_worker', false)->where('settings.is_swarm_manager', false)->where('settings.is_build_server', false);
- } else {
- $this->servers = $this->allServers;
- }
- break;
- }
- if (str($type)->startsWith('one-click-service') || str($type)->startsWith('docker-compose-empty')) {
- $this->isDatabase = true;
- $this->includeSwarm = false;
- if ($this->allServers instanceof Collection) {
- $this->servers = $this->allServers->where('settings.is_swarm_worker', false)->where('settings.is_swarm_manager', false)->where('settings.is_build_server', false);
- } else {
- $this->servers = $this->allServers;
- }
- }
- if ($type === 'existing-postgresql') {
- $this->current_step = $type;
-
- return;
- }
- if (count($this->servers) === 1) {
- $server = $this->servers->first();
- if ($server instanceof Server) {
- $this->setServer($server);
- }
- }
- if (! is_null($this->server)) {
- $foundServer = $this->servers->where('id', $this->server->id)->first();
- if ($foundServer) {
- return $this->setServer($foundServer);
- }
- }
- $this->current_step = 'servers';
- }
-
- public function setServer(Server $server)
- {
- $this->server_id = $server->id;
- $this->server = $server;
- $this->standaloneDockers = $server->standaloneDockers;
- $this->swarmDockers = $server->swarmDockers;
- $count = count($this->standaloneDockers) + count($this->swarmDockers);
- if ($count === 1) {
- $docker = $this->standaloneDockers->first() ?? $this->swarmDockers->first();
- if ($docker) {
- $this->setDestination($docker->uuid);
-
- return $this->whatToDoNext();
- }
- }
- $this->current_step = 'destinations';
- }
-
- public function setDestination(string $destination_uuid)
- {
- $this->destination_uuid = $destination_uuid;
-
- return $this->whatToDoNext();
- }
-
- public function setPostgresqlType(string $type)
- {
- $this->postgresql_type = $type;
-
- return redirect()->route('project.resource.create', [
- 'project_uuid' => $this->parameters['project_uuid'],
- 'environment_uuid' => $this->parameters['environment_uuid'],
- 'type' => $this->type,
- 'destination' => $this->destination_uuid,
- 'server_id' => $this->server_id,
- 'database_image' => $this->postgresql_type,
- ]);
- }
-
- public function whatToDoNext()
- {
- if ($this->type === 'postgresql') {
- $this->current_step = 'select-postgresql-type';
- } else {
- return redirect()->route('project.resource.create', [
- 'project_uuid' => $this->parameters['project_uuid'],
- 'environment_uuid' => $this->parameters['environment_uuid'],
- 'type' => $this->type,
- 'destination' => $this->destination_uuid,
- 'server_id' => $this->server_id,
- ]);
- }
- }
-
- public function loadServers()
- {
- $this->servers = Server::isUsable()->get()->sortBy('name');
- $this->allServers = $this->servers;
-
- if ($this->allServers && $this->allServers->isNotEmpty()) {
- $this->onlyBuildServerAvailable = $this->allServers->every(function ($server) {
- return $server->isBuildServer();
- });
- }
- }
-}
diff --git a/app/Livewire/Project/New/SimpleDockerfile.php b/app/Livewire/Project/New/SimpleDockerfile.php
deleted file mode 100644
index c3ed6039a0..0000000000
--- a/app/Livewire/Project/New/SimpleDockerfile.php
+++ /dev/null
@@ -1,85 +0,0 @@
-parameters = get_route_parameters();
- $this->query = request()->query();
- if (isDev()) {
- $this->dockerfile = 'FROM nginx
-EXPOSE 80
-CMD ["nginx", "-g", "daemon off;"]
-';
- }
- }
-
- public function submit()
- {
- $this->validate([
- 'dockerfile' => 'required',
- ]);
- $destination_uuid = $this->query['destination'];
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
- if (! $destination) {
- $destination = SwarmDocker::where('uuid', $destination_uuid)->first();
- }
- if (! $destination) {
- throw new \Exception('Destination not found. What?!');
- }
- $destination_class = $destination->getMorphClass();
-
- $project = Project::where('uuid', $this->parameters['project_uuid'])->first();
- $environment = $project->load(['environments'])->environments->where('uuid', $this->parameters['environment_uuid'])->first();
-
- $port = get_port_from_dockerfile($this->dockerfile);
- if (! $port) {
- $port = 80;
- }
- $application = Application::create([
- 'name' => 'dockerfile-'.new Cuid2,
- 'repository_project_id' => 0,
- 'git_repository' => 'coollabsio/coolify',
- 'git_branch' => 'main',
- 'build_pack' => 'dockerfile',
- 'dockerfile' => $this->dockerfile,
- 'ports_exposes' => $port,
- 'environment_id' => $environment->id,
- 'destination_id' => $destination->id,
- 'destination_type' => $destination_class,
- 'health_check_enabled' => false,
- 'source_id' => 0,
- 'source_type' => GithubApp::class,
- ]);
-
- $fqdn = generateFqdn($destination->server, $application->uuid);
- $application->update([
- 'name' => 'dockerfile-'.$application->uuid,
- 'fqdn' => $fqdn,
- ]);
-
- $application->parseHealthcheckFromDockerfile(dockerfile: collect(str($this->dockerfile)->trim()->explode("\n")), isInit: true);
-
- return redirect()->route('project.application.configuration', [
- 'application_uuid' => $application->uuid,
- 'environment_uuid' => $environment->uuid,
- 'project_uuid' => $project->uuid,
- ]);
- }
-}
diff --git a/app/Livewire/Project/Resource/Create.php b/app/Livewire/Project/Resource/Create.php
deleted file mode 100644
index 0faf0b8da2..0000000000
--- a/app/Livewire/Project/Resource/Create.php
+++ /dev/null
@@ -1,123 +0,0 @@
-query('type'));
- $destination_uuid = request()->query('destination');
- $server_id = request()->query('server_id');
- $database_image = request()->query('database_image');
-
- $project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
- if (! $project) {
- return redirect()->route('dashboard');
- }
- $this->project = $project;
- $environment = $project->load(['environments'])->environments->where('uuid', request()->route('environment_uuid'))->first();
- if (! $environment) {
- return redirect()->route('dashboard');
- }
- if (isset($type) && isset($destination_uuid) && isset($server_id)) {
- $services = get_service_templates();
-
- if (in_array($type, DATABASE_TYPES)) {
- if ($type->value() === 'postgresql') {
- $database = create_standalone_postgresql(
- environmentId: $environment->id,
- destinationUuid: $destination_uuid,
- databaseImage: $database_image
- );
- } elseif ($type->value() === 'redis') {
- $database = create_standalone_redis($environment->id, $destination_uuid);
- } elseif ($type->value() === 'mongodb') {
- $database = create_standalone_mongodb($environment->id, $destination_uuid);
- } elseif ($type->value() === 'mysql') {
- $database = create_standalone_mysql($environment->id, $destination_uuid);
- } elseif ($type->value() === 'mariadb') {
- $database = create_standalone_mariadb($environment->id, $destination_uuid);
- } elseif ($type->value() === 'keydb') {
- $database = create_standalone_keydb($environment->id, $destination_uuid);
- } elseif ($type->value() === 'dragonfly') {
- $database = create_standalone_dragonfly($environment->id, $destination_uuid);
- } elseif ($type->value() === 'clickhouse') {
- $database = create_standalone_clickhouse($environment->id, $destination_uuid);
- }
-
- return redirect()->route('project.database.configuration', [
- 'project_uuid' => $project->uuid,
- 'environment_uuid' => $environment->uuid,
- 'database_uuid' => $database->uuid,
- ]);
- }
- if ($type->startsWith('one-click-service-') && ! is_null((int) $server_id)) {
- $oneClickServiceName = $type->after('one-click-service-')->value();
- $oneClickService = data_get($services, "$oneClickServiceName.compose");
- $oneClickDotEnvs = data_get($services, "$oneClickServiceName.envs", null);
- if ($oneClickDotEnvs) {
- $oneClickDotEnvs = str(base64_decode($oneClickDotEnvs))->split('/\r\n|\r|\n/')->filter(function ($value) {
- return ! empty($value);
- });
- }
- if ($oneClickService) {
- $destination = StandaloneDocker::whereUuid($destination_uuid)->first();
- $service_payload = [
- 'name' => "$oneClickServiceName-".str()->random(10),
- 'docker_compose_raw' => base64_decode($oneClickService),
- 'environment_id' => $environment->id,
- 'service_type' => $oneClickServiceName,
- 'server_id' => (int) $server_id,
- 'destination_id' => $destination->id,
- 'destination_type' => $destination->getMorphClass(),
- ];
- if ($oneClickServiceName === 'cloudflared') {
- data_set($service_payload, 'connect_to_docker_network', true);
- }
- $service = Service::create($service_payload);
- $service->name = "$oneClickServiceName-".$service->uuid;
- $service->save();
- if ($oneClickDotEnvs?->count() > 0) {
- $oneClickDotEnvs->each(function ($value) use ($service) {
- $key = str()->before($value, '=');
- $value = str(str()->after($value, '='));
- if ($value) {
- EnvironmentVariable::create([
- 'key' => $key,
- 'value' => $value,
- 'resourceable_id' => $service->id,
- 'resourceable_type' => $service->getMorphClass(),
- 'is_build_time' => false,
- 'is_preview' => false,
- ]);
- }
- });
- }
- $service->parse(isNew: true);
-
- return redirect()->route('project.service.configuration', [
- 'service_uuid' => $service->uuid,
- 'environment_uuid' => $environment->uuid,
- 'project_uuid' => $project->uuid,
- ]);
- }
- }
- $this->type = $type->value();
- }
- }
-
- public function render()
- {
- return view('livewire.project.resource.create');
- }
-}
diff --git a/app/Livewire/Project/Resource/EnvironmentSelect.php b/app/Livewire/Project/Resource/EnvironmentSelect.php
deleted file mode 100644
index a38d750daa..0000000000
--- a/app/Livewire/Project/Resource/EnvironmentSelect.php
+++ /dev/null
@@ -1,35 +0,0 @@
-selectedEnvironment = request()->route('environment_uuid');
- $this->project_uuid = request()->route('project_uuid');
- }
-
- public function updatedSelectedEnvironment($value)
- {
- if ($value === 'edit') {
- return redirect()->route('project.show', [
- 'project_uuid' => $this->project_uuid,
- ]);
- } else {
- return redirect()->route('project.resource.index', [
- 'project_uuid' => $this->project_uuid,
- 'environment_uuid' => $value,
- ]);
- }
- }
-}
diff --git a/app/Livewire/Project/Resource/Index.php b/app/Livewire/Project/Resource/Index.php
deleted file mode 100644
index 2b199dcfd6..0000000000
--- a/app/Livewire/Project/Resource/Index.php
+++ /dev/null
@@ -1,132 +0,0 @@
-applications = $this->postgresqls = $this->redis = $this->mongodbs = $this->mysqls = $this->mariadbs = $this->keydbs = $this->dragonflies = $this->clickhouses = $this->services = collect();
- $this->parameters = get_route_parameters();
- $project = currentTeam()
- ->projects()
- ->select('id', 'uuid', 'team_id', 'name')
- ->where('uuid', request()->route('project_uuid'))
- ->firstOrFail();
- $environment = $project->environments()
- ->select('id', 'uuid', 'name', 'project_id')
- ->where('uuid', request()->route('environment_uuid'))
- ->firstOrFail();
-
- $this->project = $project;
- $this->environment = $environment->loadCount([
- 'applications',
- 'redis',
- 'postgresqls',
- 'mysqls',
- 'keydbs',
- 'dragonflies',
- 'clickhouses',
- 'mariadbs',
- 'mongodbs',
- 'services',
- ]);
-
- // Eager load all relationships for applications including nested ones
- $this->applications = $this->environment->applications()->with([
- 'tags',
- 'additional_servers.settings',
- 'additional_networks',
- 'destination.server.settings',
- 'settings',
- ])->get()->sortBy('name');
- $this->applications = $this->applications->map(function ($application) {
- $application->hrefLink = route('project.application.configuration', [
- 'project_uuid' => data_get($application, 'environment.project.uuid'),
- 'environment_uuid' => data_get($application, 'environment.uuid'),
- 'application_uuid' => data_get($application, 'uuid'),
- ]);
-
- return $application;
- });
-
- // Load all database resources in a single query per type
- $databaseTypes = [
- 'postgresqls' => 'postgresqls',
- 'redis' => 'redis',
- 'mongodbs' => 'mongodbs',
- 'mysqls' => 'mysqls',
- 'mariadbs' => 'mariadbs',
- 'keydbs' => 'keydbs',
- 'dragonflies' => 'dragonflies',
- 'clickhouses' => 'clickhouses',
- ];
-
- foreach ($databaseTypes as $property => $relation) {
- $this->{$property} = $this->environment->{$relation}()->with([
- 'tags',
- 'destination.server.settings',
- ])->get()->sortBy('name');
- $this->{$property} = $this->{$property}->map(function ($db) {
- $db->hrefLink = route('project.database.configuration', [
- 'project_uuid' => $this->project->uuid,
- 'database_uuid' => $db->uuid,
- 'environment_uuid' => data_get($this->environment, 'uuid'),
- ]);
-
- return $db;
- });
- }
-
- // Load services with their tags and server
- $this->services = $this->environment->services()->with([
- 'tags',
- 'destination.server.settings',
- ])->get()->sortBy('name');
- $this->services = $this->services->map(function ($service) {
- $service->hrefLink = route('project.service.configuration', [
- 'project_uuid' => data_get($service, 'environment.project.uuid'),
- 'environment_uuid' => data_get($service, 'environment.uuid'),
- 'service_uuid' => data_get($service, 'uuid'),
- ]);
-
- return $service;
- });
- }
-
- public function render()
- {
- return view('livewire.project.resource.index');
- }
-}
diff --git a/app/Livewire/Project/Service/Configuration.php b/app/Livewire/Project/Service/Configuration.php
deleted file mode 100644
index da49dcae98..0000000000
--- a/app/Livewire/Project/Service/Configuration.php
+++ /dev/null
@@ -1,109 +0,0 @@
- 'check_status',
- 'check_status',
- 'refreshStatus' => '$refresh',
- ];
- }
-
- public function render()
- {
- return view('livewire.project.service.configuration');
- }
-
- public function mount()
- {
- $this->parameters = get_route_parameters();
- $this->currentRoute = request()->route()->getName();
- $this->query = request()->query();
- $project = currentTeam()
- ->projects()
- ->select('id', 'uuid', 'team_id')
- ->where('uuid', request()->route('project_uuid'))
- ->firstOrFail();
- $environment = $project->environments()
- ->select('id', 'uuid', 'name', 'project_id')
- ->where('uuid', request()->route('environment_uuid'))
- ->firstOrFail();
- $this->service = $environment->services()->whereUuid(request()->route('service_uuid'))->firstOrFail();
-
- $this->project = $project;
- $this->environment = $environment;
- $this->applications = $this->service->applications->sort();
- $this->databases = $this->service->databases->sort();
- }
-
- public function restartApplication($id)
- {
- try {
- $application = $this->service->applications->find($id);
- if ($application) {
- $application->restart();
- $this->dispatch('success', 'Service application restarted successfully.');
- }
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function restartDatabase($id)
- {
- try {
- $database = $this->service->databases->find($id);
- if ($database) {
- $database->restart();
- $this->dispatch('success', 'Service database restarted successfully.');
- }
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function check_status()
- {
- try {
- if ($this->service->server->isFunctional()) {
- GetContainersStatus::dispatch($this->service->server);
- }
- $this->service->applications->each(function ($application) {
- $application->refresh();
- });
- $this->service->databases->each(function ($database) {
- $database->refresh();
- });
- $this->dispatch('refreshStatus');
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Project/Service/Database.php b/app/Livewire/Project/Service/Database.php
deleted file mode 100644
index c3b7577e9d..0000000000
--- a/app/Livewire/Project/Service/Database.php
+++ /dev/null
@@ -1,129 +0,0 @@
- 'nullable',
- 'database.description' => 'nullable',
- 'database.image' => 'required',
- 'database.exclude_from_status' => 'required|boolean',
- 'database.public_port' => 'nullable|integer',
- 'database.is_public' => 'required|boolean',
- 'database.is_log_drain_enabled' => 'required|boolean',
- ];
-
- public function render()
- {
- return view('livewire.project.service.database');
- }
-
- public function mount()
- {
- $this->parameters = get_route_parameters();
- if ($this->database->is_public) {
- $this->db_url_public = $this->database->getServiceDatabaseUrl();
- }
- $this->refreshFileStorages();
- }
-
- public function delete($password)
- {
- if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return;
- }
- }
-
- try {
- $this->database->delete();
- $this->dispatch('success', 'Database deleted.');
-
- return redirect()->route('project.service.configuration', $this->parameters);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSaveExclude()
- {
- $this->submit();
- }
-
- public function instantSaveLogDrain()
- {
- if (! $this->database->service->destination->server->isLogDrainEnabled()) {
- $this->database->is_log_drain_enabled = false;
- $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
-
- return;
- }
- $this->submit();
- $this->dispatch('success', 'You need to restart the service for the changes to take effect.');
- }
-
- public function instantSave()
- {
- if ($this->database->is_public && ! $this->database->public_port) {
- $this->dispatch('error', 'Public port is required.');
- $this->database->is_public = false;
-
- return;
- }
- if ($this->database->is_public) {
- if (! str($this->database->status)->startsWith('running')) {
- $this->dispatch('error', 'Database must be started to be publicly accessible.');
- $this->database->is_public = false;
-
- return;
- }
- StartDatabaseProxy::run($this->database);
- $this->db_url_public = $this->database->getServiceDatabaseUrl();
- $this->dispatch('success', 'Database is now publicly accessible.');
- } else {
- StopDatabaseProxy::run($this->database);
- $this->db_url_public = null;
- $this->dispatch('success', 'Database is no longer publicly accessible.');
- }
- $this->submit();
- }
-
- public function refreshFileStorages()
- {
- $this->fileStorages = $this->database->fileStorages()->get();
- }
-
- public function submit()
- {
- try {
- $this->validate();
- $this->database->save();
- updateCompose($this->database);
- $this->dispatch('success', 'Database saved.');
- } catch (\Throwable) {
- } finally {
- $this->dispatch('generateDockerCompose');
- }
- }
-}
diff --git a/app/Livewire/Project/Service/EditCompose.php b/app/Livewire/Project/Service/EditCompose.php
deleted file mode 100644
index b5f2089415..0000000000
--- a/app/Livewire/Project/Service/EditCompose.php
+++ /dev/null
@@ -1,72 +0,0 @@
- 'envsUpdated',
- ];
-
- protected $rules = [
- 'service.docker_compose_raw' => 'required',
- 'service.docker_compose' => 'required',
- 'service.is_container_label_escape_enabled' => 'required',
- ];
-
- public function envsUpdated()
- {
- $this->dispatch('saveCompose', $this->service->docker_compose_raw);
- $this->refreshEnvs();
- }
-
- public function refreshEnvs()
- {
- $this->service = Service::ownedByCurrentTeam()->find($this->serviceId);
- }
-
- public function mount()
- {
- $this->service = Service::ownedByCurrentTeam()->find($this->serviceId);
- }
-
- public function validateCompose()
- {
- $isValid = validateComposeFile($this->service->docker_compose_raw, $this->service->server_id);
- if ($isValid !== 'OK') {
- $this->dispatch('error', "Invalid docker-compose file.\n$isValid");
- } else {
- $this->dispatch('success', 'Docker compose is valid.');
- }
- }
-
- public function saveEditedCompose()
- {
- $this->dispatch('info', 'Saving new docker compose...');
- $this->dispatch('saveCompose', $this->service->docker_compose_raw);
- $this->dispatch('refreshStorages');
- }
-
- public function instantSave()
- {
- $this->validate([
- 'service.is_container_label_escape_enabled' => 'required',
- ]);
- $this->service->save(['is_container_label_escape_enabled' => $this->service->is_container_label_escape_enabled]);
- $this->dispatch('success', 'Service updated successfully');
- }
-
- public function render()
- {
- return view('livewire.project.service.edit-compose');
- }
-}
diff --git a/app/Livewire/Project/Service/EditDomain.php b/app/Livewire/Project/Service/EditDomain.php
deleted file mode 100644
index fb1c052554..0000000000
--- a/app/Livewire/Project/Service/EditDomain.php
+++ /dev/null
@@ -1,65 +0,0 @@
- 'nullable',
- 'application.required_fqdn' => 'required|boolean',
- ];
-
- public function mount()
- {
- $this->application = ServiceApplication::find($this->applicationId);
- }
-
- public function submit()
- {
- try {
- $this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
- $this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim();
- $this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
- Url::fromString($domain, ['http', 'https']);
-
- return str($domain)->trim()->lower();
- });
- $this->application->fqdn = $this->application->fqdn->unique()->implode(',');
- $warning = sslipDomainWarning($this->application->fqdn);
- if ($warning) {
- $this->dispatch('warning', __('warning.sslipdomain'));
- }
- check_domain_usage(resource: $this->application);
- $this->validate();
- $this->application->save();
- updateCompose($this->application);
- if (str($this->application->fqdn)->contains(',')) {
- $this->dispatch('warning', 'Some services do not support multiple domains, which can lead to problems and is NOT RECOMMENDED. Only use multiple domains if you know what you are doing.');
- }
- $this->application->service->parse();
- $this->dispatch('refresh');
- $this->dispatch('configurationChanged');
- $this->dispatch('refreshStatus');
- } catch (\Throwable $e) {
- $originalFqdn = $this->application->getOriginal('fqdn');
- if ($originalFqdn !== $this->application->fqdn) {
- $this->application->fqdn = $originalFqdn;
- }
-
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.project.service.edit-domain');
- }
-}
diff --git a/app/Livewire/Project/Service/FileStorage.php b/app/Livewire/Project/Service/FileStorage.php
deleted file mode 100644
index 4d070bc0cc..0000000000
--- a/app/Livewire/Project/Service/FileStorage.php
+++ /dev/null
@@ -1,152 +0,0 @@
- 'required',
- 'fileStorage.fs_path' => 'required',
- 'fileStorage.mount_path' => 'required',
- 'fileStorage.content' => 'nullable',
- 'fileStorage.is_based_on_git' => 'required|boolean',
- ];
-
- public function mount()
- {
- $this->resource = $this->fileStorage->service;
- if (str($this->fileStorage->fs_path)->startsWith('.')) {
- $this->workdir = $this->resource->service?->workdir();
- $this->fs_path = str($this->fileStorage->fs_path)->after('.');
- } else {
- $this->workdir = null;
- $this->fs_path = $this->fileStorage->fs_path;
- }
- $this->fileStorage->loadStorageOnServer();
- }
-
- public function convertToDirectory()
- {
- try {
- $this->fileStorage->deleteStorageOnServer();
- $this->fileStorage->is_directory = true;
- $this->fileStorage->content = null;
- $this->fileStorage->is_based_on_git = false;
- $this->fileStorage->save();
- $this->fileStorage->saveStorageOnServer();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- $this->dispatch('refreshStorages');
- }
- }
-
- public function convertToFile()
- {
- try {
- $this->fileStorage->deleteStorageOnServer();
- $this->fileStorage->is_directory = false;
- $this->fileStorage->content = null;
- if (data_get($this->resource, 'settings.is_preserve_repository_enabled')) {
- $this->fileStorage->is_based_on_git = true;
- }
- $this->fileStorage->save();
- $this->fileStorage->saveStorageOnServer();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- $this->dispatch('refreshStorages');
- }
- }
-
- public function delete($password)
- {
- if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return;
- }
- }
-
- try {
- $message = 'File deleted.';
- if ($this->fileStorage->is_directory) {
- $message = 'Directory deleted.';
- }
- if ($this->permanently_delete) {
- $message = 'Directory deleted from the server.';
- $this->fileStorage->deleteStorageOnServer();
- }
- $this->fileStorage->delete();
- $this->dispatch('success', $message);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- $this->dispatch('refreshStorages');
- }
- }
-
- public function submit()
- {
- $original = $this->fileStorage->getOriginal();
- try {
- $this->validate();
- if ($this->fileStorage->is_directory) {
- $this->fileStorage->content = null;
- }
- $this->fileStorage->save();
- $this->fileStorage->saveStorageOnServer();
- $this->dispatch('success', 'File updated.');
- } catch (\Throwable $e) {
- $this->fileStorage->setRawAttributes($original);
- $this->fileStorage->save();
-
- return handleError($e, $this);
- }
- }
-
- public function instantSave()
- {
- $this->submit();
- }
-
- public function render()
- {
- return view('livewire.project.service.file-storage', [
- 'directoryDeletionCheckboxes' => [
- ['id' => 'permanently_delete', 'label' => 'The selected directory and all its contents will be permantely deleted form the server.'],
- ],
- 'fileDeletionCheckboxes' => [
- ['id' => 'permanently_delete', 'label' => 'The selected file will be permanently deleted form the server.'],
- ],
- ]);
- }
-}
diff --git a/app/Livewire/Project/Service/Index.php b/app/Livewire/Project/Service/Index.php
deleted file mode 100644
index ba4ebe2fca..0000000000
--- a/app/Livewire/Project/Service/Index.php
+++ /dev/null
@@ -1,62 +0,0 @@
-services = collect([]);
- $this->parameters = get_route_parameters();
- $this->query = request()->query();
- $this->service = Service::whereUuid($this->parameters['service_uuid'])->first();
- if (! $this->service) {
- return redirect()->route('dashboard');
- }
- $service = $this->service->applications()->whereUuid($this->parameters['stack_service_uuid'])->first();
- if ($service) {
- $this->serviceApplication = $service;
- $this->serviceApplication->getFilesFromServer();
- } else {
- $this->serviceDatabase = $this->service->databases()->whereUuid($this->parameters['stack_service_uuid'])->first();
- $this->serviceDatabase->getFilesFromServer();
- }
- $this->s3s = currentTeam()->s3s;
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function generateDockerCompose()
- {
- $this->service->parse();
- }
-
- public function render()
- {
- return view('livewire.project.service.index');
- }
-}
diff --git a/app/Livewire/Project/Service/Navbar.php b/app/Livewire/Project/Service/Navbar.php
deleted file mode 100644
index 5da425cbd1..0000000000
--- a/app/Livewire/Project/Service/Navbar.php
+++ /dev/null
@@ -1,154 +0,0 @@
-service->status)->contains('running') && is_null($this->service->config_hash)) {
- $this->service->isConfigurationChanged(true);
- $this->dispatch('configurationChanged');
- }
- }
-
- public function getListeners()
- {
- $userId = Auth::id();
-
- return [
- "echo-private:user.{$userId},ServiceStatusChanged" => 'serviceStarted',
- 'envsUpdated' => '$refresh',
- 'refreshStatus' => '$refresh',
- ];
- }
-
- public function serviceStarted()
- {
- // $this->dispatch('success', 'Service status changed.');
- if (is_null($this->service->config_hash) || $this->service->isConfigurationChanged()) {
- $this->service->isConfigurationChanged(true);
- $this->dispatch('configurationChanged');
- } else {
- $this->dispatch('configurationChanged');
- }
- }
-
- public function check_status_without_notification()
- {
- $this->dispatch('check_status');
- }
-
- public function check_status()
- {
- $this->dispatch('check_status');
- $this->dispatch('success', 'Service status updated.');
- }
-
- public function checkDeployments()
- {
- try {
- $activity = Activity::where('properties->type_uuid', $this->service->uuid)->latest()->first();
- $status = data_get($activity, 'properties.status');
- if ($status === ProcessStatus::QUEUED->value || $status === ProcessStatus::IN_PROGRESS->value) {
- $this->isDeploymentProgress = true;
- } else {
- $this->isDeploymentProgress = false;
- }
- } catch (\Throwable) {
- $this->isDeploymentProgress = false;
- }
-
- return $this->isDeploymentProgress;
- }
-
- public function start()
- {
- $activity = StartService::run($this->service, pullLatestImages: true);
- $this->dispatch('activityMonitor', $activity->id);
- }
-
- public function forceDeploy()
- {
- try {
- $activities = Activity::where('properties->type_uuid', $this->service->uuid)->where('properties->status', ProcessStatus::IN_PROGRESS->value)->orWhere('properties->status', ProcessStatus::QUEUED->value)->get();
- foreach ($activities as $activity) {
- $activity->properties->status = ProcessStatus::ERROR->value;
- $activity->save();
- }
- $activity = StartService::run($this->service, pullLatestImages: true, stopBeforeStart: true);
- $this->dispatch('activityMonitor', $activity->id);
- } catch (\Exception $e) {
- $this->dispatch('error', $e->getMessage());
- }
- }
-
- public function stop($cleanupContainers = false)
- {
- try {
- StopService::run($this->service, false, $this->docker_cleanup);
- ServiceStatusChanged::dispatch();
- if ($cleanupContainers) {
- $this->dispatch('success', 'Containers cleaned up.');
- } else {
- $this->dispatch('success', 'Service stopped.');
- }
- } catch (\Exception $e) {
- $this->dispatch('error', $e->getMessage());
- }
- }
-
- public function restart()
- {
- $this->checkDeployments();
- if ($this->isDeploymentProgress) {
- $this->dispatch('error', 'There is a deployment in progress.');
-
- return;
- }
- $activity = StartService::run($this->service, stopBeforeStart: true);
- $this->dispatch('activityMonitor', $activity->id);
- }
-
- public function pullAndRestartEvent()
- {
- $this->checkDeployments();
- if ($this->isDeploymentProgress) {
- $this->dispatch('error', 'There is a deployment in progress.');
-
- return;
- }
- $activity = StartService::run($this->service, pullLatestImages: true, stopBeforeStart: true);
- $this->dispatch('activityMonitor', $activity->id);
- }
-
- public function render()
- {
- return view('livewire.project.service.navbar', [
- 'checkboxes' => [
- ['id' => 'docker_cleanup', 'label' => __('resource.docker_cleanup')],
- ],
- ]);
- }
-}
diff --git a/app/Livewire/Project/Service/ServiceApplicationView.php b/app/Livewire/Project/Service/ServiceApplicationView.php
deleted file mode 100644
index 8324ee645c..0000000000
--- a/app/Livewire/Project/Service/ServiceApplicationView.php
+++ /dev/null
@@ -1,123 +0,0 @@
- 'nullable',
- 'application.description' => 'nullable',
- 'application.fqdn' => 'nullable',
- 'application.image' => 'required',
- 'application.exclude_from_status' => 'required|boolean',
- 'application.required_fqdn' => 'required|boolean',
- 'application.is_log_drain_enabled' => 'nullable|boolean',
- 'application.is_gzip_enabled' => 'nullable|boolean',
- 'application.is_stripprefix_enabled' => 'nullable|boolean',
- ];
-
- public function instantSave()
- {
- $this->submit();
- }
-
- public function instantSaveAdvanced()
- {
- if (! $this->application->service->destination->server->isLogDrainEnabled()) {
- $this->application->is_log_drain_enabled = false;
- $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
-
- return;
- }
- $this->application->save();
- $this->dispatch('success', 'You need to restart the service for the changes to take effect.');
- }
-
- public function delete($password)
- {
- if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return;
- }
- }
-
- try {
- $this->application->delete();
- $this->dispatch('success', 'Application deleted.');
-
- return redirect()->route('project.service.configuration', $this->parameters);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function mount()
- {
- $this->parameters = get_route_parameters();
- }
-
- public function submit()
- {
- try {
- $this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
- $this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim();
- $this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
- Url::fromString($domain, ['http', 'https']);
-
- return str($domain)->trim()->lower();
- });
- $this->application->fqdn = $this->application->fqdn->unique()->implode(',');
- $warning = sslipDomainWarning($this->application->fqdn);
- if ($warning) {
- $this->dispatch('warning', __('warning.sslipdomain'));
- }
- check_domain_usage(resource: $this->application);
- $this->validate();
- $this->application->save();
- updateCompose($this->application);
- if (str($this->application->fqdn)->contains(',')) {
- $this->dispatch('warning', 'Some services do not support multiple domains, which can lead to problems and is NOT RECOMMENDED. Only use multiple domains if you know what you are doing.');
- } else {
- ! $warning && $this->dispatch('success', 'Service saved.');
- }
- $this->dispatch('generateDockerCompose');
- } catch (\Throwable $e) {
- $originalFqdn = $this->application->getOriginal('fqdn');
- if ($originalFqdn !== $this->application->fqdn) {
- $this->application->fqdn = $originalFqdn;
- }
-
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.project.service.service-application-view', [
- 'checkboxes' => [
- ['id' => 'delete_volumes', 'label' => __('resource.delete_volumes')],
- ['id' => 'docker_cleanup', 'label' => __('resource.docker_cleanup')],
- // ['id' => 'delete_associated_backups_locally', 'label' => 'All backups associated with this Ressource will be permanently deleted from local storage.'],
- // ['id' => 'delete_associated_backups_s3', 'label' => 'All backups associated with this Ressource will be permanently deleted from the selected S3 Storage.'],
- // ['id' => 'delete_associated_backups_sftp', 'label' => 'All backups associated with this Ressource will be permanently deleted from the selected SFTP Storage.']
- ],
- ]);
- }
-}
diff --git a/app/Livewire/Project/Service/StackForm.php b/app/Livewire/Project/Service/StackForm.php
deleted file mode 100644
index 3685984660..0000000000
--- a/app/Livewire/Project/Service/StackForm.php
+++ /dev/null
@@ -1,101 +0,0 @@
- 'required',
- 'service.docker_compose' => 'required',
- 'service.name' => 'required',
- 'service.description' => 'nullable',
- 'service.connect_to_docker_network' => 'nullable',
- ];
-
- public $validationAttributes = [];
-
- public function mount()
- {
- $this->fields = collect([]);
- $extraFields = $this->service->extraFields();
- foreach ($extraFields as $serviceName => $fields) {
- foreach ($fields as $fieldKey => $field) {
- $key = data_get($field, 'key');
- $value = data_get($field, 'value');
- $rules = data_get($field, 'rules', 'nullable');
- $isPassword = data_get($field, 'isPassword', false);
- $customHelper = data_get($field, 'customHelper', false);
- $this->fields->put($key, [
- 'serviceName' => $serviceName,
- 'key' => $key,
- 'name' => $fieldKey,
- 'value' => $value,
- 'isPassword' => $isPassword,
- 'rules' => $rules,
- 'customHelper' => $customHelper,
- ]);
-
- $this->rules["fields.$key.value"] = $rules;
- $this->validationAttributes["fields.$key.value"] = $fieldKey;
- }
- }
- $this->fields = $this->fields->groupBy('serviceName')->map(function ($group) {
- return $group->sortBy(function ($field) {
- return data_get($field, 'isPassword') ? 1 : 0;
- })->mapWithKeys(function ($field) {
- return [$field['key'] => $field];
- });
- })->flatMap(function ($group) {
- return $group;
- });
- }
-
- public function saveCompose($raw)
- {
- $this->service->docker_compose_raw = $raw;
- $this->submit(notify: true);
- }
-
- public function instantSave()
- {
- $this->service->save();
- $this->dispatch('success', 'Service settings saved.');
- }
-
- public function submit($notify = true)
- {
- try {
- $this->validate();
- $this->service->save();
- $this->service->saveExtraFields($this->fields);
- $this->service->parse();
- $this->service->refresh();
- $this->service->saveComposeConfigs();
- $this->dispatch('refreshEnvs');
- $notify && $this->dispatch('success', 'Service saved.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- if (is_null($this->service->config_hash)) {
- $this->service->isConfigurationChanged(true);
- } else {
- $this->dispatch('configurationChanged');
- }
- }
- }
-
- public function render()
- {
- return view('livewire.project.service.stack-form');
- }
-}
diff --git a/app/Livewire/Project/Service/Storage.php b/app/Livewire/Project/Service/Storage.php
deleted file mode 100644
index 4b64a8b5ef..0000000000
--- a/app/Livewire/Project/Service/Storage.php
+++ /dev/null
@@ -1,65 +0,0 @@
-user()->currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},FileStorageChanged" => 'refreshStoragesFromEvent',
- 'refreshStorages',
- 'addNewVolume',
- ];
- }
-
- public function mount()
- {
- $this->refreshStorages();
- }
-
- public function refreshStoragesFromEvent()
- {
- $this->refreshStorages();
- $this->dispatch('warning', 'File storage changed. Usually it means that the file / directory is already defined on the server, so Coolify set it up for you properly on the UI.');
- }
-
- public function refreshStorages()
- {
- $this->fileStorage = $this->resource->fileStorages()->get();
- $this->dispatch('$refresh');
- }
-
- public function addNewVolume($data)
- {
- try {
- LocalPersistentVolume::create([
- 'name' => $data['name'],
- 'mount_path' => $data['mount_path'],
- 'host_path' => $data['host_path'],
- 'resource_id' => $this->resource->id,
- 'resource_type' => $this->resource->getMorphClass(),
- ]);
- $this->resource->refresh();
- $this->dispatch('success', 'Storage added successfully');
- $this->dispatch('clearAddStorage');
- $this->dispatch('refreshStorages');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.project.service.storage');
- }
-}
diff --git a/app/Livewire/Project/Shared/ConfigurationChecker.php b/app/Livewire/Project/Shared/ConfigurationChecker.php
deleted file mode 100644
index ab9f3785df..0000000000
--- a/app/Livewire/Project/Shared/ConfigurationChecker.php
+++ /dev/null
@@ -1,39 +0,0 @@
-configurationChanged();
- }
-
- public function render()
- {
- return view('livewire.project.shared.configuration-checker');
- }
-
- public function configurationChanged()
- {
- $this->isConfigurationChanged = $this->resource->isConfigurationChanged();
- }
-}
diff --git a/app/Livewire/Project/Shared/Danger.php b/app/Livewire/Project/Shared/Danger.php
deleted file mode 100644
index 7da48f9fb4..0000000000
--- a/app/Livewire/Project/Shared/Danger.php
+++ /dev/null
@@ -1,131 +0,0 @@
-modalId = new Cuid2;
- $this->projectUuid = data_get($parameters, 'project_uuid');
- $this->environmentUuid = data_get($parameters, 'environment_uuid');
-
- if ($this->resource === null) {
- if (isset($parameters['service_uuid'])) {
- $this->resource = Service::where('uuid', $parameters['service_uuid'])->first();
- } elseif (isset($parameters['stack_service_uuid'])) {
- $this->resource = ServiceApplication::where('uuid', $parameters['stack_service_uuid'])->first()
- ?? ServiceDatabase::where('uuid', $parameters['stack_service_uuid'])->first();
- }
- }
-
- if ($this->resource === null) {
- $this->resourceName = 'Unknown Resource';
-
- return;
- }
-
- if (! method_exists($this->resource, 'type')) {
- $this->resourceName = 'Unknown Resource';
-
- return;
- }
-
- $this->resourceName = match ($this->resource->type()) {
- 'application' => $this->resource->name ?? 'Application',
- 'standalone-postgresql',
- 'standalone-redis',
- 'standalone-mongodb',
- 'standalone-mysql',
- 'standalone-mariadb',
- 'standalone-keydb',
- 'standalone-dragonfly',
- 'standalone-clickhouse' => $this->resource->name ?? 'Database',
- 'service' => $this->resource->name ?? 'Service',
- 'service-application' => $this->resource->name ?? 'Service Application',
- 'service-database' => $this->resource->name ?? 'Service Database',
- default => 'Unknown Resource',
- };
- }
-
- public function delete($password)
- {
- if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return;
- }
- }
-
- if (! $this->resource) {
- $this->addError('resource', 'Resource not found.');
-
- return;
- }
-
- try {
- $this->resource->delete();
- DeleteResourceJob::dispatch(
- $this->resource,
- $this->delete_configurations,
- $this->delete_volumes,
- $this->docker_cleanup,
- $this->delete_connected_networks
- );
-
- return redirect()->route('project.resource.index', [
- 'project_uuid' => $this->projectUuid,
- 'environment_uuid' => $this->environmentUuid,
- ]);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.project.shared.danger', [
- 'checkboxes' => [
- ['id' => 'delete_volumes', 'label' => __('resource.delete_volumes')],
- ['id' => 'delete_connected_networks', 'label' => __('resource.delete_connected_networks')],
- ['id' => 'delete_configurations', 'label' => __('resource.delete_configurations')],
- ['id' => 'docker_cleanup', 'label' => __('resource.docker_cleanup')],
- // ['id' => 'delete_associated_backups_locally', 'label' => 'All backups associated with this Ressource will be permanently deleted from local storage.'],
- // ['id' => 'delete_associated_backups_s3', 'label' => 'All backups associated with this Ressource will be permanently deleted from the selected S3 Storage.'],
- // ['id' => 'delete_associated_backups_sftp', 'label' => 'All backups associated with this Ressource will be permanently deleted from the selected SFTP Storage.']
- ],
- ]);
- }
-}
diff --git a/app/Livewire/Project/Shared/Destination.php b/app/Livewire/Project/Shared/Destination.php
deleted file mode 100644
index 1759fe08ac..0000000000
--- a/app/Livewire/Project/Shared/Destination.php
+++ /dev/null
@@ -1,155 +0,0 @@
-user()->currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},ApplicationStatusChanged" => 'loadData',
- ];
- }
-
- public function mount()
- {
- $this->networks = collect([]);
- $this->loadData();
- }
-
- public function loadData()
- {
- $all_networks = collect([]);
- $all_networks = $all_networks->push($this->resource->destination);
- $all_networks = $all_networks->merge($this->resource->additional_networks);
-
- $this->networks = Server::isUsable()->get()->map(function ($server) {
- return $server->standaloneDockers;
- })->flatten();
- $this->networks = $this->networks->reject(function ($network) use ($all_networks) {
- return $all_networks->pluck('id')->contains($network->id);
- });
- $this->networks = $this->networks->reject(function ($network) {
- return $this->resource->destination->server->id == $network->server->id;
- });
- if ($this->resource?->additional_servers?->count() > 0) {
- $this->networks = $this->networks->reject(function ($network) {
- return $this->resource->additional_servers->pluck('id')->contains($network->server->id);
- });
- }
- }
-
- public function stop($serverId)
- {
- try {
- $server = Server::ownedByCurrentTeam()->findOrFail($serverId);
- StopApplicationOneServer::run($this->resource, $server);
- $this->refreshServers();
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function redeploy(int $network_id, int $server_id)
- {
- try {
- if ($this->resource->additional_servers->count() > 0 && str($this->resource->docker_registry_image_name)->isEmpty()) {
- $this->dispatch('error', 'Failed to deploy.', 'Before deploying to multiple servers, you must first set a Docker image in the General tab. More information here: documentation ');
-
- return;
- }
- $deployment_uuid = new Cuid2;
- $server = Server::ownedByCurrentTeam()->findOrFail($server_id);
- $destination = $server->standaloneDockers->where('id', $network_id)->firstOrFail();
- queue_application_deployment(
- deployment_uuid: $deployment_uuid,
- application: $this->resource,
- server: $server,
- destination: $destination,
- only_this_server: true,
- no_questions_asked: true,
- );
-
- return redirect()->route('project.application.deployment.show', [
- 'project_uuid' => data_get($this->resource, 'environment.project.uuid'),
- 'application_uuid' => data_get($this->resource, 'uuid'),
- 'deployment_uuid' => $deployment_uuid,
- 'environment_uuid' => data_get($this->resource, 'environment.uuid'),
- ]);
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function promote(int $network_id, int $server_id)
- {
- $main_destination = $this->resource->destination;
- $this->resource->update([
- 'destination_id' => $network_id,
- 'destination_type' => StandaloneDocker::class,
- ]);
- $this->resource->additional_networks()->detach($network_id, ['server_id' => $server_id]);
- $this->resource->additional_networks()->attach($main_destination->id, ['server_id' => $main_destination->server->id]);
- $this->refreshServers();
- }
-
- public function refreshServers()
- {
- GetContainersStatus::run($this->resource->destination->server);
- // ContainerStatusJob::dispatchSync($this->resource->destination->server);
- $this->loadData();
- $this->dispatch('refresh');
- ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
- }
-
- public function addServer(int $network_id, int $server_id)
- {
- $this->resource->additional_networks()->attach($network_id, ['server_id' => $server_id]);
- $this->loadData();
- ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
- }
-
- public function removeServer(int $network_id, int $server_id, $password)
- {
- try {
- if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return;
- }
- }
-
- if ($this->resource->destination->server->id == $server_id && $this->resource->destination->id == $network_id) {
- $this->dispatch('error', 'You cannot remove this destination server.', 'You are trying to remove the main server.');
-
- return;
- }
- $server = Server::ownedByCurrentTeam()->findOrFail($server_id);
- StopApplicationOneServer::run($this->resource, $server);
- $this->resource->additional_networks()->detach($network_id, ['server_id' => $server_id]);
- $this->loadData();
- ApplicationStatusChanged::dispatch(data_get($this->resource, 'environment.project.team.id'));
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Add.php b/app/Livewire/Project/Shared/EnvironmentVariable/Add.php
deleted file mode 100644
index 0dbf0f957f..0000000000
--- a/app/Livewire/Project/Shared/EnvironmentVariable/Add.php
+++ /dev/null
@@ -1,70 +0,0 @@
- 'clear'];
-
- protected $rules = [
- 'key' => 'required|string',
- 'value' => 'nullable',
- 'is_build_time' => 'required|boolean',
- 'is_multiline' => 'required|boolean',
- 'is_literal' => 'required|boolean',
- ];
-
- protected $validationAttributes = [
- 'key' => 'key',
- 'value' => 'value',
- 'is_build_time' => 'build',
- 'is_multiline' => 'multiline',
- 'is_literal' => 'literal',
- ];
-
- public function mount()
- {
- $this->parameters = get_route_parameters();
- }
-
- public function submit()
- {
- $this->validate();
- $this->dispatch('saveKey', [
- 'key' => $this->key,
- 'value' => $this->value,
- 'is_build_time' => $this->is_build_time,
- 'is_multiline' => $this->is_multiline,
- 'is_literal' => $this->is_literal,
- 'is_preview' => $this->is_preview,
- ]);
- $this->clear();
- }
-
- public function clear()
- {
- $this->key = '';
- $this->value = '';
- $this->is_build_time = false;
- $this->is_multiline = false;
- $this->is_literal = false;
- }
-}
diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/All.php b/app/Livewire/Project/Shared/EnvironmentVariable/All.php
deleted file mode 100644
index 35e585c82e..0000000000
--- a/app/Livewire/Project/Shared/EnvironmentVariable/All.php
+++ /dev/null
@@ -1,225 +0,0 @@
- 'submit',
- 'refreshEnvs',
- 'environmentVariableDeleted' => 'refreshEnvs',
- ];
-
- public function mount()
- {
- $this->is_env_sorting_enabled = data_get($this->resource, 'settings.is_env_sorting_enabled', false);
- $this->resourceClass = get_class($this->resource);
- $resourceWithPreviews = [\App\Models\Application::class];
- $simpleDockerfile = filled(data_get($this->resource, 'dockerfile'));
- if (str($this->resourceClass)->contains($resourceWithPreviews) && ! $simpleDockerfile) {
- $this->showPreview = true;
- }
- $this->sortEnvironmentVariables();
- }
-
- public function instantSave()
- {
- $this->resource->settings->is_env_sorting_enabled = $this->is_env_sorting_enabled;
- $this->resource->settings->save();
- $this->sortEnvironmentVariables();
- $this->dispatch('success', 'Environment variable settings updated.');
- }
-
- public function sortEnvironmentVariables()
- {
- if ($this->is_env_sorting_enabled === false) {
- if ($this->resource->environment_variables) {
- $this->resource->environment_variables = $this->resource->environment_variables->sortBy('order')->values();
- }
-
- if ($this->resource->environment_variables_preview) {
- $this->resource->environment_variables_preview = $this->resource->environment_variables_preview->sortBy('order')->values();
- }
- }
-
- $this->getDevView();
- }
-
- public function getDevView()
- {
- $this->variables = $this->formatEnvironmentVariables($this->resource->environment_variables);
- if ($this->showPreview) {
- $this->variablesPreview = $this->formatEnvironmentVariables($this->resource->environment_variables_preview);
- }
- }
-
- private function formatEnvironmentVariables($variables)
- {
- return $variables->map(function ($item) {
- if ($item->is_shown_once) {
- return "$item->key=(Locked Secret, delete and add again to change)";
- }
- if ($item->is_multiline) {
- return "$item->key=(Multiline environment variable, edit in normal view)";
- }
-
- return "$item->key=$item->value";
- })->join("\n");
- }
-
- public function switch()
- {
- $this->view = $this->view === 'normal' ? 'dev' : 'normal';
- $this->sortEnvironmentVariables();
- }
-
- public function submit($data = null)
- {
- try {
- if ($data === null) {
- $this->handleBulkSubmit();
- } else {
- $this->handleSingleSubmit($data);
- }
-
- $this->updateOrder();
- $this->sortEnvironmentVariables();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- $this->refreshEnvs();
- }
- }
-
- private function updateOrder()
- {
- $variables = parseEnvFormatToArray($this->variables);
- $order = 1;
- foreach ($variables as $key => $value) {
- $env = $this->resource->environment_variables()->where('key', $key)->first();
- if ($env) {
- $env->order = $order;
- $env->save();
- }
- $order++;
- }
-
- if ($this->showPreview) {
- $previewVariables = parseEnvFormatToArray($this->variablesPreview);
- $order = 1;
- foreach ($previewVariables as $key => $value) {
- $env = $this->resource->environment_variables_preview()->where('key', $key)->first();
- if ($env) {
- $env->order = $order;
- $env->save();
- }
- $order++;
- }
- }
- }
-
- private function handleBulkSubmit()
- {
- $variables = parseEnvFormatToArray($this->variables);
-
- $this->deleteRemovedVariables(false, $variables);
- $this->updateOrCreateVariables(false, $variables);
-
- if ($this->showPreview) {
- $previewVariables = parseEnvFormatToArray($this->variablesPreview);
- $this->deleteRemovedVariables(true, $previewVariables);
- $this->updateOrCreateVariables(true, $previewVariables);
- }
-
- $this->dispatch('success', 'Environment variables updated.');
- }
-
- private function handleSingleSubmit($data)
- {
- $found = $this->resource->environment_variables()->where('key', $data['key'])->first();
- if ($found) {
- $this->dispatch('error', 'Environment variable already exists.');
-
- return;
- }
-
- $maxOrder = $this->resource->environment_variables()->max('order') ?? 0;
- $environment = $this->createEnvironmentVariable($data);
- $environment->order = $maxOrder + 1;
- $environment->save();
- }
-
- private function createEnvironmentVariable($data)
- {
- $environment = new EnvironmentVariable;
- $environment->key = $data['key'];
- $environment->value = $data['value'];
- $environment->is_build_time = $data['is_build_time'] ?? false;
- $environment->is_multiline = $data['is_multiline'] ?? false;
- $environment->is_literal = $data['is_literal'] ?? false;
- $environment->is_preview = $data['is_preview'] ?? false;
- $environment->resourceable_id = $this->resource->id;
- $environment->resourceable_type = $this->resource->getMorphClass();
-
- return $environment;
- }
-
- private function deleteRemovedVariables($isPreview, $variables)
- {
- $method = $isPreview ? 'environment_variables_preview' : 'environment_variables';
- $this->resource->$method()->whereNotIn('key', array_keys($variables))->delete();
- }
-
- private function updateOrCreateVariables($isPreview, $variables)
- {
- foreach ($variables as $key => $value) {
- if (str($key)->startsWith('SERVICE_FQDN') || str($key)->startsWith('SERVICE_URL')) {
- continue;
- }
- $method = $isPreview ? 'environment_variables_preview' : 'environment_variables';
- $found = $this->resource->$method()->where('key', $key)->first();
-
- if ($found) {
- if (! $found->is_shown_once && ! $found->is_multiline) {
- $found->value = $value;
- $found->save();
- }
- } else {
- $environment = new EnvironmentVariable;
- $environment->key = $key;
- $environment->value = $value;
- $environment->is_build_time = false;
- $environment->is_multiline = false;
- $environment->is_preview = $isPreview;
- $environment->resourceable_id = $this->resource->id;
- $environment->resourceable_type = $this->resource->getMorphClass();
-
- $environment->save();
- }
- }
- }
-
- public function refreshEnvs()
- {
- $this->resource->refresh();
- $this->sortEnvironmentVariables();
- $this->getDevView();
- }
-}
diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php
deleted file mode 100644
index 3a7d0faa57..0000000000
--- a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php
+++ /dev/null
@@ -1,181 +0,0 @@
- 'refresh',
- 'refresh',
- 'compose_loaded' => '$refresh',
- ];
-
- protected $rules = [
- 'key' => 'required|string',
- 'value' => 'nullable',
- 'is_build_time' => 'required|boolean',
- 'is_multiline' => 'required|boolean',
- 'is_literal' => 'required|boolean',
- 'is_shown_once' => 'required|boolean',
- 'real_value' => 'nullable',
- 'is_required' => 'required|boolean',
- ];
-
- public function mount()
- {
- $this->syncData();
- if ($this->env->getMorphClass() === \App\Models\SharedEnvironmentVariable::class) {
- $this->isSharedVariable = true;
- }
- $this->parameters = get_route_parameters();
- $this->checkEnvs();
-
- }
-
- public function refresh()
- {
- $this->syncData();
- $this->checkEnvs();
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- if ($this->isSharedVariable) {
- $this->validate([
- 'key' => 'required|string',
- 'value' => 'nullable',
- 'is_multiline' => 'required|boolean',
- 'is_literal' => 'required|boolean',
- 'is_shown_once' => 'required|boolean',
- 'real_value' => 'nullable',
- ]);
- } else {
- $this->validate();
- $this->env->is_build_time = $this->is_build_time;
- $this->env->is_required = $this->is_required;
- $this->env->is_shared = $this->is_shared;
- }
- $this->env->key = $this->key;
- $this->env->value = $this->value;
- $this->env->is_multiline = $this->is_multiline;
- $this->env->is_literal = $this->is_literal;
- $this->env->is_shown_once = $this->is_shown_once;
- $this->env->save();
- } else {
- $this->key = $this->env->key;
- $this->value = $this->env->value;
- $this->is_build_time = $this->env->is_build_time ?? false;
- $this->is_multiline = $this->env->is_multiline;
- $this->is_literal = $this->env->is_literal;
- $this->is_shown_once = $this->env->is_shown_once;
- $this->is_required = $this->env->is_required ?? false;
- $this->is_really_required = $this->env->is_really_required ?? false;
- $this->is_shared = $this->env->is_shared ?? false;
- $this->real_value = $this->env->real_value;
- }
- }
-
- public function checkEnvs()
- {
- $this->isDisabled = false;
- if (str($this->env->key)->startsWith('SERVICE_FQDN') || str($this->env->key)->startsWith('SERVICE_URL')) {
- $this->isDisabled = true;
- }
- if ($this->env->is_shown_once) {
- $this->isLocked = true;
- }
- }
-
- public function serialize()
- {
- data_forget($this->env, 'real_value');
- if ($this->env->getMorphClass() === \App\Models\SharedEnvironmentVariable::class) {
- data_forget($this->env, 'is_build_time');
- }
- }
-
- public function lock()
- {
- $this->env->is_shown_once = true;
- if ($this->isSharedVariable) {
- unset($this->env->is_required);
- }
- $this->serialize();
- $this->env->save();
- $this->checkEnvs();
- $this->dispatch('refreshEnvs');
- }
-
- public function instantSave()
- {
- $this->submit();
- }
-
- public function submit()
- {
- try {
- if (! $this->isSharedVariable && $this->is_required && str($this->value)->isEmpty()) {
- $oldValue = $this->env->getOriginal('value');
- $this->value = $oldValue;
- $this->dispatch('error', 'Required environment variables cannot be empty.');
-
- return;
- }
-
- $this->serialize();
- $this->syncData(true);
- $this->dispatch('success', 'Environment variable updated.');
- $this->dispatch('envsUpdated');
- } catch (\Exception $e) {
- return handleError($e);
- }
- }
-
- public function delete()
- {
- try {
- $this->env->delete();
- $this->dispatch('environmentVariableDeleted');
- $this->dispatch('success', 'Environment variable deleted successfully.');
- } catch (\Exception $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Livewire/Project/Shared/ExecuteContainerCommand.php b/app/Livewire/Project/Shared/ExecuteContainerCommand.php
deleted file mode 100644
index 98289c5365..0000000000
--- a/app/Livewire/Project/Shared/ExecuteContainerCommand.php
+++ /dev/null
@@ -1,242 +0,0 @@
- 'required',
- 'container' => 'required',
- 'command' => 'required',
- ];
-
- public function mount()
- {
- if (! auth()->user()->isAdmin()) {
- abort(403);
- }
- $this->parameters = get_route_parameters();
- $this->containers = collect();
- $this->servers = collect();
- if (data_get($this->parameters, 'application_uuid')) {
- $this->type = 'application';
- $this->resource = Application::where('uuid', $this->parameters['application_uuid'])->firstOrFail();
- if ($this->resource->destination->server->isFunctional()) {
- $this->servers = $this->servers->push($this->resource->destination->server);
- }
- foreach ($this->resource->additional_servers as $server) {
- if ($server->isFunctional()) {
- $this->servers = $this->servers->push($server);
- }
- }
- $this->loadContainers();
- } elseif (data_get($this->parameters, 'database_uuid')) {
- $this->type = 'database';
- $resource = getResourceByUuid($this->parameters['database_uuid'], data_get(auth()->user()->currentTeam(), 'id'));
- if (is_null($resource)) {
- abort(404);
- }
- $this->resource = $resource;
- if ($this->resource->destination->server->isFunctional()) {
- $this->servers = $this->servers->push($this->resource->destination->server);
- }
- $this->loadContainers();
- } elseif (data_get($this->parameters, 'service_uuid')) {
- $this->type = 'service';
- $this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
- if ($this->resource->server->isFunctional()) {
- $this->servers = $this->servers->push($this->resource->server);
- }
- $this->loadContainers();
- } elseif (data_get($this->parameters, 'server_uuid')) {
- $this->type = 'server';
- $this->resource = Server::where('uuid', $this->parameters['server_uuid'])->firstOrFail();
- $this->server = $this->resource;
- }
- }
-
- public function loadContainers()
- {
- foreach ($this->servers as $server) {
- if (data_get($this->parameters, 'application_uuid')) {
- if ($server->isSwarm()) {
- $containers = collect([
- [
- 'Names' => $this->resource->uuid.'_'.$this->resource->uuid,
- ],
- ]);
- } else {
- $containers = getCurrentApplicationContainerStatus($server, $this->resource->id, includePullrequests: true);
- }
- foreach ($containers as $container) {
- // if container state is running
- if (data_get($container, 'State') === 'running') {
- $payload = [
- 'server' => $server,
- 'container' => $container,
- ];
- $this->containers = $this->containers->push($payload);
- }
- }
- } elseif (data_get($this->parameters, 'database_uuid')) {
- if ($this->resource->isRunning()) {
- $this->containers = $this->containers->push([
- 'server' => $server,
- 'container' => [
- 'Names' => $this->resource->uuid,
- ],
- ]);
- }
- } elseif (data_get($this->parameters, 'service_uuid')) {
- $this->resource->applications()->get()->each(function ($application) {
- if ($application->isRunning()) {
- $this->containers->push([
- 'server' => $this->resource->server,
- 'container' => [
- 'Names' => data_get($application, 'name').'-'.data_get($this->resource, 'uuid'),
- ],
- ]);
- }
- });
- $this->resource->databases()->get()->each(function ($database) {
- if ($database->isRunning()) {
- $this->containers->push([
- 'server' => $this->resource->server,
- 'container' => [
- 'Names' => data_get($database, 'name').'-'.data_get($this->resource, 'uuid'),
- ],
- ]);
- }
- });
- }
- }
- if ($this->containers->count() > 0) {
- $this->container = $this->containers->first();
- }
- if ($this->containers->count() === 1) {
- $this->selected_container = data_get($this->containers->first(), 'container.Names');
- }
- }
-
- private function checkShellAvailability(Server $server, string $container): bool
- {
- $escapedContainer = escapeshellarg($container);
- try {
- instant_remote_process([
- "docker exec {$escapedContainer} bash -c 'exit 0' 2>/dev/null || ".
- "docker exec {$escapedContainer} sh -c 'exit 0' 2>/dev/null",
- ], $server);
-
- return true;
- } catch (\Throwable) {
- return false;
- }
- }
-
- #[On('connectToServer')]
- public function connectToServer()
- {
- try {
- if ($this->server->isForceDisabled()) {
- throw new \RuntimeException('Server is disabled.');
- }
- $this->hasShell = true;
- $this->dispatch(
- 'send-terminal-command',
- false,
- data_get($this->server, 'name'),
- data_get($this->server, 'uuid')
- );
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- #[On('connectToContainer')]
- public function connectToContainer()
- {
- if ($this->selected_container === 'default') {
- $this->dispatch('error', 'Please select a container.');
-
- return;
- }
- try {
- // Validate container name format
- if (! preg_match('/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/', $this->selected_container)) {
- throw new \InvalidArgumentException('Invalid container name format');
- }
-
- // Verify container exists in our allowed list
- $container = collect($this->containers)->firstWhere('container.Names', $this->selected_container);
- if (is_null($container)) {
- throw new \RuntimeException('Container not found.');
- }
-
- // Verify server ownership and status
- $server = data_get($container, 'server');
- if (! $server || ! $server instanceof Server) {
- throw new \RuntimeException('Invalid server configuration.');
- }
-
- if ($server->isForceDisabled()) {
- throw new \RuntimeException('Server is disabled.');
- }
-
- // Additional ownership verification based on resource type
- $resourceServer = match ($this->type) {
- 'application' => $this->resource->destination->server,
- 'database' => $this->resource->destination->server,
- 'service' => $this->resource->server,
- default => throw new \RuntimeException('Invalid resource type.')
- };
-
- if ($server->id !== $resourceServer->id && ! $this->resource->additional_servers->contains('id', $server->id)) {
- throw new \RuntimeException('Server ownership verification failed.');
- }
-
- $this->hasShell = $this->checkShellAvailability($server, data_get($container, 'container.Names'));
- if (! $this->hasShell) {
- return;
- }
-
- $this->dispatch(
- 'send-terminal-command',
- true,
- data_get($container, 'container.Names'),
- data_get($container, 'server.uuid')
- );
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.project.shared.execute-container-command');
- }
-}
diff --git a/app/Livewire/Project/Shared/GetLogs.php b/app/Livewire/Project/Shared/GetLogs.php
deleted file mode 100644
index 43fd97c341..0000000000
--- a/app/Livewire/Project/Shared/GetLogs.php
+++ /dev/null
@@ -1,159 +0,0 @@
-resource)) {
- if ($this->resource->getMorphClass() === \App\Models\Application::class) {
- $this->showTimeStamps = $this->resource->settings->is_include_timestamps;
- } else {
- if ($this->servicesubtype) {
- $this->showTimeStamps = $this->servicesubtype->is_include_timestamps;
- } else {
- $this->showTimeStamps = $this->resource->is_include_timestamps;
- }
- }
- if ($this->resource?->getMorphClass() === \App\Models\Application::class) {
- if (str($this->container)->contains('-pr-')) {
- $this->pull_request = 'Pull Request: '.str($this->container)->afterLast('-pr-')->beforeLast('_')->value();
- }
- }
- }
- }
-
- public function doSomethingWithThisChunkOfOutput($output)
- {
- $this->outputs .= removeAnsiColors($output);
- }
-
- public function instantSave()
- {
- if (! is_null($this->resource)) {
- if ($this->resource->getMorphClass() === \App\Models\Application::class) {
- $this->resource->settings->is_include_timestamps = $this->showTimeStamps;
- $this->resource->settings->save();
- }
- if ($this->resource->getMorphClass() === \App\Models\Service::class) {
- $serviceName = str($this->container)->beforeLast('-')->value();
- $subType = $this->resource->applications()->where('name', $serviceName)->first();
- if ($subType) {
- $subType->is_include_timestamps = $this->showTimeStamps;
- $subType->save();
- } else {
- $subType = $this->resource->databases()->where('name', $serviceName)->first();
- if ($subType) {
- $subType->is_include_timestamps = $this->showTimeStamps;
- $subType->save();
- }
- }
- }
- }
- }
-
- public function getLogs($refresh = false)
- {
- if (! $this->server->isFunctional()) {
- return;
- }
- if (! $refresh && ($this->resource?->getMorphClass() === \App\Models\Service::class || str($this->container)->contains('-pr-'))) {
- return;
- }
- if ($this->numberOfLines <= 0 || is_null($this->numberOfLines)) {
- $this->numberOfLines = 1000;
- }
- if ($this->container) {
- if ($this->showTimeStamps) {
- if ($this->server->isSwarm()) {
- $command = "docker service logs -n {$this->numberOfLines} -t {$this->container}";
- if ($this->server->isNonRoot()) {
- $command = parseCommandsByLineForSudo(collect($command), $this->server);
- $command = $command[0];
- }
- $sshCommand = SshMultiplexingHelper::generateSshCommand($this->server, $command);
- } else {
- $command = "docker logs -n {$this->numberOfLines} -t {$this->container}";
- if ($this->server->isNonRoot()) {
- $command = parseCommandsByLineForSudo(collect($command), $this->server);
- $command = $command[0];
- }
- $sshCommand = SshMultiplexingHelper::generateSshCommand($this->server, $command);
- }
- } else {
- if ($this->server->isSwarm()) {
- $command = "docker service logs -n {$this->numberOfLines} {$this->container}";
- if ($this->server->isNonRoot()) {
- $command = parseCommandsByLineForSudo(collect($command), $this->server);
- $command = $command[0];
- }
- $sshCommand = SshMultiplexingHelper::generateSshCommand($this->server, $command);
- } else {
- $command = "docker logs -n {$this->numberOfLines} {$this->container}";
- if ($this->server->isNonRoot()) {
- $command = parseCommandsByLineForSudo(collect($command), $this->server);
- $command = $command[0];
- }
- $sshCommand = SshMultiplexingHelper::generateSshCommand($this->server, $command);
- }
- }
- if ($refresh) {
- $this->outputs = '';
- }
- Process::run($sshCommand, function (string $type, string $output) {
- $this->doSomethingWithThisChunkOfOutput($output);
- });
- if ($this->showTimeStamps) {
- $this->outputs = str($this->outputs)->split('/\n/')->sort(function ($a, $b) {
- $a = explode(' ', $a);
- $b = explode(' ', $b);
-
- return $a[0] <=> $b[0];
- })->join("\n");
- }
- }
- }
-
- public function render()
- {
- return view('livewire.project.shared.get-logs');
- }
-}
diff --git a/app/Livewire/Project/Shared/HealthChecks.php b/app/Livewire/Project/Shared/HealthChecks.php
deleted file mode 100644
index 83162e36a2..0000000000
--- a/app/Livewire/Project/Shared/HealthChecks.php
+++ /dev/null
@@ -1,49 +0,0 @@
- 'boolean',
- 'resource.health_check_path' => 'string',
- 'resource.health_check_port' => 'nullable|string',
- 'resource.health_check_host' => 'string',
- 'resource.health_check_method' => 'string',
- 'resource.health_check_return_code' => 'integer',
- 'resource.health_check_scheme' => 'string',
- 'resource.health_check_response_text' => 'nullable|string',
- 'resource.health_check_interval' => 'integer|min:1',
- 'resource.health_check_timeout' => 'integer|min:1',
- 'resource.health_check_retries' => 'integer|min:1',
- 'resource.health_check_start_period' => 'integer',
- 'resource.custom_healthcheck_found' => 'boolean',
-
- ];
-
- public function instantSave()
- {
- $this->resource->save();
- $this->dispatch('success', 'Health check updated.');
- }
-
- public function submit()
- {
- try {
- $this->validate();
- $this->resource->save();
- $this->dispatch('success', 'Health check updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.project.shared.health-checks');
- }
-}
diff --git a/app/Livewire/Project/Shared/Logs.php b/app/Livewire/Project/Shared/Logs.php
deleted file mode 100644
index 12022b1eeb..0000000000
--- a/app/Livewire/Project/Shared/Logs.php
+++ /dev/null
@@ -1,122 +0,0 @@
-servers->firstWhere('id', $server_id);
- if (! $server->isFunctional()) {
- return;
- }
- if ($server->isSwarm()) {
- $containers = collect([
- [
- 'Names' => $this->resource->uuid.'_'.$this->resource->uuid,
- ],
- ]);
- } else {
- $containers = getCurrentApplicationContainerStatus($server, $this->resource->id, includePullrequests: true);
- }
- $server->containers = $containers->sort();
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function mount()
- {
- try {
- $this->containers = collect();
- $this->servers = collect();
- $this->parameters = get_route_parameters();
- $this->query = request()->query();
- if (data_get($this->parameters, 'application_uuid')) {
- $this->type = 'application';
- $this->resource = Application::where('uuid', $this->parameters['application_uuid'])->firstOrFail();
- $this->status = $this->resource->status;
- if ($this->resource->destination->server->isFunctional()) {
- $this->servers = $this->servers->push($this->resource->destination->server);
- }
- foreach ($this->resource->additional_servers as $server) {
- if ($server->isFunctional()) {
- $this->servers = $this->servers->push($server);
- }
- }
- } elseif (data_get($this->parameters, 'database_uuid')) {
- $this->type = 'database';
- $resource = getResourceByUuid($this->parameters['database_uuid'], data_get(auth()->user()->currentTeam(), 'id'));
- if (is_null($resource)) {
- abort(404);
- }
- $this->resource = $resource;
- $this->status = $this->resource->status;
- if ($this->resource->destination->server->isFunctional()) {
- $this->servers = $this->servers->push($this->resource->destination->server);
- }
- $this->container = $this->resource->uuid;
- $this->containers->push($this->container);
- } elseif (data_get($this->parameters, 'service_uuid')) {
- $this->type = 'service';
- $this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
- $this->resource->applications()->get()->each(function ($application) {
- $this->containers->push(data_get($application, 'name').'-'.data_get($this->resource, 'uuid'));
- });
- $this->resource->databases()->get()->each(function ($database) {
- $this->containers->push(data_get($database, 'name').'-'.data_get($this->resource, 'uuid'));
- });
- if ($this->resource->server->isFunctional()) {
- $this->servers = $this->servers->push($this->resource->server);
- }
- }
- $this->containers = $this->containers->sort();
- if (data_get($this->query, 'pull_request_id')) {
- $this->containers = $this->containers->filter(function ($container) {
- return str_contains($container, $this->query['pull_request_id']);
- });
- }
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.project.shared.logs');
- }
-}
diff --git a/app/Livewire/Project/Shared/Metrics.php b/app/Livewire/Project/Shared/Metrics.php
deleted file mode 100644
index fdc35fc0fb..0000000000
--- a/app/Livewire/Project/Shared/Metrics.php
+++ /dev/null
@@ -1,59 +0,0 @@
-poll || $this->interval <= 10) {
- $this->loadData();
- if ($this->interval > 10) {
- $this->poll = false;
- }
- }
- }
-
- public function loadData()
- {
- try {
- $cpuMetrics = $this->resource->getCpuMetrics($this->interval);
- $memoryMetrics = $this->resource->getMemoryMetrics($this->interval);
- $this->dispatch("refreshChartData-{$this->chartId}-cpu", [
- 'seriesData' => $cpuMetrics,
- ]);
- $this->dispatch("refreshChartData-{$this->chartId}-memory", [
- 'seriesData' => $memoryMetrics,
- ]);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function setInterval()
- {
- if ($this->interval <= 10) {
- $this->poll = true;
- }
- $this->loadData();
- }
-
- public function render()
- {
- return view('livewire.project.shared.metrics');
- }
-}
diff --git a/app/Livewire/Project/Shared/ResourceLimits.php b/app/Livewire/Project/Shared/ResourceLimits.php
deleted file mode 100644
index 608dfbf022..0000000000
--- a/app/Livewire/Project/Shared/ResourceLimits.php
+++ /dev/null
@@ -1,62 +0,0 @@
- 'required|string',
- 'resource.limits_memory_swap' => 'required|string',
- 'resource.limits_memory_swappiness' => 'required|integer|min:0|max:100',
- 'resource.limits_memory_reservation' => 'required|string',
- 'resource.limits_cpus' => 'nullable',
- 'resource.limits_cpuset' => 'nullable',
- 'resource.limits_cpu_shares' => 'nullable',
- ];
-
- protected $validationAttributes = [
- 'resource.limits_memory' => 'memory',
- 'resource.limits_memory_swap' => 'swap',
- 'resource.limits_memory_swappiness' => 'swappiness',
- 'resource.limits_memory_reservation' => 'reservation',
- 'resource.limits_cpus' => 'cpus',
- 'resource.limits_cpuset' => 'cpuset',
- 'resource.limits_cpu_shares' => 'cpu shares',
- ];
-
- public function submit()
- {
- try {
- if (! $this->resource->limits_memory) {
- $this->resource->limits_memory = '0';
- }
- if (! $this->resource->limits_memory_swap) {
- $this->resource->limits_memory_swap = '0';
- }
- if (is_null($this->resource->limits_memory_swappiness)) {
- $this->resource->limits_memory_swappiness = '60';
- }
- if (! $this->resource->limits_memory_reservation) {
- $this->resource->limits_memory_reservation = '0';
- }
- if (! $this->resource->limits_cpus) {
- $this->resource->limits_cpus = '0';
- }
- if ($this->resource->limits_cpuset === '') {
- $this->resource->limits_cpuset = null;
- }
- if (is_null($this->resource->limits_cpu_shares)) {
- $this->resource->limits_cpu_shares = 1024;
- }
- $this->validate();
- $this->resource->save();
- $this->dispatch('success', 'Resource limits updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Project/Shared/ResourceOperations.php b/app/Livewire/Project/Shared/ResourceOperations.php
deleted file mode 100644
index e19f1272dd..0000000000
--- a/app/Livewire/Project/Shared/ResourceOperations.php
+++ /dev/null
@@ -1,526 +0,0 @@
-projectUuid = data_get($parameters, 'project_uuid');
- $this->environmentUuid = data_get($parameters, 'environment_uuid');
- $this->projects = Project::ownedByCurrentTeam()->get();
- $this->servers = currentTeam()->servers;
- }
-
- public function toggleVolumeCloning(bool $value)
- {
- $this->cloneVolumeData = $value;
- }
-
- public function cloneTo($destination_id)
- {
- $new_destination = StandaloneDocker::find($destination_id);
- if (! $new_destination) {
- $new_destination = SwarmDocker::find($destination_id);
- }
- if (! $new_destination) {
- return $this->addError('destination_id', 'Destination not found.');
- }
- $uuid = (string) new Cuid2;
- $server = $new_destination->server;
-
- if ($this->resource->getMorphClass() === \App\Models\Application::class) {
- $name = 'clone-of-'.str($this->resource->name)->limit(20).'-'.$uuid;
- $applicationSettings = $this->resource->settings;
- $url = $this->resource->fqdn;
-
- if ($server->proxyType() !== 'NONE' && $applicationSettings->is_container_label_readonly_enabled === true) {
- $url = generateFqdn($server, $uuid);
- }
-
- $new_resource = $this->resource->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- 'additional_servers_count',
- 'additional_networks_count',
- ])->fill([
- 'uuid' => $uuid,
- 'name' => $name,
- 'fqdn' => $url,
- 'status' => 'exited',
- 'destination_id' => $new_destination->id,
- ]);
- $new_resource->save();
-
- if ($new_resource->destination->server->proxyType() !== 'NONE' && $applicationSettings->is_container_label_readonly_enabled === true) {
- $customLabels = str(implode('|coolify|', generateLabelsApplication($new_resource)))->replace('|coolify|', "\n");
- $new_resource->custom_labels = base64_encode($customLabels);
- $new_resource->save();
- }
-
- $new_resource->settings()->delete();
- if ($applicationSettings) {
- $newApplicationSettings = $applicationSettings->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'application_id' => $new_resource->id,
- ]);
- $newApplicationSettings->save();
- }
-
- $tags = $this->resource->tags;
- foreach ($tags as $tag) {
- $new_resource->tags()->attach($tag->id);
- }
-
- $scheduledTasks = $this->resource->scheduled_tasks()->get();
- foreach ($scheduledTasks as $task) {
- $newTask = $task->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'uuid' => (string) new Cuid2,
- 'application_id' => $new_resource->id,
- 'team_id' => currentTeam()->id,
- ]);
- $newTask->save();
- }
-
- $applicationPreviews = $this->resource->previews()->get();
- foreach ($applicationPreviews as $preview) {
- $newPreview = $preview->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'application_id' => $new_resource->id,
- 'status' => 'exited',
- ]);
- $newPreview->save();
- }
-
- $persistentVolumes = $this->resource->persistentStorages()->get();
- foreach ($persistentVolumes as $volume) {
- $newName = '';
- if (str_starts_with($volume->name, $this->resource->uuid)) {
- $newName = str($volume->name)->replace($this->resource->uuid, $new_resource->uuid);
- } else {
- $newName = $new_resource->uuid.'-'.str($volume->name)->afterLast('-');
- }
-
- $newPersistentVolume = $volume->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'name' => $newName,
- 'resource_id' => $new_resource->id,
- ]);
- $newPersistentVolume->save();
-
- if ($this->cloneVolumeData) {
- try {
- StopApplication::dispatch($this->resource, false, false);
- $sourceVolume = $volume->name;
- $targetVolume = $newPersistentVolume->name;
- $sourceServer = $this->resource->destination->server;
- $targetServer = $new_resource->destination->server;
-
- VolumeCloneJob::dispatch($sourceVolume, $targetVolume, $sourceServer, $targetServer, $newPersistentVolume);
-
- queue_application_deployment(
- deployment_uuid: (string) new Cuid2,
- application: $this->resource,
- server: $sourceServer,
- destination: $this->resource->destination,
- no_questions_asked: true
- );
- } catch (\Exception $e) {
- \Log::error('Failed to copy volume data for '.$volume->name.': '.$e->getMessage());
- }
- }
- }
-
- $fileStorages = $this->resource->fileStorages()->get();
- foreach ($fileStorages as $storage) {
- $newStorage = $storage->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'resource_id' => $new_resource->id,
- ]);
- $newStorage->save();
- }
-
- $environmentVaribles = $this->resource->environment_variables()->get();
- foreach ($environmentVaribles as $environmentVarible) {
- $newEnvironmentVariable = $environmentVarible->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'resourceable_id' => $new_resource->id,
- 'resourceable_type' => $new_resource->getMorphClass(),
- ]);
- $newEnvironmentVariable->save();
- }
-
- $route = route('project.application.configuration', [
- 'project_uuid' => $this->projectUuid,
- 'environment_uuid' => $this->environmentUuid,
- 'application_uuid' => $new_resource->uuid,
- ]).'#resource-operations';
-
- return redirect()->to($route);
- } elseif (
- $this->resource->getMorphClass() === \App\Models\StandalonePostgresql::class ||
- $this->resource->getMorphClass() === \App\Models\StandaloneMongodb::class ||
- $this->resource->getMorphClass() === \App\Models\StandaloneMysql::class ||
- $this->resource->getMorphClass() === \App\Models\StandaloneMariadb::class ||
- $this->resource->getMorphClass() === \App\Models\StandaloneRedis::class ||
- $this->resource->getMorphClass() === \App\Models\StandaloneKeydb::class ||
- $this->resource->getMorphClass() === \App\Models\StandaloneDragonfly::class ||
- $this->resource->getMorphClass() === \App\Models\StandaloneClickhouse::class
- ) {
- $uuid = (string) new Cuid2;
- $new_resource = $this->resource->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'uuid' => $uuid,
- 'name' => $this->resource->name.'-clone-'.$uuid,
- 'status' => 'exited',
- 'started_at' => null,
- 'destination_id' => $new_destination->id,
- ]);
- $new_resource->save();
-
- $tags = $this->resource->tags;
- foreach ($tags as $tag) {
- $new_resource->tags()->attach($tag->id);
- }
-
- $new_resource->persistentStorages()->delete();
- $persistentVolumes = $this->resource->persistentStorages()->get();
- foreach ($persistentVolumes as $volume) {
- $originalName = $volume->name;
- $newName = '';
-
- if (str_starts_with($originalName, 'postgres-data-')) {
- $newName = 'postgres-data-'.$new_resource->uuid;
- } elseif (str_starts_with($originalName, 'mysql-data-')) {
- $newName = 'mysql-data-'.$new_resource->uuid;
- } elseif (str_starts_with($originalName, 'redis-data-')) {
- $newName = 'redis-data-'.$new_resource->uuid;
- } elseif (str_starts_with($originalName, 'clickhouse-data-')) {
- $newName = 'clickhouse-data-'.$new_resource->uuid;
- } elseif (str_starts_with($originalName, 'mariadb-data-')) {
- $newName = 'mariadb-data-'.$new_resource->uuid;
- } elseif (str_starts_with($originalName, 'mongodb-data-')) {
- $newName = 'mongodb-data-'.$new_resource->uuid;
- } elseif (str_starts_with($originalName, 'keydb-data-')) {
- $newName = 'keydb-data-'.$new_resource->uuid;
- } elseif (str_starts_with($originalName, 'dragonfly-data-')) {
- $newName = 'dragonfly-data-'.$new_resource->uuid;
- } else {
- if (str_starts_with($volume->name, $this->resource->uuid)) {
- $newName = str($volume->name)->replace($this->resource->uuid, $new_resource->uuid);
- } else {
- $newName = $new_resource->uuid.'-'.$volume->name;
- }
- }
-
- $newPersistentVolume = $volume->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'name' => $newName,
- 'resource_id' => $new_resource->id,
- ]);
- $newPersistentVolume->save();
-
- if ($this->cloneVolumeData) {
- try {
- StopDatabase::dispatch($this->resource);
- $sourceVolume = $volume->name;
- $targetVolume = $newPersistentVolume->name;
- $sourceServer = $this->resource->destination->server;
- $targetServer = $new_resource->destination->server;
-
- VolumeCloneJob::dispatch($sourceVolume, $targetVolume, $sourceServer, $targetServer, $newPersistentVolume);
-
- StartDatabase::dispatch($this->resource);
- } catch (\Exception $e) {
- \Log::error('Failed to copy volume data for '.$volume->name.': '.$e->getMessage());
- }
- }
- }
-
- $fileStorages = $this->resource->fileStorages()->get();
- foreach ($fileStorages as $storage) {
- $newStorage = $storage->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'resource_id' => $new_resource->id,
- ]);
- $newStorage->save();
- }
-
- $scheduledBackups = $this->resource->scheduledBackups()->get();
- foreach ($scheduledBackups as $backup) {
- $uuid = (string) new Cuid2;
- $newBackup = $backup->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'uuid' => $uuid,
- 'database_id' => $new_resource->id,
- 'database_type' => $new_resource->getMorphClass(),
- 'team_id' => currentTeam()->id,
- ]);
- $newBackup->save();
- }
-
- $environmentVaribles = $this->resource->environment_variables()->get();
- foreach ($environmentVaribles as $environmentVarible) {
- $payload = [
- 'resourceable_id' => $new_resource->id,
- 'resourceable_type' => $new_resource->getMorphClass(),
- ];
- $newEnvironmentVariable = $environmentVarible->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill($payload);
- $newEnvironmentVariable->save();
- }
-
- $route = route('project.database.configuration', [
- 'project_uuid' => $this->projectUuid,
- 'environment_uuid' => $this->environmentUuid,
- 'database_uuid' => $new_resource->uuid,
- ]).'#resource-operations';
-
- return redirect()->to($route);
- } elseif ($this->resource->type() === 'service') {
- $uuid = (string) new Cuid2;
- $new_resource = $this->resource->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'uuid' => $uuid,
- 'name' => $this->resource->name.'-clone-'.$uuid,
- 'destination_id' => $new_destination->id,
- 'destination_type' => $new_destination->getMorphClass(),
- 'server_id' => $new_destination->server_id, // server_id is probably not needed anymore because of the new polymorphic relationships (here it is needed for clone to a different server to work - but maybe we can drop the column)
- ]);
-
- $new_resource->save();
-
- $tags = $this->resource->tags;
- foreach ($tags as $tag) {
- $new_resource->tags()->attach($tag->id);
- }
-
- $scheduledTasks = $this->resource->scheduled_tasks()->get();
- foreach ($scheduledTasks as $task) {
- $newTask = $task->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'uuid' => (string) new Cuid2,
- 'service_id' => $new_resource->id,
- 'team_id' => currentTeam()->id,
- ]);
- $newTask->save();
- }
-
- $environmentVariables = $this->resource->environment_variables()->get();
- foreach ($environmentVariables as $environmentVariable) {
- $newEnvironmentVariable = $environmentVariable->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'resourceable_id' => $new_resource->id,
- 'resourceable_type' => $new_resource->getMorphClass(),
- ]);
- $newEnvironmentVariable->save();
- }
-
- foreach ($new_resource->applications() as $application) {
- $application->update([
- 'status' => 'exited',
- ]);
-
- $persistentVolumes = $application->persistentStorages()->get();
- foreach ($persistentVolumes as $volume) {
- $newName = '';
- if (str_starts_with($volume->name, $volume->resource->uuid)) {
- $newName = str($volume->name)->replace($volume->resource->uuid, $application->uuid);
- } else {
- $newName = $application->uuid.'-'.str($volume->name)->afterLast('-');
- }
-
- $newPersistentVolume = $volume->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'name' => $newName,
- 'resource_id' => $application->id,
- ]);
- $newPersistentVolume->save();
-
- if ($this->cloneVolumeData) {
- try {
- StopService::dispatch($application, false, false);
- $sourceVolume = $volume->name;
- $targetVolume = $newPersistentVolume->name;
- $sourceServer = $application->service->destination->server;
- $targetServer = $new_resource->destination->server;
-
- VolumeCloneJob::dispatch($sourceVolume, $targetVolume, $sourceServer, $targetServer, $newPersistentVolume);
-
- StartService::dispatch($application);
- } catch (\Exception $e) {
- \Log::error('Failed to copy volume data for '.$volume->name.': '.$e->getMessage());
- }
- }
- }
- }
-
- foreach ($new_resource->databases() as $database) {
- $database->update([
- 'status' => 'exited',
- ]);
-
- $persistentVolumes = $database->persistentStorages()->get();
- foreach ($persistentVolumes as $volume) {
- $newName = '';
- if (str_starts_with($volume->name, $volume->resource->uuid)) {
- $newName = str($volume->name)->replace($volume->resource->uuid, $database->uuid);
- } else {
- $newName = $database->uuid.'-'.str($volume->name)->afterLast('-');
- }
-
- $newPersistentVolume = $volume->replicate([
- 'id',
- 'created_at',
- 'updated_at',
- ])->fill([
- 'name' => $newName,
- 'resource_id' => $database->id,
- ]);
- $newPersistentVolume->save();
-
- if ($this->cloneVolumeData) {
- try {
- StopService::dispatch($database->service, false, false);
- $sourceVolume = $volume->name;
- $targetVolume = $newPersistentVolume->name;
- $sourceServer = $database->service->destination->server;
- $targetServer = $new_resource->destination->server;
-
- VolumeCloneJob::dispatch($sourceVolume, $targetVolume, $sourceServer, $targetServer, $newPersistentVolume);
-
- StartService::dispatch($database->service);
- } catch (\Exception $e) {
- \Log::error('Failed to copy volume data for '.$volume->name.': '.$e->getMessage());
- }
- }
- }
- }
-
- $new_resource->parse();
-
- $route = route('project.service.configuration', [
- 'project_uuid' => $this->projectUuid,
- 'environment_uuid' => $this->environmentUuid,
- 'service_uuid' => $new_resource->uuid,
- ]).'#resource-operations';
-
- return redirect()->to($route);
- }
- }
-
- public function moveTo($environment_id)
- {
- try {
- $new_environment = Environment::findOrFail($environment_id);
- $this->resource->update([
- 'environment_id' => $environment_id,
- ]);
- if ($this->resource->type() === 'application') {
- $route = route('project.application.configuration', [
- 'project_uuid' => $new_environment->project->uuid,
- 'environment_uuid' => $new_environment->uuid,
- 'application_uuid' => $this->resource->uuid,
- ]).'#resource-operations';
-
- return redirect()->to($route);
- } elseif (str($this->resource->type())->startsWith('standalone-')) {
- $route = route('project.database.configuration', [
- 'project_uuid' => $new_environment->project->uuid,
- 'environment_uuid' => $new_environment->uuid,
- 'database_uuid' => $this->resource->uuid,
- ]).'#resource-operations';
-
- return redirect()->to($route);
- } elseif ($this->resource->type() === 'service') {
- $route = route('project.service.configuration', [
- 'project_uuid' => $new_environment->project->uuid,
- 'environment_uuid' => $new_environment->uuid,
- 'service_uuid' => $this->resource->uuid,
- ]).'#resource-operations';
-
- return redirect()->to($route);
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.project.shared.resource-operations');
- }
-}
diff --git a/app/Livewire/Project/Shared/ScheduledTask/Add.php b/app/Livewire/Project/Shared/ScheduledTask/Add.php
deleted file mode 100644
index c286fee5a8..0000000000
--- a/app/Livewire/Project/Shared/ScheduledTask/Add.php
+++ /dev/null
@@ -1,111 +0,0 @@
- 'required|string',
- 'command' => 'required|string',
- 'frequency' => 'required|string',
- 'container' => 'nullable|string',
- ];
-
- protected $validationAttributes = [
- 'name' => 'name',
- 'command' => 'command',
- 'frequency' => 'frequency',
- 'container' => 'container',
- ];
-
- public function mount()
- {
- $this->parameters = get_route_parameters();
- if ($this->containerNames->count() > 0) {
- $this->container = $this->containerNames->first();
- }
- }
-
- public function submit()
- {
- try {
- $this->validate();
- $isValid = validate_cron_expression($this->frequency);
- if (! $isValid) {
- $this->dispatch('error', 'Invalid Cron / Human expression.');
-
- return;
- }
- if (empty($this->container) || $this->container === 'null') {
- if ($this->type === 'service') {
- $this->container = $this->subServiceName;
- }
- }
- $this->saveScheduledTask();
- $this->clear();
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function saveScheduledTask()
- {
- try {
- $task = new ScheduledTask;
- $task->name = $this->name;
- $task->command = $this->command;
- $task->frequency = $this->frequency;
- $task->container = $this->container;
- $task->team_id = currentTeam()->id;
-
- switch ($this->type) {
- case 'application':
- $task->application_id = $this->id;
- break;
- case 'standalone-postgresql':
- $task->standalone_postgresql_id = $this->id;
- break;
- case 'service':
- $task->service_id = $this->id;
- break;
- }
- $task->save();
- $this->dispatch('refreshTasks');
- $this->dispatch('success', 'Scheduled task added.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function clear()
- {
- $this->name = '';
- $this->command = '';
- $this->frequency = '';
- $this->container = '';
- }
-}
diff --git a/app/Livewire/Project/Shared/ScheduledTask/All.php b/app/Livewire/Project/Shared/ScheduledTask/All.php
deleted file mode 100644
index b58e4f97a9..0000000000
--- a/app/Livewire/Project/Shared/ScheduledTask/All.php
+++ /dev/null
@@ -1,44 +0,0 @@
-parameters = get_route_parameters();
- if ($this->resource->type() === 'service') {
- $this->containerNames = $this->resource->applications()->pluck('name');
- $this->containerNames = $this->containerNames->merge($this->resource->databases()->pluck('name'));
- } elseif ($this->resource->type() === 'application') {
- if ($this->resource->build_pack === 'dockercompose') {
- $parsed = $this->resource->parse();
- $containers = collect(data_get($parsed, 'services'))->keys();
- $this->containerNames = $containers;
- } else {
- $this->containerNames = collect([]);
- }
- }
- }
-
- #[On('refreshTasks')]
- public function refreshTasks()
- {
- $this->resource->refresh();
- }
-}
diff --git a/app/Livewire/Project/Shared/ScheduledTask/Executions.php b/app/Livewire/Project/Shared/ScheduledTask/Executions.php
deleted file mode 100644
index 6f62a5b5bf..0000000000
--- a/app/Livewire/Project/Shared/ScheduledTask/Executions.php
+++ /dev/null
@@ -1,144 +0,0 @@
-currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},ScheduledTaskDone" => 'refreshExecutions',
- ];
- }
-
- public function mount($taskId)
- {
- try {
- $this->taskId = $taskId;
- $this->task = ScheduledTask::findOrFail($taskId);
- $this->executions = $this->task->executions()->take(20)->get();
- $this->serverTimezone = data_get($this->task, 'application.destination.server.settings.server_timezone');
- if (! $this->serverTimezone) {
- $this->serverTimezone = data_get($this->task, 'service.destination.server.settings.server_timezone');
- }
- if (! $this->serverTimezone) {
- $this->serverTimezone = 'UTC';
- }
- } catch (\Exception $e) {
- return handleError($e);
- }
- }
-
- public function refreshExecutions(): void
- {
- $this->executions = $this->task->executions()->take(20)->get();
- if ($this->selectedKey) {
- $this->selectedExecution = $this->task->executions()->find($this->selectedKey);
- if ($this->selectedExecution && $this->selectedExecution->status !== 'running') {
- $this->isPollingActive = false;
- }
- }
- }
-
- public function selectTask($key): void
- {
- if ($key == $this->selectedKey) {
- $this->selectedKey = null;
- $this->selectedExecution = null;
- $this->currentPage = 1;
- $this->isPollingActive = false;
-
- return;
- }
- $this->selectedKey = $key;
- $this->selectedExecution = $this->task->executions()->find($key);
- $this->currentPage = 1;
-
- // Start polling if task is running
- if ($this->selectedExecution && $this->selectedExecution->status === 'running') {
- $this->isPollingActive = true;
- }
- }
-
- public function polling()
- {
- if ($this->selectedExecution && $this->isPollingActive) {
- $this->selectedExecution->refresh();
- if ($this->selectedExecution->status !== 'running') {
- $this->isPollingActive = false;
- }
- }
- }
-
- public function loadMoreLogs()
- {
- $this->currentPage++;
- }
-
- public function getLogLinesProperty()
- {
- if (! $this->selectedExecution) {
- return collect();
- }
-
- if (! $this->selectedExecution->message) {
- return collect(['Waiting for task output...']);
- }
-
- $lines = collect(explode("\n", $this->selectedExecution->message));
-
- return $lines->take($this->currentPage * $this->logsPerPage);
- }
-
- public function downloadLogs(int $executionId)
- {
- $execution = $this->executions->firstWhere('id', $executionId);
- if (! $execution) {
- return;
- }
-
- return response()->streamDownload(function () use ($execution) {
- echo $execution->message;
- }, 'task-execution-'.$execution->id.'.log');
- }
-
- public function hasMoreLogs()
- {
- if (! $this->selectedExecution || ! $this->selectedExecution->message) {
- return false;
- }
- $lines = collect(explode("\n", $this->selectedExecution->message));
-
- return $lines->count() > ($this->currentPage * $this->logsPerPage);
- }
-}
diff --git a/app/Livewire/Project/Shared/ScheduledTask/Show.php b/app/Livewire/Project/Shared/ScheduledTask/Show.php
deleted file mode 100644
index 6d9c6982a6..0000000000
--- a/app/Livewire/Project/Shared/ScheduledTask/Show.php
+++ /dev/null
@@ -1,154 +0,0 @@
-task_uuid = $task_uuid;
- if ($application_uuid) {
- $this->type = 'application';
- $this->application_uuid = $application_uuid;
- $this->resource = Application::ownedByCurrentTeam()->where('uuid', $application_uuid)->firstOrFail();
- } elseif ($service_uuid) {
- $this->type = 'service';
- $this->service_uuid = $service_uuid;
- $this->resource = Service::ownedByCurrentTeam()->where('uuid', $service_uuid)->firstOrFail();
- }
- $this->parameters = [
- 'environment_uuid' => $environment_uuid,
- 'project_uuid' => $project_uuid,
- 'application_uuid' => $application_uuid,
- 'service_uuid' => $service_uuid,
- ];
-
- $this->task = $this->resource->scheduled_tasks()->where('uuid', $task_uuid)->firstOrFail();
- $this->syncData();
- } catch (\Exception $e) {
- return handleError($e);
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $isValid = validate_cron_expression($this->frequency);
- if (! $isValid) {
- $this->frequency = $this->task->frequency;
- throw new \Exception('Invalid Cron / Human expression.');
- }
- $this->task->enabled = $this->isEnabled;
- $this->task->name = str($this->name)->trim()->value();
- $this->task->command = str($this->command)->trim()->value();
- $this->task->frequency = str($this->frequency)->trim()->value();
- $this->task->container = str($this->container)->trim()->value();
- $this->task->save();
- } else {
- $this->isEnabled = $this->task->enabled;
- $this->name = $this->task->name;
- $this->command = $this->task->command;
- $this->frequency = $this->task->frequency;
- $this->container = $this->task->container;
- }
- }
-
- public function instantSave()
- {
- try {
- $this->syncData(true);
- $this->dispatch('success', 'Scheduled task updated.');
- $this->refreshTasks();
- } catch (\Exception $e) {
- return handleError($e);
- }
- }
-
- public function submit()
- {
- try {
- $this->syncData(true);
- $this->dispatch('success', 'Scheduled task updated.');
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function refreshTasks()
- {
- try {
- $this->task->refresh();
- } catch (\Exception $e) {
- return handleError($e);
- }
- }
-
- public function delete()
- {
- try {
- $this->task->delete();
-
- if ($this->type === 'application') {
- return redirect()->route('project.application.scheduled-tasks.show', $this->parameters);
- } else {
- return redirect()->route('project.service.scheduled-tasks.show', $this->parameters);
- }
- } catch (\Exception $e) {
- return handleError($e);
- }
- }
-
- public function executeNow()
- {
- try {
- ScheduledTaskJob::dispatch($this->task);
- $this->dispatch('success', 'Scheduled task executed.');
- } catch (\Exception $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Livewire/Project/Shared/Storages/Add.php b/app/Livewire/Project/Shared/Storages/Add.php
deleted file mode 100644
index dc015386c6..0000000000
--- a/app/Livewire/Project/Shared/Storages/Add.php
+++ /dev/null
@@ -1,165 +0,0 @@
- 'required|string',
- 'mount_path' => 'required|string',
- 'host_path' => 'string|nullable',
- 'file_storage_path' => 'string',
- 'file_storage_content' => 'nullable|string',
- 'file_storage_directory_source' => 'string',
- 'file_storage_directory_destination' => 'string',
- ];
-
- protected $listeners = ['clearAddStorage' => 'clear'];
-
- protected $validationAttributes = [
- 'name' => 'name',
- 'mount_path' => 'mount',
- 'host_path' => 'host',
- 'file_storage_path' => 'file storage path',
- 'file_storage_content' => 'file storage content',
- 'file_storage_directory_source' => 'file storage directory source',
- 'file_storage_directory_destination' => 'file storage directory destination',
- ];
-
- public function mount()
- {
- if (str($this->resource->getMorphClass())->contains('Standalone')) {
- $this->file_storage_directory_source = database_configuration_dir()."/{$this->resource->uuid}";
- } else {
- $this->file_storage_directory_source = application_configuration_dir()."/{$this->resource->uuid}";
- }
- $this->uuid = $this->resource->uuid;
- $this->parameters = get_route_parameters();
- if (data_get($this->parameters, 'application_uuid')) {
- $applicationUuid = $this->parameters['application_uuid'];
- $application = Application::where('uuid', $applicationUuid)->first();
- if (! $application) {
- abort(404);
- }
- if ($application->destination->server->isSwarm()) {
- $this->isSwarm = true;
- $this->rules['host_path'] = 'required|string';
- }
- }
- }
-
- public function submitFileStorage()
- {
- try {
- $this->validate([
- 'file_storage_path' => 'string',
- 'file_storage_content' => 'nullable|string',
- ]);
-
- $this->file_storage_path = trim($this->file_storage_path);
- $this->file_storage_path = str($this->file_storage_path)->start('/')->value();
-
- if ($this->resource->getMorphClass() === \App\Models\Application::class) {
- $fs_path = application_configuration_dir().'/'.$this->resource->uuid.$this->file_storage_path;
- } elseif (str($this->resource->getMorphClass())->contains('Standalone')) {
- $fs_path = database_configuration_dir().'/'.$this->resource->uuid.$this->file_storage_path;
- } else {
- throw new \Exception('No valid resource type for file mount storage type!');
- }
-
- LocalFileVolume::create(
- [
- 'fs_path' => $fs_path,
- 'mount_path' => $this->file_storage_path,
- 'content' => $this->file_storage_content,
- 'is_directory' => false,
- 'resource_id' => $this->resource->id,
- 'resource_type' => get_class($this->resource),
- ],
- );
- $this->dispatch('refreshStorages');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submitFileStorageDirectory()
- {
- try {
- $this->validate([
- 'file_storage_directory_source' => 'string',
- 'file_storage_directory_destination' => 'string',
- ]);
-
- $this->file_storage_directory_source = trim($this->file_storage_directory_source);
- $this->file_storage_directory_source = str($this->file_storage_directory_source)->start('/')->value();
- $this->file_storage_directory_destination = trim($this->file_storage_directory_destination);
- $this->file_storage_directory_destination = str($this->file_storage_directory_destination)->start('/')->value();
-
- LocalFileVolume::create(
- [
- 'fs_path' => $this->file_storage_directory_source,
- 'mount_path' => $this->file_storage_directory_destination,
- 'is_directory' => true,
- 'resource_id' => $this->resource->id,
- 'resource_type' => get_class($this->resource),
- ],
- );
- $this->dispatch('refreshStorages');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submitPersistentVolume()
- {
- try {
- $this->validate([
- 'name' => 'required|string',
- 'mount_path' => 'required|string',
- 'host_path' => 'string|nullable',
- ]);
- $name = $this->uuid.'-'.$this->name;
- $this->dispatch('addNewVolume', [
- 'name' => $name,
- 'mount_path' => $this->mount_path,
- 'host_path' => $this->host_path,
- ]);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function clear()
- {
- $this->name = '';
- $this->mount_path = '';
- $this->host_path = null;
- }
-}
diff --git a/app/Livewire/Project/Shared/Storages/All.php b/app/Livewire/Project/Shared/Storages/All.php
deleted file mode 100644
index c26315d3b2..0000000000
--- a/app/Livewire/Project/Shared/Storages/All.php
+++ /dev/null
@@ -1,12 +0,0 @@
- '$refresh'];
-}
diff --git a/app/Livewire/Project/Shared/Storages/Show.php b/app/Livewire/Project/Shared/Storages/Show.php
deleted file mode 100644
index 54b1be3af5..0000000000
--- a/app/Livewire/Project/Shared/Storages/Show.php
+++ /dev/null
@@ -1,55 +0,0 @@
- 'required|string',
- 'storage.mount_path' => 'required|string',
- 'storage.host_path' => 'string|nullable',
- ];
-
- protected $validationAttributes = [
- 'name' => 'name',
- 'mount_path' => 'mount',
- 'host_path' => 'host',
- ];
-
- public function submit()
- {
- $this->validate();
- $this->storage->save();
- $this->dispatch('success', 'Storage updated successfully');
- }
-
- public function delete($password)
- {
- if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return;
- }
- }
-
- $this->storage->delete();
- $this->dispatch('refreshStorages');
- }
-}
diff --git a/app/Livewire/Project/Shared/Tags.php b/app/Livewire/Project/Shared/Tags.php
deleted file mode 100644
index 811859cb88..0000000000
--- a/app/Livewire/Project/Shared/Tags.php
+++ /dev/null
@@ -1,104 +0,0 @@
-loadTags();
- }
-
- public function loadTags()
- {
- $this->tags = Tag::ownedByCurrentTeam()->get();
- $this->filteredTags = $this->tags->filter(function ($tag) {
- return ! $this->resource->tags->contains($tag);
- });
- }
-
- public function submit()
- {
- try {
- $this->validate();
- $tags = str($this->newTags)->trim()->explode(' ');
- foreach ($tags as $tag) {
- $tag = strip_tags($tag);
- if (strlen($tag) < 2) {
- $this->dispatch('error', 'Invalid tag.', "Tag $tag is invalid. Min length is 2.");
-
- continue;
- }
- if ($this->resource->tags()->where('name', $tag)->exists()) {
- $this->dispatch('error', 'Duplicate tags.', "Tag $tag already added.");
-
- continue;
- }
- $found = Tag::ownedByCurrentTeam()->where(['name' => $tag])->exists();
- if (! $found) {
- $found = Tag::create([
- 'name' => $tag,
- 'team_id' => currentTeam()->id,
- ]);
- }
- $this->resource->tags()->attach($found->id);
- }
- $this->refresh();
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function addTag(string $id, string $name)
- {
- try {
- $name = strip_tags($name);
- if ($this->resource->tags()->where('id', $id)->exists()) {
- $this->dispatch('error', 'Duplicate tags.', "Tag $name already added.");
-
- return;
- }
- $this->resource->tags()->attach($id);
- $this->refresh();
- $this->dispatch('success', 'Tag added.');
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function deleteTag(string $id)
- {
- try {
- $this->resource->tags()->detach($id);
- $found_more_tags = Tag::ownedByCurrentTeam()->find($id);
- if ($found_more_tags && $found_more_tags->applications()->count() == 0 && $found_more_tags->services()->count() == 0) {
- $found_more_tags->delete();
- }
- $this->refresh();
- $this->dispatch('success', 'Tag deleted.');
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function refresh()
- {
- $this->resource->refresh(); // Remove this when legacy_model_binding is false
- $this->loadTags();
- $this->reset('newTags');
- }
-}
diff --git a/app/Livewire/Project/Shared/Terminal.php b/app/Livewire/Project/Shared/Terminal.php
deleted file mode 100644
index a3d1aa10f5..0000000000
--- a/app/Livewire/Project/Shared/Terminal.php
+++ /dev/null
@@ -1,89 +0,0 @@
-user()->currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},ApplicationStatusChanged" => 'closeTerminal',
- ];
- }
-
- public function closeTerminal()
- {
- $this->dispatch('reloadWindow');
- }
-
- private function checkShellAvailability(Server $server, string $container): bool
- {
- $escapedContainer = escapeshellarg($container);
- try {
- instant_remote_process([
- "docker exec {$escapedContainer} bash -c 'exit 0' 2>/dev/null || ".
- "docker exec {$escapedContainer} sh -c 'exit 0' 2>/dev/null",
- ], $server);
-
- return true;
- } catch (\Throwable) {
- return false;
- }
- }
-
- #[On('send-terminal-command')]
- public function sendTerminalCommand($isContainer, $identifier, $serverUuid)
- {
- $server = Server::ownedByCurrentTeam()->whereUuid($serverUuid)->firstOrFail();
-
- if ($isContainer) {
- // Validate container identifier format (alphanumeric, dashes, and underscores only)
- if (! preg_match('/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/', $identifier)) {
- throw new \InvalidArgumentException('Invalid container identifier format');
- }
-
- // Verify container exists and belongs to the user's team
- $status = getContainerStatus($server, $identifier);
- if ($status !== 'running') {
- return;
- }
-
- // Check shell availability
- $this->hasShell = $this->checkShellAvailability($server, $identifier);
- if (! $this->hasShell) {
- return;
- }
-
- // Escape the identifier for shell usage
- $escapedIdentifier = escapeshellarg($identifier);
- $command = SshMultiplexingHelper::generateSshCommand($server, "docker exec -it {$escapedIdentifier} sh -c 'PATH=\$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && if [ -f ~/.profile ]; then . ~/.profile; fi && if [ -n \"\$SHELL\" ]; then exec \$SHELL; else sh; fi'");
- } else {
- $command = SshMultiplexingHelper::generateSshCommand($server, 'PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && if [ -f ~/.profile ]; then . ~/.profile; fi && if [ -n "$SHELL" ]; then exec $SHELL; else sh; fi');
- }
-
- // ssh command is sent back to frontend then to websocket
- // this is done because the websocket connection is not available here
- // a better solution would be to remove websocket on NodeJS and work with something like
- // 1. Laravel Pusher/Echo connection (not possible without a sdk)
- // 2. Ratchet / Revolt / ReactPHP / Event Loop (possible but hard to implement and huge dependencies)
- // 3. Just found out about this https://github.com/sirn-se/websocket-php, perhaps it can be used
- // 4. Follow-up discussions here:
- // - https://github.com/coollabsio/coolify/issues/2298
- // - https://github.com/coollabsio/coolify/discussions/3362
- $this->dispatch('send-back-command', $command);
- }
-
- public function render()
- {
- return view('livewire.project.shared.terminal');
- }
-}
diff --git a/app/Livewire/Project/Shared/UploadConfig.php b/app/Livewire/Project/Shared/UploadConfig.php
deleted file mode 100644
index 1b10f588b8..0000000000
--- a/app/Livewire/Project/Shared/UploadConfig.php
+++ /dev/null
@@ -1,46 +0,0 @@
-config = '{
- "build_pack": "nixpacks",
- "base_directory": "/nodejs",
- "publish_directory": "/",
- "ports_exposes": "3000",
- "settings": {
- "is_static": false
- }
-}';
- }
- }
-
- public function uploadConfig()
- {
- try {
- $application = Application::findOrFail($this->applicationId);
- $application->setConfig($this->config);
- $this->dispatch('success', 'Application settings updated');
- } catch (\Exception $e) {
- $this->dispatch('error', $e->getMessage());
-
- return;
- }
- }
-
- public function render()
- {
- return view('livewire.project.shared.upload-config');
- }
-}
diff --git a/app/Livewire/Project/Shared/Webhooks.php b/app/Livewire/Project/Shared/Webhooks.php
deleted file mode 100644
index 57c65c4dd2..0000000000
--- a/app/Livewire/Project/Shared/Webhooks.php
+++ /dev/null
@@ -1,62 +0,0 @@
-deploywebhook = generateDeployWebhook($this->resource);
-
- $this->githubManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_github');
- $this->githubManualWebhook = generateGitManualWebhook($this->resource, 'github');
-
- $this->gitlabManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_gitlab');
- $this->gitlabManualWebhook = generateGitManualWebhook($this->resource, 'gitlab');
-
- $this->bitbucketManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_bitbucket');
- $this->bitbucketManualWebhook = generateGitManualWebhook($this->resource, 'bitbucket');
-
- $this->giteaManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_gitea');
- $this->giteaManualWebhook = generateGitManualWebhook($this->resource, 'gitea');
- }
-
- public function submit()
- {
- try {
- $this->authorize('update', $this->resource);
- $this->resource->update([
- 'manual_webhook_secret_github' => $this->githubManualWebhookSecret,
- 'manual_webhook_secret_gitlab' => $this->gitlabManualWebhookSecret,
- 'manual_webhook_secret_bitbucket' => $this->bitbucketManualWebhookSecret,
- 'manual_webhook_secret_gitea' => $this->giteaManualWebhookSecret,
- ]);
- $this->dispatch('success', 'Secret Saved.');
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Project/Show.php b/app/Livewire/Project/Show.php
deleted file mode 100644
index 886a20218f..0000000000
--- a/app/Livewire/Project/Show.php
+++ /dev/null
@@ -1,61 +0,0 @@
-project = Project::where('team_id', currentTeam()->id)->where('uuid', $project_uuid)->firstOrFail();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- $this->validate();
- $environment = Environment::create([
- 'name' => $this->name,
- 'project_id' => $this->project->id,
- 'uuid' => (string) new Cuid2,
- ]);
-
- return redirect()->route('project.resource.index', [
- 'project_uuid' => $this->project->uuid,
- 'environment_uuid' => $environment->uuid,
- ]);
- } catch (\Throwable $e) {
- handleError($e, $this);
- }
- }
-
- public function navigateToEnvironment($projectUuid, $environmentUuid)
- {
- return redirect()->route('project.resource.index', [
- 'project_uuid' => $projectUuid,
- 'environment_uuid' => $environmentUuid,
- ]);
- }
-
- public function render()
- {
- return view('livewire.project.show');
- }
-}
diff --git a/app/Livewire/Security/ApiTokens.php b/app/Livewire/Security/ApiTokens.php
deleted file mode 100644
index 72684bdc63..0000000000
--- a/app/Livewire/Security/ApiTokens.php
+++ /dev/null
@@ -1,74 +0,0 @@
-isApiEnabled = InstanceSettings::get()->is_api_enabled;
- $this->getTokens();
- }
-
- private function getTokens()
- {
- $this->tokens = auth()->user()->tokens->sortByDesc('created_at');
- }
-
- public function updatedPermissions($permissionToUpdate)
- {
- if ($permissionToUpdate == 'root') {
- $this->permissions = ['root'];
- } elseif ($permissionToUpdate == 'read:sensitive' && ! in_array('read', $this->permissions)) {
- $this->permissions[] = 'read';
- } elseif ($permissionToUpdate == 'deploy') {
- $this->permissions = ['deploy'];
- } else {
- if (count($this->permissions) == 0) {
- $this->permissions = ['read'];
- }
- }
- sort($this->permissions);
- }
-
- public function addNewToken()
- {
- try {
- $this->validate([
- 'description' => 'required|min:3|max:255',
- ]);
- $token = auth()->user()->createToken($this->description, array_values($this->permissions));
- $this->getTokens();
- session()->flash('token', $token->plainTextToken);
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function revoke(int $id)
- {
- try {
- $token = auth()->user()->tokens()->where('id', $id)->firstOrFail();
- $token->delete();
- $this->getTokens();
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Security/PrivateKey/Create.php b/app/Livewire/Security/PrivateKey/Create.php
deleted file mode 100644
index 319cec1926..0000000000
--- a/app/Livewire/Security/PrivateKey/Create.php
+++ /dev/null
@@ -1,90 +0,0 @@
- 'required|string',
- 'value' => 'required|string',
- ];
-
- public function generateNewRSAKey()
- {
- $this->generateNewKey('rsa');
- }
-
- public function generateNewEDKey()
- {
- $this->generateNewKey('ed25519');
- }
-
- private function generateNewKey($type)
- {
- $keyData = PrivateKey::generateNewKeyPair($type);
- $this->setKeyData($keyData);
- }
-
- public function updated($property)
- {
- if ($property === 'value') {
- $this->validatePrivateKey();
- }
- }
-
- public function createPrivateKey()
- {
- $this->validate();
-
- try {
- $privateKey = PrivateKey::createAndStore([
- 'name' => $this->name,
- 'description' => $this->description,
- 'private_key' => trim($this->value)."\n",
- 'team_id' => currentTeam()->id,
- ]);
-
- return $this->redirectAfterCreation($privateKey);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- private function setKeyData(array $keyData)
- {
- $this->name = $keyData['name'];
- $this->description = $keyData['description'];
- $this->value = $keyData['private_key'];
- $this->publicKey = $keyData['public_key'];
- }
-
- private function validatePrivateKey()
- {
- $validationResult = PrivateKey::validateAndExtractPublicKey($this->value);
- $this->publicKey = $validationResult['publicKey'];
-
- if (! $validationResult['isValid']) {
- $this->addError('value', 'Invalid private key');
- }
- }
-
- private function redirectAfterCreation(PrivateKey $privateKey)
- {
- return $this->from === 'server'
- ? redirect()->route('dashboard')
- : redirect()->route('security.private-key.show', ['private_key_uuid' => $privateKey->uuid]);
- }
-}
diff --git a/app/Livewire/Security/PrivateKey/Index.php b/app/Livewire/Security/PrivateKey/Index.php
deleted file mode 100644
index 76441a67e5..0000000000
--- a/app/Livewire/Security/PrivateKey/Index.php
+++ /dev/null
@@ -1,24 +0,0 @@
-get();
-
- return view('livewire.security.private-key.index', [
- 'privateKeys' => $privateKeys,
- ])->layout('components.layout');
- }
-
- public function cleanupUnusedKeys()
- {
- PrivateKey::cleanupUnusedKeys();
- $this->dispatch('success', 'Unused keys have been cleaned up.');
- }
-}
diff --git a/app/Livewire/Security/PrivateKey/Show.php b/app/Livewire/Security/PrivateKey/Show.php
deleted file mode 100644
index b9195b5430..0000000000
--- a/app/Livewire/Security/PrivateKey/Show.php
+++ /dev/null
@@ -1,70 +0,0 @@
- 'required|string',
- 'private_key.description' => 'nullable|string',
- 'private_key.private_key' => 'required|string',
- 'private_key.is_git_related' => 'nullable|boolean',
- ];
-
- protected $validationAttributes = [
- 'private_key.name' => 'name',
- 'private_key.description' => 'description',
- 'private_key.private_key' => 'private key',
- ];
-
- public function mount()
- {
- try {
- $this->private_key = PrivateKey::ownedByCurrentTeam(['name', 'description', 'private_key', 'is_git_related'])->whereUuid(request()->private_key_uuid)->firstOrFail();
- } catch (\Throwable) {
- abort(404);
- }
- }
-
- public function loadPublicKey()
- {
- $this->public_key = $this->private_key->getPublicKey();
- if ($this->public_key === 'Error loading private key') {
- $this->dispatch('error', 'Failed to load public key. The private key may be invalid.');
- }
- }
-
- public function delete()
- {
- try {
- $this->private_key->safeDelete();
- currentTeam()->privateKeys = PrivateKey::where('team_id', currentTeam()->id)->get();
-
- return redirect()->route('security.private-key.index');
- } catch (\Exception $e) {
- $this->dispatch('error', $e->getMessage());
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function changePrivateKey()
- {
- try {
- $this->private_key->updatePrivateKey([
- 'private_key' => formatPrivateKey($this->private_key->private_key),
- ]);
- refresh_server_connection($this->private_key);
- $this->dispatch('success', 'Private key updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Server/Advanced.php b/app/Livewire/Server/Advanced.php
deleted file mode 100644
index b269c916f9..0000000000
--- a/app/Livewire/Server/Advanced.php
+++ /dev/null
@@ -1,83 +0,0 @@
-server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
- $this->parameters = get_route_parameters();
- $this->syncData();
- } catch (\Throwable) {
- return redirect()->route('server.index');
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->server->settings->concurrent_builds = $this->concurrentBuilds;
- $this->server->settings->dynamic_timeout = $this->dynamicTimeout;
- $this->server->settings->server_disk_usage_notification_threshold = $this->serverDiskUsageNotificationThreshold;
- $this->server->settings->server_disk_usage_check_frequency = $this->serverDiskUsageCheckFrequency;
- $this->server->settings->save();
- } else {
- $this->concurrentBuilds = $this->server->settings->concurrent_builds;
- $this->dynamicTimeout = $this->server->settings->dynamic_timeout;
- $this->serverDiskUsageNotificationThreshold = $this->server->settings->server_disk_usage_notification_threshold;
- $this->serverDiskUsageCheckFrequency = $this->server->settings->server_disk_usage_check_frequency;
- }
- }
-
- public function instantSave()
- {
- try {
- $this->syncData(true);
- $this->dispatch('success', 'Server updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- if (! validate_cron_expression($this->serverDiskUsageCheckFrequency)) {
- $this->serverDiskUsageCheckFrequency = $this->server->settings->getOriginal('server_disk_usage_check_frequency');
- throw new \Exception('Invalid Cron / Human expression for Disk Usage Check Frequency.');
- }
- $this->syncData(true);
- $this->dispatch('success', 'Server updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.advanced');
- }
-}
diff --git a/app/Livewire/Server/Charts.php b/app/Livewire/Server/Charts.php
deleted file mode 100644
index d0db87f577..0000000000
--- a/app/Livewire/Server/Charts.php
+++ /dev/null
@@ -1,64 +0,0 @@
-server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function pollData()
- {
- if ($this->poll || $this->interval <= 10) {
- $this->loadData();
- if ($this->interval > 10) {
- $this->poll = false;
- }
- }
- }
-
- public function loadData()
- {
- try {
- $cpuMetrics = $this->server->getCpuMetrics($this->interval);
- $memoryMetrics = $this->server->getMemoryMetrics($this->interval);
- $this->dispatch("refreshChartData-{$this->chartId}-cpu", [
- 'seriesData' => $cpuMetrics,
- ]);
- $this->dispatch("refreshChartData-{$this->chartId}-memory", [
- 'seriesData' => $memoryMetrics,
- ]);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function setInterval()
- {
- if ($this->interval <= 10) {
- $this->poll = true;
- }
- $this->loadData();
- }
-}
diff --git a/app/Livewire/Server/CloudflareTunnels.php b/app/Livewire/Server/CloudflareTunnels.php
deleted file mode 100644
index f69fc86557..0000000000
--- a/app/Livewire/Server/CloudflareTunnels.php
+++ /dev/null
@@ -1,54 +0,0 @@
-server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
- if ($this->server->isLocalhost()) {
- return redirect()->route('server.show', ['server_uuid' => $server_uuid]);
- }
- $this->isCloudflareTunnelsEnabled = $this->server->settings->is_cloudflare_tunnel;
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSave()
- {
- try {
- $this->validate();
- $this->server->settings->is_cloudflare_tunnel = $this->isCloudflareTunnelsEnabled;
- $this->server->settings->save();
- $this->dispatch('success', 'Server updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function manualCloudflareConfig()
- {
- $this->isCloudflareTunnelsEnabled = true;
- $this->server->settings->is_cloudflare_tunnel = true;
- $this->server->settings->save();
- $this->server->refresh();
- $this->dispatch('success', 'Cloudflare Tunnels enabled.');
- }
-
- public function render()
- {
- return view('livewire.server.cloudflare-tunnels');
- }
-}
diff --git a/app/Livewire/Server/ConfigureCloudflareTunnels.php b/app/Livewire/Server/ConfigureCloudflareTunnels.php
deleted file mode 100644
index f27614aa4c..0000000000
--- a/app/Livewire/Server/ConfigureCloudflareTunnels.php
+++ /dev/null
@@ -1,54 +0,0 @@
-where('id', $this->server_id)->firstOrFail();
- $server->settings->is_cloudflare_tunnel = true;
- $server->settings->save();
- $this->dispatch('success', 'Cloudflare Tunnels configured successfully.');
- $this->dispatch('refreshServerShow');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- if (str($this->ssh_domain)->contains('https://')) {
- $this->ssh_domain = str($this->ssh_domain)->replace('https://', '')->replace('http://', '')->trim();
- // remove / from the end
- $this->ssh_domain = str($this->ssh_domain)->replace('/', '');
- }
- $server = Server::ownedByCurrentTeam()->where('id', $this->server_id)->firstOrFail();
- ConfigureCloudflared::dispatch($server, $this->cloudflare_token);
- $server->settings->is_cloudflare_tunnel = true;
- $server->ip = $this->ssh_domain;
- $server->save();
- $server->settings->save();
- $this->dispatch('info', 'Cloudflare Tunnels configuration started.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.configure-cloudflare-tunnels');
- }
-}
diff --git a/app/Livewire/Server/Create.php b/app/Livewire/Server/Create.php
deleted file mode 100644
index 2d4ba4430c..0000000000
--- a/app/Livewire/Server/Create.php
+++ /dev/null
@@ -1,30 +0,0 @@
-private_keys = PrivateKey::ownedByCurrentTeam()->get();
- if (! isCloud()) {
- $this->limit_reached = false;
-
- return;
- }
- $this->limit_reached = Team::serverLimitReached();
- }
-
- public function render()
- {
- return view('livewire.server.create');
- }
-}
diff --git a/app/Livewire/Server/Delete.php b/app/Livewire/Server/Delete.php
deleted file mode 100644
index b9e3944b54..0000000000
--- a/app/Livewire/Server/Delete.php
+++ /dev/null
@@ -1,57 +0,0 @@
-server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function delete($password)
- {
- if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return;
- }
- }
- try {
- $this->authorize('delete', $this->server);
- if ($this->server->hasDefinedResources()) {
- $this->dispatch('error', 'Server has defined resources. Please delete them first.');
-
- return;
- }
- $this->server->delete();
- DeleteServer::dispatch($this->server);
-
- return redirect()->route('server.index');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.delete');
- }
-}
diff --git a/app/Livewire/Server/Destinations.php b/app/Livewire/Server/Destinations.php
deleted file mode 100644
index dbab6e03f0..0000000000
--- a/app/Livewire/Server/Destinations.php
+++ /dev/null
@@ -1,90 +0,0 @@
-networks = collect();
- $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- private function createNetworkAndAttachToProxy()
- {
- $connectProxyToDockerNetworks = connectProxyToNetworks($this->server);
- instant_remote_process($connectProxyToDockerNetworks, $this->server, false);
- }
-
- public function add($name)
- {
- if ($this->server->isSwarm()) {
- $found = $this->server->swarmDockers()->where('network', $name)->first();
- if ($found) {
- $this->dispatch('error', 'Network already added to this server.');
-
- return;
- } else {
- SwarmDocker::create([
- 'name' => $this->server->name.'-'.$name,
- 'network' => $this->name,
- 'server_id' => $this->server->id,
- ]);
- }
- } else {
- $found = $this->server->standaloneDockers()->where('network', $name)->first();
- if ($found) {
- $this->dispatch('error', 'Network already added to this server.');
-
- return;
- } else {
- StandaloneDocker::create([
- 'name' => $this->server->name.'-'.$name,
- 'network' => $name,
- 'server_id' => $this->server->id,
- ]);
- }
- $this->createNetworkAndAttachToProxy();
- }
- }
-
- public function scan()
- {
- if ($this->server->isSwarm()) {
- $alreadyAddedNetworks = $this->server->swarmDockers;
- } else {
- $alreadyAddedNetworks = $this->server->standaloneDockers;
- }
- $networks = instant_remote_process(['docker network ls --format "{{json .}}"'], $this->server, false);
- $this->networks = format_docker_command_output_to_json($networks)->filter(function ($network) {
- return $network['Name'] !== 'bridge' && $network['Name'] !== 'host' && $network['Name'] !== 'none';
- })->filter(function ($network) use ($alreadyAddedNetworks) {
- return ! $alreadyAddedNetworks->contains('network', $network['Name']);
- });
- if ($this->networks->count() === 0) {
- $this->dispatch('success', 'No new destinations found on this server.');
-
- return;
- }
- $this->dispatch('success', 'Scan done.');
- }
-
- public function render()
- {
- return view('livewire.server.destinations');
- }
-}
diff --git a/app/Livewire/Server/DockerCleanup.php b/app/Livewire/Server/DockerCleanup.php
deleted file mode 100644
index d3378d63f6..0000000000
--- a/app/Livewire/Server/DockerCleanup.php
+++ /dev/null
@@ -1,99 +0,0 @@
-server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
- $this->parameters = get_route_parameters();
- $this->syncData();
- } catch (\Throwable) {
- return redirect()->route('server.index');
- }
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->server->settings->force_docker_cleanup = $this->forceDockerCleanup;
- $this->server->settings->docker_cleanup_frequency = $this->dockerCleanupFrequency;
- $this->server->settings->docker_cleanup_threshold = $this->dockerCleanupThreshold;
- $this->server->settings->delete_unused_volumes = $this->deleteUnusedVolumes;
- $this->server->settings->delete_unused_networks = $this->deleteUnusedNetworks;
- $this->server->settings->save();
- } else {
- $this->forceDockerCleanup = $this->server->settings->force_docker_cleanup;
- $this->dockerCleanupFrequency = $this->server->settings->docker_cleanup_frequency;
- $this->dockerCleanupThreshold = $this->server->settings->docker_cleanup_threshold;
- $this->deleteUnusedVolumes = $this->server->settings->delete_unused_volumes;
- $this->deleteUnusedNetworks = $this->server->settings->delete_unused_networks;
- }
- }
-
- public function instantSave()
- {
- try {
- $this->syncData(true);
- $this->dispatch('success', 'Server updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function manualCleanup()
- {
- try {
- DockerCleanupJob::dispatch($this->server, true);
- $this->dispatch('success', 'Manual cleanup job started. Depending on the amount of data, this might take a while.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- if (! validate_cron_expression($this->dockerCleanupFrequency)) {
- $this->dockerCleanupFrequency = $this->server->settings->getOriginal('docker_cleanup_frequency');
- throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency.');
- }
- $this->syncData(true);
- $this->dispatch('success', 'Server updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.docker-cleanup');
- }
-}
diff --git a/app/Livewire/Server/DockerCleanupExecutions.php b/app/Livewire/Server/DockerCleanupExecutions.php
deleted file mode 100644
index 56d6130644..0000000000
--- a/app/Livewire/Server/DockerCleanupExecutions.php
+++ /dev/null
@@ -1,132 +0,0 @@
-user()->currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},DockerCleanupDone" => 'refreshExecutions',
- ];
- }
-
- public function mount(Server $server)
- {
- $this->server = $server;
- $this->refreshExecutions();
- }
-
- public function refreshExecutions(): void
- {
- $this->executions = $this->server->dockerCleanupExecutions()
- ->orderBy('created_at', 'desc')
- ->take(20)
- ->get();
-
- if ($this->selectedKey) {
- $this->selectedExecution = DockerCleanupExecution::find($this->selectedKey);
- if ($this->selectedExecution && $this->selectedExecution->status !== 'running') {
- $this->isPollingActive = false;
- }
- }
- }
-
- public function selectExecution($key): void
- {
- if ($key == $this->selectedKey) {
- $this->selectedKey = null;
- $this->selectedExecution = null;
- $this->currentPage = 1;
- $this->isPollingActive = false;
-
- return;
- }
- $this->selectedKey = $key;
- $this->selectedExecution = DockerCleanupExecution::find($key);
- $this->currentPage = 1;
-
- if ($this->selectedExecution && $this->selectedExecution->status === 'running') {
- $this->isPollingActive = true;
- }
- }
-
- public function polling()
- {
- if ($this->selectedExecution && $this->isPollingActive) {
- $this->selectedExecution->refresh();
- if ($this->selectedExecution->status !== 'running') {
- $this->isPollingActive = false;
- }
- }
- $this->refreshExecutions();
- }
-
- public function loadMoreLogs()
- {
- $this->currentPage++;
- }
-
- public function getLogLinesProperty()
- {
- if (! $this->selectedExecution) {
- return collect();
- }
-
- if (! $this->selectedExecution->message) {
- return collect(['Waiting for execution output...']);
- }
-
- $lines = collect(explode("\n", $this->selectedExecution->message));
-
- return $lines->take($this->currentPage * $this->logsPerPage);
- }
-
- public function downloadLogs(int $executionId)
- {
- $execution = $this->executions->firstWhere('id', $executionId);
- if (! $execution) {
- return;
- }
-
- return response()->streamDownload(function () use ($execution) {
- echo $execution->message;
- }, "docker-cleanup-{$execution->uuid}.log");
- }
-
- public function hasMoreLogs()
- {
- if (! $this->selectedExecution || ! $this->selectedExecution->message) {
- return false;
- }
- $lines = collect(explode("\n", $this->selectedExecution->message));
-
- return $lines->count() > ($this->currentPage * $this->logsPerPage);
- }
-
- public function render()
- {
- return view('livewire.server.docker-cleanup-executions');
- }
-}
diff --git a/app/Livewire/Server/Index.php b/app/Livewire/Server/Index.php
deleted file mode 100644
index 74764960ae..0000000000
--- a/app/Livewire/Server/Index.php
+++ /dev/null
@@ -1,22 +0,0 @@
-servers = Server::ownedByCurrentTeam()->get();
- }
-
- public function render()
- {
- return view('livewire.server.index');
- }
-}
diff --git a/app/Livewire/Server/LogDrains.php b/app/Livewire/Server/LogDrains.php
deleted file mode 100644
index edddfc7557..0000000000
--- a/app/Livewire/Server/LogDrains.php
+++ /dev/null
@@ -1,190 +0,0 @@
-server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
- $this->syncData();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function syncDataNewRelic(bool $toModel = false)
- {
- if ($toModel) {
- $this->server->settings->is_logdrain_newrelic_enabled = $this->isLogDrainNewRelicEnabled;
- $this->server->settings->logdrain_newrelic_license_key = $this->logDrainNewRelicLicenseKey;
- $this->server->settings->logdrain_newrelic_base_uri = $this->logDrainNewRelicBaseUri;
- } else {
- $this->isLogDrainNewRelicEnabled = $this->server->settings->is_logdrain_newrelic_enabled;
- $this->logDrainNewRelicLicenseKey = $this->server->settings->logdrain_newrelic_license_key;
- $this->logDrainNewRelicBaseUri = $this->server->settings->logdrain_newrelic_base_uri;
- }
- }
-
- public function syncDataAxiom(bool $toModel = false)
- {
- if ($toModel) {
- $this->server->settings->is_logdrain_axiom_enabled = $this->isLogDrainAxiomEnabled;
- $this->server->settings->logdrain_axiom_dataset_name = $this->logDrainAxiomDatasetName;
- $this->server->settings->logdrain_axiom_api_key = $this->logDrainAxiomApiKey;
- } else {
- $this->isLogDrainAxiomEnabled = $this->server->settings->is_logdrain_axiom_enabled;
- $this->logDrainAxiomDatasetName = $this->server->settings->logdrain_axiom_dataset_name;
- $this->logDrainAxiomApiKey = $this->server->settings->logdrain_axiom_api_key;
- }
- }
-
- public function syncDataCustom(bool $toModel = false)
- {
- if ($toModel) {
- $this->server->settings->is_logdrain_custom_enabled = $this->isLogDrainCustomEnabled;
- $this->server->settings->logdrain_custom_config = $this->logDrainCustomConfig;
- $this->server->settings->logdrain_custom_config_parser = $this->logDrainCustomConfigParser;
- } else {
- $this->isLogDrainCustomEnabled = $this->server->settings->is_logdrain_custom_enabled;
- $this->logDrainCustomConfig = $this->server->settings->logdrain_custom_config;
- $this->logDrainCustomConfigParser = $this->server->settings->logdrain_custom_config_parser;
- }
- }
-
- public function syncData(bool $toModel = false, ?string $type = null)
- {
- if ($toModel) {
- $this->customValidation();
- if ($type === 'newrelic') {
- $this->syncDataNewRelic($toModel);
- } elseif ($type === 'axiom') {
- $this->syncDataAxiom($toModel);
- } elseif ($type === 'custom') {
- $this->syncDataCustom($toModel);
- } else {
- $this->syncDataNewRelic($toModel);
- $this->syncDataAxiom($toModel);
- $this->syncDataCustom($toModel);
- }
- $this->server->settings->save();
- } else {
- if ($type === 'newrelic') {
- $this->syncDataNewRelic($toModel);
- } elseif ($type === 'axiom') {
- $this->syncDataAxiom($toModel);
- } elseif ($type === 'custom') {
- $this->syncDataCustom($toModel);
- } else {
- $this->syncDataNewRelic($toModel);
- $this->syncDataAxiom($toModel);
- $this->syncDataCustom($toModel);
- }
- }
- }
-
- public function customValidation()
- {
- if ($this->isLogDrainNewRelicEnabled) {
- try {
- $this->validate([
- 'logDrainNewRelicLicenseKey' => ['required'],
- 'logDrainNewRelicBaseUri' => ['required', 'url'],
- ]);
- } catch (\Throwable $e) {
- $this->isLogDrainNewRelicEnabled = false;
-
- throw $e;
- }
- } elseif ($this->isLogDrainAxiomEnabled) {
- try {
- $this->validate([
- 'logDrainAxiomDatasetName' => ['required'],
- 'logDrainAxiomApiKey' => ['required'],
- ]);
- } catch (\Throwable $e) {
- $this->isLogDrainAxiomEnabled = false;
-
- throw $e;
- }
- } elseif ($this->isLogDrainCustomEnabled) {
- try {
- $this->validate([
- 'logDrainCustomConfig' => ['required'],
- 'logDrainCustomConfigParser' => ['string', 'nullable'],
- ]);
- } catch (\Throwable $e) {
- $this->isLogDrainCustomEnabled = false;
-
- throw $e;
- }
- }
- }
-
- public function instantSave()
- {
- try {
- $this->syncData(true);
- if ($this->server->isLogDrainEnabled()) {
- StartLogDrain::run($this->server);
- $this->dispatch('success', 'Log drain service started.');
- } else {
- StopLogDrain::run($this->server);
- $this->dispatch('success', 'Log drain service stopped.');
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit(string $type)
- {
- try {
- $this->syncData(true, $type);
- $this->dispatch('success', 'Settings saved.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.log-drains');
- }
-}
diff --git a/app/Livewire/Server/New/ByIp.php b/app/Livewire/Server/New/ByIp.php
deleted file mode 100644
index 5f60c5db5e..0000000000
--- a/app/Livewire/Server/New/ByIp.php
+++ /dev/null
@@ -1,133 +0,0 @@
-name = generate_random_name();
- $this->private_key_id = $this->private_keys->first()?->id;
- $this->swarm_managers = Server::isUsable()->get()->where('settings.is_swarm_manager', true);
- if ($this->swarm_managers->count() > 0) {
- $this->selected_swarm_cluster = $this->swarm_managers->first()->id;
- }
- }
-
- public function setPrivateKey(string $private_key_id)
- {
- $this->private_key_id = $private_key_id;
- }
-
- public function instantSave()
- {
- // $this->dispatch('success', 'Application settings updated!');
- }
-
- public function submit()
- {
- $this->validate();
- try {
- if (Server::where('team_id', currentTeam()->id)
- ->where('ip', $this->ip)
- ->exists()) {
- return $this->dispatch('error', 'This IP/Domain is already in use by another server in your team.');
- }
-
- if (is_null($this->private_key_id)) {
- return $this->dispatch('error', 'You must select a private key');
- }
- if (Team::serverLimitReached()) {
- return $this->dispatch('error', 'You have reached the server limit for your subscription.');
- }
- $payload = [
- 'name' => $this->name,
- 'description' => $this->description,
- 'ip' => $this->ip,
- 'user' => $this->user,
- 'port' => $this->port,
- 'team_id' => currentTeam()->id,
- 'private_key_id' => $this->private_key_id,
- ];
- if ($this->is_swarm_worker) {
- $payload['swarm_cluster'] = $this->selected_swarm_cluster;
- }
- if ($this->is_build_server) {
- data_forget($payload, 'proxy');
- }
- $server = Server::create($payload);
- $server->proxy->set('status', 'exited');
- $server->proxy->set('type', ProxyTypes::TRAEFIK->value);
- $server->save();
- if ($this->is_build_server) {
- $this->is_swarm_manager = false;
- $this->is_swarm_worker = false;
- } else {
- $server->settings->is_swarm_manager = $this->is_swarm_manager;
- $server->settings->is_swarm_worker = $this->is_swarm_worker;
- }
- $server->settings->is_build_server = $this->is_build_server;
- $server->settings->save();
-
- return redirect()->route('server.show', $server->uuid);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Server/PrivateKey/Show.php b/app/Livewire/Server/PrivateKey/Show.php
deleted file mode 100644
index 64aa1884ba..0000000000
--- a/app/Livewire/Server/PrivateKey/Show.php
+++ /dev/null
@@ -1,72 +0,0 @@
-server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
- $this->privateKeys = PrivateKey::ownedByCurrentTeam()->get()->where('is_git_related', false);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function setPrivateKey($privateKeyId)
- {
- $ownedPrivateKey = PrivateKey::ownedByCurrentTeam()->find($privateKeyId);
- if (is_null($ownedPrivateKey)) {
- $this->dispatch('error', 'You are not allowed to use this private key.');
-
- return;
- }
-
- $originalPrivateKeyId = $this->server->getOriginal('private_key_id');
- try {
- $this->server->update(['private_key_id' => $privateKeyId]);
- ['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection(justCheckingNewKey: true);
- if ($uptime) {
- $this->dispatch('success', 'Private key updated successfully.');
- } else {
- throw new \Exception($error);
- }
- } catch (\Exception $e) {
- $this->server->update(['private_key_id' => $originalPrivateKeyId]);
- $this->server->validateConnection();
- $this->dispatch('error', $e->getMessage());
- }
- }
-
- public function checkConnection()
- {
- try {
- ['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
- if ($uptime) {
- $this->dispatch('success', 'Server is reachable.');
- } else {
- $this->dispatch('error', 'Server is not reachable. Check this documentation for further help. Error: '.$error);
-
- return;
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.private-key.show');
- }
-}
diff --git a/app/Livewire/Server/Proxy.php b/app/Livewire/Server/Proxy.php
deleted file mode 100644
index 4e325c1ff6..0000000000
--- a/app/Livewire/Server/Proxy.php
+++ /dev/null
@@ -1,119 +0,0 @@
- 'submit'];
-
- protected $rules = [
- 'server.settings.generate_exact_labels' => 'required|boolean',
- ];
-
- public function mount()
- {
- $this->selectedProxy = $this->server->proxyType();
- $this->redirect_enabled = data_get($this->server, 'proxy.redirect_enabled', true);
- $this->redirect_url = data_get($this->server, 'proxy.redirect_url');
- }
-
- public function proxyStatusUpdated()
- {
- $this->dispatch('refresh')->self();
- }
-
- public function changeProxy()
- {
- $this->server->proxy = null;
- $this->server->save();
- $this->dispatch('reloadWindow');
- }
-
- public function selectProxy($proxy_type)
- {
- try {
- $this->server->changeProxy($proxy_type, async: false);
- $this->selectedProxy = $this->server->proxy->type;
- $this->dispatch('reloadWindow');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSave()
- {
- try {
- $this->validate();
- $this->server->settings->save();
- $this->dispatch('success', 'Settings saved.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSaveRedirect()
- {
- try {
- $this->server->proxy->redirect_enabled = $this->redirect_enabled;
- $this->server->save();
- $this->server->setupDefaultRedirect();
- $this->dispatch('success', 'Proxy configuration saved.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- SaveConfiguration::run($this->server, $this->proxy_settings);
- $this->server->proxy->redirect_url = $this->redirect_url;
- $this->server->save();
- $this->server->setupDefaultRedirect();
- $this->dispatch('success', 'Proxy configuration saved.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function reset_proxy_configuration()
- {
- try {
- $this->proxy_settings = CheckConfiguration::run($this->server, true);
- SaveConfiguration::run($this->server, $this->proxy_settings);
- $this->server->save();
- $this->dispatch('success', 'Proxy configuration saved.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function loadProxyConfiguration()
- {
- try {
- $this->proxy_settings = CheckConfiguration::run($this->server);
- if (str($this->proxy_settings)->contains('--api.dashboard=true') && str($this->proxy_settings)->contains('--api.insecure=true')) {
- $this->dispatch('traefikDashboardAvailable', true);
- } else {
- $this->dispatch('traefikDashboardAvailable', false);
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Server/Proxy/Deploy.php b/app/Livewire/Server/Proxy/Deploy.php
deleted file mode 100644
index f823ff3d44..0000000000
--- a/app/Livewire/Server/Proxy/Deploy.php
+++ /dev/null
@@ -1,140 +0,0 @@
-user()->currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},ProxyStatusChanged" => 'proxyStarted',
- 'proxyStatusUpdated',
- 'traefikDashboardAvailable',
- 'serverRefresh' => 'proxyStatusUpdated',
- 'checkProxy',
- 'startProxy',
- 'proxyChanged' => 'proxyStatusUpdated',
- ];
- }
-
- public function mount()
- {
- if ($this->server->id === 0) {
- $this->serverIp = base_ip();
- } else {
- $this->serverIp = $this->server->ip;
- }
- $this->currentRoute = request()->route()->getName();
- }
-
- public function traefikDashboardAvailable(bool $data)
- {
- $this->traefikDashboardAvailable = $data;
- }
-
- public function proxyStarted()
- {
- CheckProxy::run($this->server, true);
- $this->dispatch('proxyStatusUpdated');
- }
-
- public function proxyStatusUpdated()
- {
- $this->server->refresh();
- }
-
- public function restart()
- {
- try {
- $this->stop();
- $this->dispatch('checkProxy');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function checkProxy()
- {
- try {
- CheckProxy::run($this->server, true);
- $this->dispatch('startProxyPolling');
- $this->dispatch('proxyChecked');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function startProxy()
- {
- try {
- $this->server->proxy->force_stop = false;
- $this->server->save();
- $activity = StartProxy::run($this->server, force: true);
- $this->dispatch('activityMonitor', $activity->id, ProxyStatusChanged::class);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function stop(bool $forceStop = true)
- {
- try {
- $containerName = $this->server->isSwarm() ? 'coolify-proxy_traefik' : 'coolify-proxy';
- $timeout = 30;
-
- $process = $this->stopContainer($containerName, $timeout);
-
- $startTime = Carbon::now()->getTimestamp();
- while ($process->running()) {
- if (Carbon::now()->getTimestamp() - $startTime >= $timeout) {
- $this->forceStopContainer($containerName);
- break;
- }
- usleep(100000);
- }
-
- $this->removeContainer($containerName);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- } finally {
- $this->server->proxy->force_stop = $forceStop;
- $this->server->proxy->status = 'exited';
- $this->server->save();
- $this->dispatch('proxyStatusUpdated');
- }
- }
-
- private function stopContainer(string $containerName, int $timeout): InvokedProcess
- {
- return Process::timeout($timeout)->start("docker stop --time=$timeout $containerName");
- }
-
- private function forceStopContainer(string $containerName)
- {
- instant_remote_process(["docker kill $containerName"], $this->server, throwError: false);
- }
-
- private function removeContainer(string $containerName)
- {
- instant_remote_process(["docker rm -f $containerName"], $this->server, throwError: false);
- }
-}
diff --git a/app/Livewire/Server/Proxy/DynamicConfigurationNavbar.php b/app/Livewire/Server/Proxy/DynamicConfigurationNavbar.php
deleted file mode 100644
index 392ad38fa9..0000000000
--- a/app/Livewire/Server/Proxy/DynamicConfigurationNavbar.php
+++ /dev/null
@@ -1,42 +0,0 @@
-whereId($this->server_id)->first();
- $proxy_path = $server->proxyPath();
- $proxy_type = $server->proxyType();
- $file = str_replace('|', '.', $fileName);
- if ($proxy_type === 'CADDY' && $file === 'Caddyfile') {
- $this->dispatch('error', 'Cannot delete Caddyfile.');
-
- return;
- }
- instant_remote_process(["rm -f {$proxy_path}/dynamic/{$file}"], $server);
- if ($proxy_type === 'CADDY') {
- $server->reloadCaddy();
- }
- $this->dispatch('success', 'File deleted.');
- $this->dispatch('loadDynamicConfigurations');
- $this->dispatch('refresh');
- }
-
- public function render()
- {
- return view('livewire.server.proxy.dynamic-configuration-navbar');
- }
-}
diff --git a/app/Livewire/Server/Proxy/DynamicConfigurations.php b/app/Livewire/Server/Proxy/DynamicConfigurations.php
deleted file mode 100644
index 6277a24bd4..0000000000
--- a/app/Livewire/Server/Proxy/DynamicConfigurations.php
+++ /dev/null
@@ -1,64 +0,0 @@
-user()->currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},ProxyStatusChanged" => 'loadDynamicConfigurations',
- 'loadDynamicConfigurations',
- ];
- }
-
- protected $rules = [
- 'contents.*' => 'nullable|string',
- ];
-
- public function loadDynamicConfigurations()
- {
- $proxy_path = $this->server->proxyPath();
- $files = instant_remote_process(["mkdir -p $proxy_path/dynamic && ls -1 {$proxy_path}/dynamic"], $this->server);
- $files = collect(explode("\n", $files))->filter(fn ($file) => ! empty($file));
- $files = $files->map(fn ($file) => trim($file));
- $files = $files->sort();
- $contents = collect([]);
- foreach ($files as $file) {
- $without_extension = str_replace('.', '|', $file);
- $contents[$without_extension] = instant_remote_process(["cat {$proxy_path}/dynamic/{$file}"], $this->server);
- }
- $this->contents = $contents;
- $this->dispatch('$refresh');
- }
-
- public function mount()
- {
- $this->parameters = get_route_parameters();
- try {
- $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
- if (is_null($this->server)) {
- return redirect()->route('server.index');
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.proxy.dynamic-configurations');
- }
-}
diff --git a/app/Livewire/Server/Proxy/Logs.php b/app/Livewire/Server/Proxy/Logs.php
deleted file mode 100644
index 8e0f40c54e..0000000000
--- a/app/Livewire/Server/Proxy/Logs.php
+++ /dev/null
@@ -1,31 +0,0 @@
-parameters = get_route_parameters();
- try {
- $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
- if (is_null($this->server)) {
- return redirect()->route('server.index');
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.proxy.logs');
- }
-}
diff --git a/app/Livewire/Server/Proxy/NewDynamicConfiguration.php b/app/Livewire/Server/Proxy/NewDynamicConfiguration.php
deleted file mode 100644
index 2155f1e82d..0000000000
--- a/app/Livewire/Server/Proxy/NewDynamicConfiguration.php
+++ /dev/null
@@ -1,97 +0,0 @@
-parameters = get_route_parameters();
- if ($this->fileName !== '') {
- $this->fileName = str_replace('|', '.', $this->fileName);
- }
- }
-
- public function addDynamicConfiguration()
- {
- try {
- $this->validate([
- 'fileName' => 'required',
- 'value' => 'required',
- ]);
- if (data_get($this->parameters, 'server_uuid')) {
- $this->server = Server::ownedByCurrentTeam()->whereUuid(data_get($this->parameters, 'server_uuid'))->first();
- }
- if (! is_null($this->server_id)) {
- $this->server = Server::ownedByCurrentTeam()->whereId($this->server_id)->first();
- }
- if (is_null($this->server)) {
- return redirect()->route('server.index');
- }
- $proxy_type = $this->server->proxyType();
- if ($proxy_type === ProxyTypes::TRAEFIK->value) {
- if (! str($this->fileName)->endsWith('.yaml') && ! str($this->fileName)->endsWith('.yml')) {
- $this->fileName = "{$this->fileName}.yaml";
- }
- if ($this->fileName === 'coolify.yaml') {
- $this->dispatch('error', 'File name is reserved.');
-
- return;
- }
- } elseif ($proxy_type === 'CADDY') {
- if (! str($this->fileName)->endsWith('.caddy')) {
- $this->fileName = "{$this->fileName}.caddy";
- }
- }
- $proxy_path = $this->server->proxyPath();
- $file = "{$proxy_path}/dynamic/{$this->fileName}";
- if ($this->newFile) {
- $exists = instant_remote_process(["test -f $file && echo 1 || echo 0"], $this->server);
- if ($exists == 1) {
- $this->dispatch('error', 'File already exists');
-
- return;
- }
- }
- if ($proxy_type === ProxyTypes::TRAEFIK->value) {
- $yaml = Yaml::parse($this->value);
- $yaml = Yaml::dump($yaml, 10, 2);
- $this->value = $yaml;
- }
- $base64_value = base64_encode($this->value);
- instant_remote_process([
- "echo '{$base64_value}' | base64 -d | tee {$file} > /dev/null",
- ], $this->server);
- if ($proxy_type === 'CADDY') {
- $this->server->reloadCaddy();
- }
- $this->dispatch('loadDynamicConfigurations');
- $this->dispatch('dynamic-configuration-added');
- $this->dispatch('success', 'Dynamic configuration saved.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.proxy.new-dynamic-configuration');
- }
-}
diff --git a/app/Livewire/Server/Proxy/Show.php b/app/Livewire/Server/Proxy/Show.php
deleted file mode 100644
index 5ecb56a691..0000000000
--- a/app/Livewire/Server/Proxy/Show.php
+++ /dev/null
@@ -1,35 +0,0 @@
- 'proxyStatusUpdated'];
-
- public function proxyStatusUpdated()
- {
- $this->server->refresh();
- }
-
- public function mount()
- {
- $this->parameters = get_route_parameters();
- try {
- $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->firstOrFail();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.proxy.show');
- }
-}
diff --git a/app/Livewire/Server/Proxy/Status.php b/app/Livewire/Server/Proxy/Status.php
deleted file mode 100644
index f4f18381f8..0000000000
--- a/app/Livewire/Server/Proxy/Status.php
+++ /dev/null
@@ -1,77 +0,0 @@
-checkProxy();
- }
-
- public function proxyStatusUpdated()
- {
- $this->server->refresh();
- }
-
- public function checkProxy(bool $notification = false)
- {
- try {
- if ($this->polling) {
- if ($this->numberOfPolls >= 10) {
- $this->polling = false;
- $this->numberOfPolls = 0;
- $notification && $this->dispatch('error', 'Proxy is not running.');
-
- return;
- }
- $this->numberOfPolls++;
- }
- $shouldStart = CheckProxy::run($this->server, true);
- if ($shouldStart) {
- StartProxy::run($this->server, false);
- }
- $this->dispatch('proxyStatusUpdated');
- if ($this->server->proxy->status === 'running') {
- $this->polling = false;
- $notification && $this->dispatch('success', 'Proxy is running.');
- } elseif ($this->server->proxy->status === 'exited' and ! $this->server->proxy->force_stop) {
- $notification && $this->dispatch('error', 'Proxy has exited.');
- } elseif ($this->server->proxy->force_stop) {
- $notification && $this->dispatch('error', 'Proxy is stopped manually.');
- } else {
- $notification && $this->dispatch('error', 'Proxy is not running.');
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function getProxyStatus()
- {
- try {
- GetContainersStatus::run($this->server);
- // dispatch_sync(new ContainerStatusJob($this->server));
- $this->dispatch('proxyStatusUpdated');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Server/Resources.php b/app/Livewire/Server/Resources.php
deleted file mode 100644
index f549b43cbd..0000000000
--- a/app/Livewire/Server/Resources.php
+++ /dev/null
@@ -1,102 +0,0 @@
-user()->currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},ApplicationStatusChanged" => 'refreshStatus',
- ];
- }
-
- public function startUnmanaged($id)
- {
- $this->server->startUnmanaged($id);
- $this->dispatch('success', 'Container started.');
- $this->loadUnmanagedContainers();
- }
-
- public function restartUnmanaged($id)
- {
- $this->server->restartUnmanaged($id);
- $this->dispatch('success', 'Container restarted.');
- $this->loadUnmanagedContainers();
- }
-
- public function stopUnmanaged($id)
- {
- $this->server->stopUnmanaged($id);
- $this->dispatch('success', 'Container stopped.');
- $this->loadUnmanagedContainers();
- }
-
- public function refreshStatus()
- {
- $this->server->refresh();
- if ($this->activeTab === 'managed') {
- $this->loadManagedContainers();
- } else {
- $this->loadUnmanagedContainers();
- }
- $this->dispatch('success', 'Resource statuses refreshed.');
- }
-
- public function loadManagedContainers()
- {
- try {
- $this->activeTab = 'managed';
- $this->containers = $this->server->refresh()->definedResources();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function loadUnmanagedContainers()
- {
- $this->activeTab = 'unmanaged';
- try {
- $this->containers = $this->server->loadUnmanagedContainers();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function mount()
- {
- $this->containers = collect();
- $this->parameters = get_route_parameters();
- try {
- $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
- if (is_null($this->server)) {
- return redirect()->route('server.index');
- }
- $this->loadManagedContainers();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.resources');
- }
-}
diff --git a/app/Livewire/Server/Show.php b/app/Livewire/Server/Show.php
deleted file mode 100644
index b0e6d88588..0000000000
--- a/app/Livewire/Server/Show.php
+++ /dev/null
@@ -1,282 +0,0 @@
-user()->currentTeam()->id;
-
- return [
- "echo-private:team.{$teamId},CloudflareTunnelConfigured" => 'refresh',
- 'refreshServerShow' => 'refresh',
- ];
- }
-
- public function mount(string $server_uuid)
- {
- try {
- $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
- $this->syncData();
- if (! $this->server->isEmpty()) {
- $this->isBuildServerLocked = true;
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- #[Computed]
- public function timezones(): array
- {
- return collect(timezone_identifiers_list())
- ->sort()
- ->values()
- ->toArray();
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
-
- if (Server::where('team_id', currentTeam()->id)
- ->where('ip', $this->ip)
- ->where('id', '!=', $this->server->id)
- ->exists()) {
- $this->ip = $this->server->ip;
- throw new \Exception('This IP/Domain is already in use by another server in your team.');
- }
-
- $this->server->name = $this->name;
- $this->server->description = $this->description;
- $this->server->ip = $this->ip;
- $this->server->user = $this->user;
- $this->server->port = $this->port;
- $this->server->validation_logs = $this->validationLogs;
- $this->server->save();
-
- $this->server->settings->is_swarm_manager = $this->isSwarmManager;
- $this->server->settings->wildcard_domain = $this->wildcardDomain;
- $this->server->settings->is_swarm_worker = $this->isSwarmWorker;
- $this->server->settings->is_build_server = $this->isBuildServer;
- $this->server->settings->is_metrics_enabled = $this->isMetricsEnabled;
- $this->server->settings->sentinel_token = $this->sentinelToken;
- $this->server->settings->sentinel_metrics_refresh_rate_seconds = $this->sentinelMetricsRefreshRateSeconds;
- $this->server->settings->sentinel_metrics_history_days = $this->sentinelMetricsHistoryDays;
- $this->server->settings->sentinel_push_interval_seconds = $this->sentinelPushIntervalSeconds;
- $this->server->settings->sentinel_custom_url = $this->sentinelCustomUrl;
- $this->server->settings->is_sentinel_enabled = $this->isSentinelEnabled;
- $this->server->settings->is_sentinel_debug_enabled = $this->isSentinelDebugEnabled;
-
- if (! validate_timezone($this->serverTimezone)) {
- $this->serverTimezone = config('app.timezone');
- throw new \Exception('Invalid timezone.');
- } else {
- $this->server->settings->server_timezone = $this->serverTimezone;
- }
-
- $this->server->settings->save();
- } else {
- $this->name = $this->server->name;
- $this->description = $this->server->description;
- $this->ip = $this->server->ip;
- $this->user = $this->server->user;
- $this->port = $this->server->port;
-
- $this->wildcardDomain = $this->server->settings->wildcard_domain;
- $this->isReachable = $this->server->settings->is_reachable;
- $this->isUsable = $this->server->settings->is_usable;
- $this->isSwarmManager = $this->server->settings->is_swarm_manager;
- $this->isSwarmWorker = $this->server->settings->is_swarm_worker;
- $this->isBuildServer = $this->server->settings->is_build_server;
- $this->isMetricsEnabled = $this->server->settings->is_metrics_enabled;
- $this->sentinelToken = $this->server->settings->sentinel_token;
- $this->sentinelMetricsRefreshRateSeconds = $this->server->settings->sentinel_metrics_refresh_rate_seconds;
- $this->sentinelMetricsHistoryDays = $this->server->settings->sentinel_metrics_history_days;
- $this->sentinelPushIntervalSeconds = $this->server->settings->sentinel_push_interval_seconds;
- $this->sentinelCustomUrl = $this->server->settings->sentinel_custom_url;
- $this->isSentinelEnabled = $this->server->settings->is_sentinel_enabled;
- $this->isSentinelDebugEnabled = $this->server->settings->is_sentinel_debug_enabled;
- $this->sentinelUpdatedAt = $this->server->settings->updated_at;
- $this->serverTimezone = $this->server->settings->server_timezone;
- }
- }
-
- public function refresh()
- {
- $this->syncData();
- $this->dispatch('$refresh');
- }
-
- public function validateServer($install = true)
- {
- try {
- $this->validationLogs = $this->server->validation_logs = null;
- $this->server->save();
- $this->dispatch('init', $install);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function checkLocalhostConnection()
- {
- $this->syncData(true);
- ['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
- if ($uptime) {
- $this->dispatch('success', 'Server is reachable.');
- $this->server->settings->is_reachable = $this->isReachable = true;
- $this->server->settings->is_usable = $this->isUsable = true;
- $this->server->settings->save();
- ServerReachabilityChanged::dispatch($this->server);
- $this->dispatch('proxyStatusUpdated');
- } else {
- $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection. Check this documentation for further help. Error: '.$error);
-
- return;
- }
- }
-
- public function restartSentinel()
- {
- $this->server->restartSentinel();
- $this->dispatch('success', 'Sentinel restarted.');
- }
-
- public function updatedIsSentinelDebugEnabled($value)
- {
- $this->submit();
- $this->restartSentinel();
- }
-
- public function updatedIsMetricsEnabled($value)
- {
- $this->submit();
- $this->restartSentinel();
- }
-
- public function updatedIsSentinelEnabled($value)
- {
- if ($value === true) {
- StartSentinel::run($this->server, true);
- } else {
- $this->isMetricsEnabled = false;
- $this->isSentinelDebugEnabled = false;
- StopSentinel::dispatch($this->server);
- }
- $this->submit();
-
- }
-
- public function regenerateSentinelToken()
- {
- try {
- $this->server->settings->generateSentinelToken();
- $this->dispatch('success', 'Token regenerated & Sentinel restarted.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSave()
- {
- $this->submit();
- }
-
- public function submit()
- {
- try {
- $this->syncData(true);
- $this->dispatch('success', 'Server updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.server.show');
- }
-}
diff --git a/app/Livewire/Server/ValidateAndInstall.php b/app/Livewire/Server/ValidateAndInstall.php
deleted file mode 100644
index 791ef93501..0000000000
--- a/app/Livewire/Server/ValidateAndInstall.php
+++ /dev/null
@@ -1,182 +0,0 @@
- '$refresh',
- ];
-
- public function init(int $data = 0)
- {
- $this->uptime = null;
- $this->supported_os_type = null;
- $this->docker_installed = null;
- $this->docker_version = null;
- $this->docker_compose_installed = null;
- $this->proxy_started = null;
- $this->error = null;
- $this->number_of_tries = $data;
- if (! $this->ask) {
- $this->dispatch('validateConnection');
- }
- }
-
- public function startValidatingAfterAsking()
- {
- $this->ask = false;
- $this->init();
- }
-
- public function startProxy()
- {
- try {
- $shouldStart = CheckProxy::run($this->server);
- if ($shouldStart) {
- $proxy = StartProxy::run($this->server, false);
- if ($proxy === 'OK') {
- $this->proxy_started = true;
- } else {
- throw new \Exception('Proxy could not be started.');
- }
- } else {
- $this->proxy_started = true;
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function validateConnection()
- {
- ['uptime' => $this->uptime, 'error' => $error] = $this->server->validateConnection();
- if (! $this->uptime) {
- $this->error = 'Server is not reachable. Please validate your configuration and connection. Check this documentation for further help. Error: '.$error.'
';
- $this->server->update([
- 'validation_logs' => $this->error,
- ]);
-
- return;
- }
- $this->dispatch('validateOS');
- }
-
- public function validateOS()
- {
- $this->supported_os_type = $this->server->validateOS();
- if (! $this->supported_os_type) {
- $this->error = 'Server OS type is not supported. Please install Docker manually before continuing: documentation .';
- $this->server->update([
- 'validation_logs' => $this->error,
- ]);
-
- return;
- }
- $this->dispatch('validateDockerEngine');
- }
-
- public function validateDockerEngine()
- {
- $this->docker_installed = $this->server->validateDockerEngine();
- $this->docker_compose_installed = $this->server->validateDockerCompose();
- if (! $this->docker_installed || ! $this->docker_compose_installed) {
- if ($this->install) {
- if ($this->number_of_tries == $this->max_tries) {
- $this->error = 'Docker Engine could not be installed. Please install Docker manually before continuing: documentation .';
- $this->server->update([
- 'validation_logs' => $this->error,
- ]);
-
- return;
- } else {
- if ($this->number_of_tries <= $this->max_tries) {
- $activity = $this->server->installDocker();
- $this->number_of_tries++;
- $this->dispatch('newActivityMonitor', $activity->id, 'init', $this->number_of_tries);
- }
-
- return;
- }
- } else {
- $this->error = 'Docker Engine is not installed. Please install Docker manually before continuing: documentation .';
- $this->server->update([
- 'validation_logs' => $this->error,
- ]);
-
- return;
- }
- }
- $this->dispatch('validateDockerVersion');
- }
-
- public function validateDockerVersion()
- {
- if ($this->server->isSwarm()) {
- $swarmInstalled = $this->server->validateDockerSwarm();
- if ($swarmInstalled) {
- $this->dispatch('success', 'Docker Swarm is initiated.');
- }
- } else {
- $this->docker_version = $this->server->validateDockerEngineVersion();
- if ($this->docker_version) {
- $this->dispatch('refreshServerShow');
- $this->dispatch('refreshBoardingIndex');
- $this->dispatch('success', 'Server validated.');
- } else {
- $requiredDockerVersion = str(config('constants.docker.minimum_required_version'))->before('.');
- $this->error = 'Minimum Docker Engine version '.$requiredDockerVersion.' is not instaled. Please install Docker manually before continuing: documentation .';
- $this->server->update([
- 'validation_logs' => $this->error,
- ]);
-
- return;
- }
- }
-
- if ($this->server->isBuildServer()) {
- return;
- }
- $this->dispatch('startProxy');
- }
-
- public function render()
- {
- return view('livewire.server.validate-and-install');
- }
-}
diff --git a/app/Livewire/Settings/Index.php b/app/Livewire/Settings/Index.php
deleted file mode 100644
index 3d90024b7e..0000000000
--- a/app/Livewire/Settings/Index.php
+++ /dev/null
@@ -1,243 +0,0 @@
-route('dashboard');
- } else {
- $this->settings = instanceSettings();
- $this->fqdn = $this->settings->fqdn;
- $this->public_port_min = $this->settings->public_port_min;
- $this->public_port_max = $this->settings->public_port_max;
- $this->custom_dns_servers = $this->settings->custom_dns_servers;
- $this->instance_name = $this->settings->instance_name;
- $this->allowed_ips = $this->settings->allowed_ips;
- $this->public_ipv4 = $this->settings->public_ipv4;
- $this->public_ipv6 = $this->settings->public_ipv6;
- $this->do_not_track = $this->settings->do_not_track;
- $this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
- $this->is_registration_enabled = $this->settings->is_registration_enabled;
- $this->is_dns_validation_enabled = $this->settings->is_dns_validation_enabled;
- $this->is_api_enabled = $this->settings->is_api_enabled;
- $this->auto_update_frequency = $this->settings->auto_update_frequency;
- $this->update_check_frequency = $this->settings->update_check_frequency;
- $this->instance_timezone = $this->settings->instance_timezone;
- $this->disable_two_step_confirmation = $this->settings->disable_two_step_confirmation;
- }
- }
-
- #[Computed]
- public function timezones(): array
- {
- return collect(timezone_identifiers_list())
- ->sort()
- ->values()
- ->toArray();
- }
-
- public function instantSave($isSave = true)
- {
- $this->validate();
- if ($this->settings->is_auto_update_enabled === true) {
- $this->validate([
- 'auto_update_frequency' => ['required', 'string'],
- ]);
- }
-
- $this->settings->fqdn = $this->fqdn;
- $this->settings->public_port_min = $this->public_port_min;
- $this->settings->public_port_max = $this->public_port_max;
- $this->settings->custom_dns_servers = $this->custom_dns_servers;
- $this->settings->instance_name = $this->instance_name;
- $this->settings->allowed_ips = $this->allowed_ips;
- $this->settings->public_ipv4 = $this->public_ipv4;
- $this->settings->public_ipv6 = $this->public_ipv6;
- $this->settings->do_not_track = $this->do_not_track;
- $this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
- $this->settings->is_registration_enabled = $this->is_registration_enabled;
- $this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled;
- $this->settings->is_api_enabled = $this->is_api_enabled;
- $this->settings->auto_update_frequency = $this->auto_update_frequency;
- $this->settings->update_check_frequency = $this->update_check_frequency;
- $this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation;
- $this->settings->instance_timezone = $this->instance_timezone;
- if ($isSave) {
- $this->settings->save();
- $this->dispatch('success', 'Settings updated!');
- }
- }
-
- public function submit()
- {
- try {
- $error_show = false;
- $this->server = Server::findOrFail(0);
- $this->resetErrorBag();
-
- if (! validate_timezone($this->instance_timezone)) {
- $this->instance_timezone = config('app.timezone');
- throw new \Exception('Invalid timezone.');
- } else {
- $this->settings->instance_timezone = $this->instance_timezone;
- }
-
- if ($this->settings->public_port_min > $this->settings->public_port_max) {
- $this->addError('settings.public_port_min', 'The minimum port must be lower than the maximum port.');
-
- return;
- }
- $this->validate();
-
- if ($this->is_auto_update_enabled && ! validate_cron_expression($this->auto_update_frequency)) {
- $this->dispatch('error', 'Invalid Cron / Human expression for Auto Update Frequency.');
- if (empty($this->auto_update_frequency)) {
- $this->auto_update_frequency = '0 0 * * *';
- }
-
- return;
- }
-
- if (! validate_cron_expression($this->update_check_frequency)) {
- $this->dispatch('error', 'Invalid Cron / Human expression for Update Check Frequency.');
- if (empty($this->update_check_frequency)) {
- $this->update_check_frequency = '0 * * * *';
- }
-
- return;
- }
-
- if ($this->settings->is_dns_validation_enabled && $this->settings->fqdn) {
- if (! validate_dns_entry($this->settings->fqdn, $this->server)) {
- $this->dispatch('error', "Validating DNS failed. Make sure you have added the DNS records correctly. {$this->settings->fqdn}->{$this->server->ip} Check this documentation for further help.");
- $error_show = true;
- }
- }
- if ($this->settings->fqdn) {
- check_domain_usage(domain: $this->settings->fqdn);
- }
- $this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->replaceEnd(',', '')->trim();
- $this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->trim()->explode(',')->map(function ($dns) {
- return str($dns)->trim()->lower();
- });
- $this->settings->custom_dns_servers = $this->settings->custom_dns_servers->unique();
- $this->settings->custom_dns_servers = $this->settings->custom_dns_servers->implode(',');
-
- $this->settings->allowed_ips = str($this->settings->allowed_ips)->replaceEnd(',', '')->trim();
- $this->settings->allowed_ips = str($this->settings->allowed_ips)->trim()->explode(',')->map(function ($ip) {
- return str($ip)->trim();
- });
- $this->settings->allowed_ips = $this->settings->allowed_ips->unique();
- $this->settings->allowed_ips = $this->settings->allowed_ips->implode(',');
-
- $this->instantSave(isSave: false);
-
- $this->settings->save();
- $this->server->setupDynamicProxyConfiguration();
- if (! $error_show) {
- $this->dispatch('success', 'Instance settings updated successfully!');
- }
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function checkManually()
- {
- CheckForUpdatesJob::dispatchSync();
- $this->dispatch('updateAvailable');
- $settings = instanceSettings();
- if ($settings->new_version_available) {
- $this->dispatch('success', 'New version available!');
- } else {
- $this->dispatch('success', 'No new version available.');
- }
- }
-
- public function toggleTwoStepConfirmation($password): bool
- {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return false;
- }
-
- $this->settings->disable_two_step_confirmation = $this->disable_two_step_confirmation = true;
- $this->settings->save();
- $this->dispatch('success', 'Two step confirmation has been disabled.');
-
- return true;
- }
-}
diff --git a/app/Livewire/SettingsBackup.php b/app/Livewire/SettingsBackup.php
deleted file mode 100644
index 1b0599ffee..0000000000
--- a/app/Livewire/SettingsBackup.php
+++ /dev/null
@@ -1,125 +0,0 @@
-route('dashboard');
- } else {
- $settings = instanceSettings();
- $this->database = StandalonePostgresql::whereName('coolify-db')->first();
- $s3s = S3Storage::whereTeamId(0)->get() ?? [];
- if ($this->database) {
- $this->uuid = $this->database->uuid;
- $this->name = $this->database->name;
- $this->description = $this->database->description;
- $this->postgres_user = $this->database->postgres_user;
- $this->postgres_password = $this->database->postgres_password;
-
- if ($this->database->status !== 'running') {
- $this->database->status = 'running';
- $this->database->save();
- }
- $this->backup = $this->database->scheduledBackups->first();
- $this->executions = $this->backup->executions;
- }
- $this->settings = $settings;
- $this->s3s = $s3s;
- }
- }
-
- public function addCoolifyDatabase()
- {
- try {
- $server = Server::findOrFail(0);
- $out = instant_remote_process(['docker inspect coolify-db'], $server);
- $envs = format_docker_envs_to_json($out);
- $postgres_password = $envs['POSTGRES_PASSWORD'];
- $postgres_user = $envs['POSTGRES_USER'];
- $postgres_db = $envs['POSTGRES_DB'];
- $this->database = StandalonePostgresql::create([
- 'id' => 0,
- 'name' => 'coolify-db',
- 'description' => 'Coolify database',
- 'postgres_user' => $postgres_user,
- 'postgres_password' => $postgres_password,
- 'postgres_db' => $postgres_db,
- 'status' => 'running',
- 'destination_type' => \App\Models\StandaloneDocker::class,
- 'destination_id' => 0,
- ]);
- $this->backup = ScheduledDatabaseBackup::create([
- 'id' => 0,
- 'enabled' => true,
- 'save_s3' => false,
- 'frequency' => '0 0 * * *',
- 'database_id' => $this->database->id,
- 'database_type' => \App\Models\StandalonePostgresql::class,
- 'team_id' => currentTeam()->id,
- ]);
- $this->database->refresh();
- $this->backup->refresh();
- $this->s3s = S3Storage::whereTeamId(0)->get();
-
- $this->uuid = $this->database->uuid;
- $this->name = $this->database->name;
- $this->description = $this->database->description;
- $this->postgres_user = $this->database->postgres_user;
- $this->postgres_password = $this->database->postgres_password;
- $this->executions = $this->backup->executions;
-
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- $this->database->update([
- 'name' => $this->name,
- 'description' => $this->description,
- 'postgres_user' => $this->postgres_user,
- 'postgres_password' => $this->postgres_password,
- ]);
- $this->dispatch('success', 'Backup updated.');
- }
-}
diff --git a/app/Livewire/SettingsEmail.php b/app/Livewire/SettingsEmail.php
deleted file mode 100644
index 4205594a52..0000000000
--- a/app/Livewire/SettingsEmail.php
+++ /dev/null
@@ -1,241 +0,0 @@
-route('dashboard');
- }
- $this->settings = instanceSettings();
- $this->syncData();
- $this->team = auth()->user()->currentTeam();
- $this->testEmailAddress = auth()->user()->email;
- }
-
- public function syncData(bool $toModel = false)
- {
- if ($toModel) {
- $this->validate();
- $this->settings->smtp_enabled = $this->smtpEnabled;
- $this->settings->smtp_host = $this->smtpHost;
- $this->settings->smtp_port = $this->smtpPort;
- $this->settings->smtp_encryption = $this->smtpEncryption;
- $this->settings->smtp_username = $this->smtpUsername;
- $this->settings->smtp_password = $this->smtpPassword;
- $this->settings->smtp_timeout = $this->smtpTimeout;
- $this->settings->smtp_from_address = $this->smtpFromAddress;
- $this->settings->smtp_from_name = $this->smtpFromName;
-
- $this->settings->resend_enabled = $this->resendEnabled;
- $this->settings->resend_api_key = $this->resendApiKey;
- $this->settings->save();
- } else {
- $this->smtpEnabled = $this->settings->smtp_enabled;
- $this->smtpHost = $this->settings->smtp_host;
- $this->smtpPort = $this->settings->smtp_port;
- $this->smtpEncryption = $this->settings->smtp_encryption;
- $this->smtpUsername = $this->settings->smtp_username;
- $this->smtpPassword = $this->settings->smtp_password;
- $this->smtpTimeout = $this->settings->smtp_timeout;
- $this->smtpFromAddress = $this->settings->smtp_from_address;
- $this->smtpFromName = $this->settings->smtp_from_name;
-
- $this->resendEnabled = $this->settings->resend_enabled;
- $this->resendApiKey = $this->settings->resend_api_key;
- }
- }
-
- public function submit()
- {
- try {
- $this->resetErrorBag();
- $this->syncData(true);
- $this->dispatch('success', 'Transactional email settings updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function instantSave(string $type)
- {
- try {
- $currentSmtpEnabled = $this->settings->smtp_enabled;
- $currentResendEnabled = $this->settings->resend_enabled;
- $this->resetErrorBag();
-
- if ($type === 'SMTP') {
- $this->submitSmtp();
- $this->resendEnabled = $this->settings->resend_enabled = false;
- } elseif ($type === 'Resend') {
- $this->submitResend();
- $this->smtpEnabled = $this->settings->smtp_enabled = false;
- }
- $this->settings->save();
-
- } catch (\Throwable $e) {
- if ($type === 'SMTP') {
- $this->smtpEnabled = $currentSmtpEnabled;
- } elseif ($type === 'Resend') {
- $this->resendEnabled = $currentResendEnabled;
- }
-
- return handleError($e, $this);
- }
- }
-
- public function submitSmtp()
- {
- try {
- $this->validate([
- 'smtpEnabled' => 'boolean',
- 'smtpFromAddress' => 'required|email',
- 'smtpFromName' => 'required|string',
- 'smtpHost' => 'required|string',
- 'smtpPort' => 'required|numeric',
- 'smtpEncryption' => 'required|string|in:starttls,tls,none',
- 'smtpUsername' => 'nullable|string',
- 'smtpPassword' => 'nullable|string',
- 'smtpTimeout' => 'nullable|numeric',
- ], [
- 'smtpFromAddress.required' => 'From Address is required.',
- 'smtpFromAddress.email' => 'Please enter a valid email address.',
- 'smtpFromName.required' => 'From Name is required.',
- 'smtpHost.required' => 'SMTP Host is required.',
- 'smtpPort.required' => 'SMTP Port is required.',
- 'smtpPort.numeric' => 'SMTP Port must be a number.',
- 'smtpEncryption.required' => 'Encryption type is required.',
- ]);
-
- $this->settings->smtp_enabled = $this->smtpEnabled;
- $this->settings->smtp_host = $this->smtpHost;
- $this->settings->smtp_port = $this->smtpPort;
- $this->settings->smtp_encryption = $this->smtpEncryption;
- $this->settings->smtp_username = $this->smtpUsername;
- $this->settings->smtp_password = $this->smtpPassword;
- $this->settings->smtp_timeout = $this->smtpTimeout;
- $this->settings->smtp_from_address = $this->smtpFromAddress;
- $this->settings->smtp_from_name = $this->smtpFromName;
-
- $this->settings->save();
-
- $this->dispatch('success', 'SMTP settings updated.');
- } catch (\Throwable $e) {
- $this->smtpEnabled = false;
-
- return handleError($e);
- }
- }
-
- public function submitResend()
- {
- try {
- $this->validate([
- 'resendEnabled' => 'boolean',
- 'resendApiKey' => 'required|string',
- 'smtpFromAddress' => 'required|email',
- 'smtpFromName' => 'required|string',
- ], [
- 'resendApiKey.required' => 'Resend API Key is required.',
- 'smtpFromAddress.required' => 'From Address is required.',
- 'smtpFromAddress.email' => 'Please enter a valid email address.',
- 'smtpFromName.required' => 'From Name is required.',
- ]);
-
- $this->settings->resend_enabled = $this->resendEnabled;
- $this->settings->resend_api_key = $this->resendApiKey;
- $this->settings->smtp_from_address = $this->smtpFromAddress;
- $this->settings->smtp_from_name = $this->smtpFromName;
-
- $this->settings->save();
-
- $this->dispatch('success', 'Resend settings updated.');
- } catch (\Throwable $e) {
- $this->resendEnabled = false;
-
- return handleError($e);
- }
- }
-
- public function sendTestEmail()
- {
- try {
- $this->validate([
- 'testEmailAddress' => 'required|email',
- ], [
- 'testEmailAddress.required' => 'Test email address is required.',
- 'testEmailAddress.email' => 'Please enter a valid email address.',
- ]);
-
- $executed = RateLimiter::attempt(
- 'test-email:'.$this->team->id,
- $perMinute = 0,
- function () {
- $this->team?->notify(new Test($this->testEmailAddress, 'email'));
- $this->dispatch('success', 'Test Email sent.');
- },
- $decaySeconds = 10,
- );
-
- if (! $executed) {
- throw new \Exception('Too many messages sent!');
- }
- } catch (\Throwable $e) {
- return handleError($e);
- }
- }
-}
diff --git a/app/Livewire/SettingsOauth.php b/app/Livewire/SettingsOauth.php
deleted file mode 100644
index e23f94a73b..0000000000
--- a/app/Livewire/SettingsOauth.php
+++ /dev/null
@@ -1,69 +0,0 @@
-reduce(function ($carry, $setting) {
- $carry["oauth_settings_map.$setting->provider.enabled"] = 'required';
- $carry["oauth_settings_map.$setting->provider.client_id"] = 'nullable';
- $carry["oauth_settings_map.$setting->provider.client_secret"] = 'nullable';
- $carry["oauth_settings_map.$setting->provider.redirect_uri"] = 'nullable';
- $carry["oauth_settings_map.$setting->provider.tenant"] = 'nullable';
- $carry["oauth_settings_map.$setting->provider.base_url"] = 'nullable';
-
- return $carry;
- }, []);
- }
-
- public function mount()
- {
- if (! isInstanceAdmin()) {
- return redirect()->route('home');
- }
- $this->oauth_settings_map = OauthSetting::all()->sortBy('provider')->reduce(function ($carry, $setting) {
- $carry[$setting->provider] = $setting;
-
- return $carry;
- }, []);
- }
-
- private function updateOauthSettings(?string $provider = null)
- {
- if ($provider) {
- $oauth = $this->oauth_settings_map[$provider];
- if (! $oauth->couldBeEnabled()) {
- $oauth->update(['enabled' => false]);
- throw new \Exception('OAuth settings are not complete for '.$oauth->provider.'. Please fill in all required fields.');
- }
- $oauth->save();
- $this->dispatch('success', 'OAuth settings for '.$oauth->provider.' updated successfully!');
- } else {
- foreach (array_values($this->oauth_settings_map) as &$setting) {
- $setting->save();
- }
- }
- }
-
- public function instantSave(string $provider)
- {
- try {
- $this->updateOauthSettings($provider);
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- $this->updateOauthSettings();
- $this->dispatch('success', 'Instance settings updated successfully!');
- }
-}
diff --git a/app/Livewire/SharedVariables/Environment/Index.php b/app/Livewire/SharedVariables/Environment/Index.php
deleted file mode 100644
index 3673a3882c..0000000000
--- a/app/Livewire/SharedVariables/Environment/Index.php
+++ /dev/null
@@ -1,22 +0,0 @@
-projects = Project::ownedByCurrentTeam()->get();
- }
-
- public function render()
- {
- return view('livewire.shared-variables.environment.index');
- }
-}
diff --git a/app/Livewire/SharedVariables/Environment/Show.php b/app/Livewire/SharedVariables/Environment/Show.php
deleted file mode 100644
index e88ac5f135..0000000000
--- a/app/Livewire/SharedVariables/Environment/Show.php
+++ /dev/null
@@ -1,53 +0,0 @@
- '$refresh', 'saveKey', 'environmentVariableDeleted' => '$refresh'];
-
- public function saveKey($data)
- {
- try {
- $found = $this->environment->environment_variables()->where('key', $data['key'])->first();
- if ($found) {
- throw new \Exception('Variable already exists.');
- }
- $this->environment->environment_variables()->create([
- 'key' => $data['key'],
- 'value' => $data['value'],
- 'is_multiline' => $data['is_multiline'],
- 'is_literal' => $data['is_literal'],
- 'type' => 'environment',
- 'team_id' => currentTeam()->id,
- ]);
- $this->environment->refresh();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function mount()
- {
- $this->parameters = get_route_parameters();
- $this->project = Project::ownedByCurrentTeam()->where('uuid', request()->route('project_uuid'))->firstOrFail();
- $this->environment = $this->project->environments()->where('uuid', request()->route('environment_uuid'))->firstOrFail();
- }
-
- public function render()
- {
- return view('livewire.shared-variables.environment.show');
- }
-}
diff --git a/app/Livewire/SharedVariables/Index.php b/app/Livewire/SharedVariables/Index.php
deleted file mode 100644
index 61c31e9f83..0000000000
--- a/app/Livewire/SharedVariables/Index.php
+++ /dev/null
@@ -1,13 +0,0 @@
-projects = Project::ownedByCurrentTeam()->get();
- }
-
- public function render()
- {
- return view('livewire.shared-variables.project.index');
- }
-}
diff --git a/app/Livewire/SharedVariables/Project/Show.php b/app/Livewire/SharedVariables/Project/Show.php
deleted file mode 100644
index 0171283c4a..0000000000
--- a/app/Livewire/SharedVariables/Project/Show.php
+++ /dev/null
@@ -1,50 +0,0 @@
- '$refresh', 'saveKey' => 'saveKey', 'environmentVariableDeleted' => '$refresh'];
-
- public function saveKey($data)
- {
- try {
- $found = $this->project->environment_variables()->where('key', $data['key'])->first();
- if ($found) {
- throw new \Exception('Variable already exists.');
- }
- $this->project->environment_variables()->create([
- 'key' => $data['key'],
- 'value' => $data['value'],
- 'is_multiline' => $data['is_multiline'],
- 'is_literal' => $data['is_literal'],
- 'type' => 'project',
- 'team_id' => currentTeam()->id,
- ]);
- $this->project->refresh();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function mount()
- {
- $projectUuid = request()->route('project_uuid');
- $teamId = currentTeam()->id;
- $project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first();
- if (! $project) {
- return redirect()->route('dashboard');
- }
- $this->project = $project;
- }
-
- public function render()
- {
- return view('livewire.shared-variables.project.show');
- }
-}
diff --git a/app/Livewire/SharedVariables/Team/Index.php b/app/Livewire/SharedVariables/Team/Index.php
deleted file mode 100644
index a76ccf58a6..0000000000
--- a/app/Livewire/SharedVariables/Team/Index.php
+++ /dev/null
@@ -1,44 +0,0 @@
- '$refresh', 'saveKey' => 'saveKey', 'environmentVariableDeleted' => '$refresh'];
-
- public function saveKey($data)
- {
- try {
- $found = $this->team->environment_variables()->where('key', $data['key'])->first();
- if ($found) {
- throw new \Exception('Variable already exists.');
- }
- $this->team->environment_variables()->create([
- 'key' => $data['key'],
- 'value' => $data['value'],
- 'is_multiline' => $data['is_multiline'],
- 'is_literal' => $data['is_literal'],
- 'type' => 'team',
- 'team_id' => currentTeam()->id,
- ]);
- $this->team->refresh();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function mount()
- {
- $this->team = currentTeam();
- }
-
- public function render()
- {
- return view('livewire.shared-variables.team.index');
- }
-}
diff --git a/app/Livewire/Source/Github/Change.php b/app/Livewire/Source/Github/Change.php
deleted file mode 100644
index e73c9dc737..0000000000
--- a/app/Livewire/Source/Github/Change.php
+++ /dev/null
@@ -1,299 +0,0 @@
- 'required|string',
- 'github_app.organization' => 'nullable|string',
- 'github_app.api_url' => 'required|string',
- 'github_app.html_url' => 'required|string',
- 'github_app.custom_user' => 'required|string',
- 'github_app.custom_port' => 'required|int',
- 'github_app.app_id' => 'required|int',
- 'github_app.installation_id' => 'required|int',
- 'github_app.client_id' => 'required|string',
- 'github_app.client_secret' => 'required|string',
- 'github_app.webhook_secret' => 'required|string',
- 'github_app.is_system_wide' => 'required|bool',
- 'github_app.contents' => 'nullable|string',
- 'github_app.metadata' => 'nullable|string',
- 'github_app.pull_requests' => 'nullable|string',
- 'github_app.administration' => 'nullable|string',
- 'github_app.private_key_id' => 'required|int',
- ];
-
- public function boot()
- {
- if ($this->github_app) {
- $this->github_app->makeVisible(['client_secret', 'webhook_secret']);
- }
- }
-
- public function checkPermissions()
- {
- try {
- GithubAppPermissionJob::dispatchSync($this->github_app);
- $this->github_app->refresh()->makeVisible('client_secret')->makeVisible('webhook_secret');
- $this->dispatch('success', 'Github App permissions updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- // public function check()
- // {
-
- // Need administration:read:write permission
- // https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#list-self-hosted-runners-for-a-repository
-
- // $github_access_token = generateGithubInstallationToken($this->github_app);
- // $repositories = Http::withToken($github_access_token)->get("{$this->github_app->api_url}/installation/repositories?per_page=100");
- // $runners_by_repository = collect([]);
- // $repositories = $repositories->json()['repositories'];
- // foreach ($repositories as $repository) {
- // $runners_downloads = Http::withToken($github_access_token)->get("{$this->github_app->api_url}/repos/{$repository['full_name']}/actions/runners/downloads");
- // $runners = Http::withToken($github_access_token)->get("{$this->github_app->api_url}/repos/{$repository['full_name']}/actions/runners");
- // $token = Http::withHeaders([
- // 'Authorization' => "Bearer $github_access_token",
- // 'Accept' => 'application/vnd.github+json'
- // ])->withBody(null)->post("{$this->github_app->api_url}/repos/{$repository['full_name']}/actions/runners/registration-token");
- // $token = $token->json();
- // $remove_token = Http::withHeaders([
- // 'Authorization' => "Bearer $github_access_token",
- // 'Accept' => 'application/vnd.github+json'
- // ])->withBody(null)->post("{$this->github_app->api_url}/repos/{$repository['full_name']}/actions/runners/remove-token");
- // $remove_token = $remove_token->json();
- // $runners_by_repository->put($repository['full_name'], [
- // 'token' => $token,
- // 'remove_token' => $remove_token,
- // 'runners' => $runners->json(),
- // 'runners_downloads' => $runners_downloads->json()
- // ]);
- // }
-
- // }
-
- public function mount()
- {
- try {
- $github_app_uuid = request()->github_app_uuid;
- $this->github_app = GithubApp::ownedByCurrentTeam()->whereUuid($github_app_uuid)->firstOrFail();
- $this->github_app->makeVisible(['client_secret', 'webhook_secret']);
- $this->privateKeys = PrivateKey::ownedByCurrentTeam()->get();
-
- $this->applications = $this->github_app->applications;
- $settings = instanceSettings();
-
- $this->name = str($this->github_app->name)->kebab();
- $this->fqdn = $settings->fqdn;
-
- if ($settings->public_ipv4) {
- $this->ipv4 = 'http://'.$settings->public_ipv4.':'.config('app.port');
- }
- if ($settings->public_ipv6) {
- $this->ipv6 = 'http://'.$settings->public_ipv6.':'.config('app.port');
- }
- if ($this->github_app->installation_id && session('from')) {
- $source_id = data_get(session('from'), 'source_id');
- if (! $source_id || $this->github_app->id !== $source_id) {
- session()->forget('from');
- } else {
- $parameters = data_get(session('from'), 'parameters');
- $back = data_get(session('from'), 'back');
- $environment_uuid = data_get($parameters, 'environment_uuid');
- $project_uuid = data_get($parameters, 'project_uuid');
- $type = data_get($parameters, 'type');
- $destination = data_get($parameters, 'destination');
- session()->forget('from');
-
- return redirect()->route($back, [
- 'environment_uuid' => $environment_uuid,
- 'project_uuid' => $project_uuid,
- 'type' => $type,
- 'destination' => $destination,
- ]);
- }
- }
- $this->parameters = get_route_parameters();
- if (isCloud() && ! isDev()) {
- $this->webhook_endpoint = config('app.url');
- } else {
- $this->webhook_endpoint = $this->ipv4;
- $this->is_system_wide = $this->github_app->is_system_wide;
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function getGithubAppNameUpdatePath()
- {
- if (str($this->github_app->organization)->isNotEmpty()) {
- return "{$this->github_app->html_url}/organizations/{$this->github_app->organization}/settings/apps/{$this->github_app->name}";
- }
-
- return "{$this->github_app->html_url}/settings/apps/{$this->github_app->name}";
- }
-
- private function generateGithubJwt($private_key, $app_id): string
- {
- $configuration = Configuration::forAsymmetricSigner(
- new Sha256,
- InMemory::plainText($private_key),
- InMemory::plainText($private_key)
- );
-
- $now = time();
-
- return $configuration->builder()
- ->issuedBy((string) $app_id)
- ->permittedFor('https://api.github.com')
- ->identifiedBy((string) $now)
- ->issuedAt(new \DateTimeImmutable("@{$now}"))
- ->expiresAt(new \DateTimeImmutable('@'.($now + 600)))
- ->getToken($configuration->signer(), $configuration->signingKey())
- ->toString();
- }
-
- public function updateGithubAppName()
- {
- try {
- $privateKey = PrivateKey::ownedByCurrentTeam()->find($this->github_app->private_key_id);
-
- if (! $privateKey) {
- $this->dispatch('error', 'No private key found for this GitHub App.');
-
- return;
- }
-
- $jwt = $this->generateGithubJwt($privateKey->private_key, $this->github_app->app_id);
-
- $response = Http::withHeaders([
- 'Accept' => 'application/vnd.github+json',
- 'X-GitHub-Api-Version' => '2022-11-28',
- 'Authorization' => "Bearer {$jwt}",
- ])->get("{$this->github_app->api_url}/app");
-
- if ($response->successful()) {
- $app_data = $response->json();
- $app_slug = $app_data['slug'] ?? null;
-
- if ($app_slug) {
- $this->github_app->name = $app_slug;
- $this->name = str($app_slug)->kebab();
- $privateKey->name = "github-app-{$app_slug}";
- $privateKey->save();
- $this->github_app->save();
- $this->dispatch('success', 'GitHub App name and SSH key name synchronized successfully.');
- } else {
- $this->dispatch('info', 'Could not find App Name (slug) in GitHub response.');
- }
- } else {
- $error_message = $response->json()['message'] ?? 'Unknown error';
- $this->dispatch('error', "Failed to fetch GitHub App information: {$error_message}");
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- try {
- $this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
- $this->validate([
- 'github_app.name' => 'required|string',
- 'github_app.organization' => 'nullable|string',
- 'github_app.api_url' => 'required|string',
- 'github_app.html_url' => 'required|string',
- 'github_app.custom_user' => 'required|string',
- 'github_app.custom_port' => 'required|int',
- 'github_app.app_id' => 'required|int',
- 'github_app.installation_id' => 'required|int',
- 'github_app.client_id' => 'required|string',
- 'github_app.client_secret' => 'required|string',
- 'github_app.webhook_secret' => 'required|string',
- 'github_app.is_system_wide' => 'required|bool',
- 'github_app.private_key_id' => 'required|int',
- ]);
- $this->github_app->save();
- $this->dispatch('success', 'Github App updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function createGithubAppManually()
- {
- $this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
- $this->github_app->app_id = '1234567890';
- $this->github_app->installation_id = '1234567890';
- $this->github_app->save();
- $this->dispatch('success', 'Github App updated.');
- }
-
- public function instantSave()
- {
- try {
- $this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
- $this->github_app->save();
- $this->dispatch('success', 'Github App updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function delete()
- {
- try {
- if ($this->github_app->applications->isNotEmpty()) {
- $this->dispatch('error', 'This source is being used by an application. Please delete all applications first.');
- $this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
-
- return;
- }
- $this->github_app->delete();
-
- return redirect()->route('source.all');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Source/Github/Create.php b/app/Livewire/Source/Github/Create.php
deleted file mode 100644
index 136d3525e0..0000000000
--- a/app/Livewire/Source/Github/Create.php
+++ /dev/null
@@ -1,63 +0,0 @@
-name = substr(generate_random_name(), 0, 30);
- }
-
- public function createGitHubApp()
- {
- try {
- $this->validate([
- 'name' => 'required|string',
- 'organization' => 'nullable|string',
- 'api_url' => 'required|string',
- 'html_url' => 'required|string',
- 'custom_user' => 'required|string',
- 'custom_port' => 'required|int',
- 'is_system_wide' => 'required|bool',
- ]);
- $payload = [
- 'name' => $this->name,
- 'organization' => $this->organization,
- 'api_url' => $this->api_url,
- 'html_url' => $this->html_url,
- 'custom_user' => $this->custom_user,
- 'custom_port' => $this->custom_port,
- 'team_id' => currentTeam()->id,
- ];
- if (isCloud()) {
- $payload['is_system_wide'] = $this->is_system_wide;
- }
- $github_app = GithubApp::create($payload);
- if (session('from')) {
- session(['from' => session('from') + ['source_id' => $github_app->id]]);
- }
-
- return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Source/Gitlab/Change.php b/app/Livewire/Source/Gitlab/Change.php
deleted file mode 100644
index 34600bb7dc..0000000000
--- a/app/Livewire/Source/Gitlab/Change.php
+++ /dev/null
@@ -1,13 +0,0 @@
- 'required|min:3|max:255',
- 'description' => 'nullable|min:3|max:255',
- 'region' => 'required|max:255',
- 'key' => 'required|max:255',
- 'secret' => 'required|max:255',
- 'bucket' => 'required|max:255',
- 'endpoint' => 'required|url|max:255',
- ];
-
- protected $validationAttributes = [
- 'name' => 'Name',
- 'description' => 'Description',
- 'region' => 'Region',
- 'key' => 'Key',
- 'secret' => 'Secret',
- 'bucket' => 'Bucket',
- 'endpoint' => 'Endpoint',
- ];
-
- public function updatedEndpoint($value)
- {
- try {
- if (empty($value)) {
- return;
- }
- if (str($value)->contains('digitaloceanspaces.com')) {
- $uri = Uri::of($value);
- $host = $uri->host();
-
- if (preg_match('/^(.+)\.([^.]+\.digitaloceanspaces\.com)$/', $host, $matches)) {
- $host = $matches[2];
- $value = "https://{$host}";
- }
- }
- } finally {
- if (! str($value)->startsWith('https://') && ! str($value)->startsWith('http://')) {
- $value = 'https://'.$value;
- }
- $this->endpoint = $value;
- }
- }
-
- public function submit()
- {
- try {
- $this->validate();
- $this->storage = new S3Storage;
- $this->storage->name = $this->name;
- $this->storage->description = $this->description ?? null;
- $this->storage->region = $this->region;
- $this->storage->key = $this->key;
- $this->storage->secret = $this->secret;
- $this->storage->bucket = $this->bucket;
- if (empty($this->endpoint)) {
- $this->storage->endpoint = "https://s3.{$this->region}.amazonaws.com";
- } else {
- $this->storage->endpoint = $this->endpoint;
- }
- $this->storage->team_id = currentTeam()->id;
- $this->storage->testConnection();
- $this->storage->save();
-
- return redirect()->route('storage.show', $this->storage->uuid);
- } catch (\Throwable $e) {
- $this->dispatch('error', 'Failed to create storage.', $e->getMessage());
- // return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Storage/Form.php b/app/Livewire/Storage/Form.php
deleted file mode 100644
index 8ca0020c7b..0000000000
--- a/app/Livewire/Storage/Form.php
+++ /dev/null
@@ -1,65 +0,0 @@
- 'nullable|boolean',
- 'storage.name' => 'nullable|min:3|max:255',
- 'storage.description' => 'nullable|min:3|max:255',
- 'storage.region' => 'required|max:255',
- 'storage.key' => 'required|max:255',
- 'storage.secret' => 'required|max:255',
- 'storage.bucket' => 'required|max:255',
- 'storage.endpoint' => 'required|url|max:255',
- ];
-
- protected $validationAttributes = [
- 'storage.is_usable' => 'Is Usable',
- 'storage.name' => 'Name',
- 'storage.description' => 'Description',
- 'storage.region' => 'Region',
- 'storage.key' => 'Key',
- 'storage.secret' => 'Secret',
- 'storage.bucket' => 'Bucket',
- 'storage.endpoint' => 'Endpoint',
- ];
-
- public function test_s3_connection()
- {
- try {
- $this->storage->testConnection(shouldSave: true);
-
- return $this->dispatch('success', 'Connection is working.', 'Tested with "ListObjectsV2" action.');
- } catch (\Throwable $e) {
- $this->dispatch('error', 'Failed to create storage.', $e->getMessage());
- }
- }
-
- public function delete()
- {
- try {
- $this->storage->delete();
-
- return redirect()->route('storage.index');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function submit()
- {
- $this->validate();
- try {
- $this->test_s3_connection();
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Storage/Index.php b/app/Livewire/Storage/Index.php
deleted file mode 100644
index 71ad89f702..0000000000
--- a/app/Livewire/Storage/Index.php
+++ /dev/null
@@ -1,21 +0,0 @@
-s3 = S3Storage::ownedByCurrentTeam()->get();
- }
-
- public function render()
- {
- return view('livewire.storage.index');
- }
-}
diff --git a/app/Livewire/Storage/Show.php b/app/Livewire/Storage/Show.php
deleted file mode 100644
index bdea9a3b04..0000000000
--- a/app/Livewire/Storage/Show.php
+++ /dev/null
@@ -1,24 +0,0 @@
-storage = S3Storage::ownedByCurrentTeam()->whereUuid(request()->storage_uuid)->first();
- if (! $this->storage) {
- abort(404);
- }
- }
-
- public function render()
- {
- return view('livewire.storage.show');
- }
-}
diff --git a/app/Livewire/Subscription/Actions.php b/app/Livewire/Subscription/Actions.php
deleted file mode 100644
index 1388d32441..0000000000
--- a/app/Livewire/Subscription/Actions.php
+++ /dev/null
@@ -1,22 +0,0 @@
-server_limits = Team::serverLimit();
- }
-
- public function stripeCustomerPortal()
- {
- $session = getStripeCustomerPortalSession(currentTeam());
- redirect($session->url);
- }
-}
diff --git a/app/Livewire/Subscription/Index.php b/app/Livewire/Subscription/Index.php
deleted file mode 100644
index df450cf7ef..0000000000
--- a/app/Livewire/Subscription/Index.php
+++ /dev/null
@@ -1,44 +0,0 @@
-user()?->isMember()) {
- return redirect()->route('dashboard');
- }
- if (data_get(currentTeam(), 'subscription') && isSubscriptionActive()) {
- return redirect()->route('subscription.show');
- }
- $this->settings = instanceSettings();
- $this->alreadySubscribed = currentTeam()->subscription()->exists();
- }
-
- public function stripeCustomerPortal()
- {
- $session = getStripeCustomerPortalSession(currentTeam());
- if (is_null($session)) {
- return;
- }
-
- return redirect($session->url);
- }
-
- public function render()
- {
- return view('livewire.subscription.index');
- }
-}
diff --git a/app/Livewire/Subscription/PricingPlans.php b/app/Livewire/Subscription/PricingPlans.php
deleted file mode 100644
index 6b2d3fb364..0000000000
--- a/app/Livewire/Subscription/PricingPlans.php
+++ /dev/null
@@ -1,70 +0,0 @@
- config('subscription.stripe_price_id_dynamic_monthly'),
- 'dynamic-yearly' => config('subscription.stripe_price_id_dynamic_yearly'),
- default => config('subscription.stripe_price_id_dynamic_monthly'),
- };
-
- if (! $priceId) {
- $this->dispatch('error', 'Price ID not found! Please contact the administrator.');
-
- return;
- }
- $payload = [
- 'allow_promotion_codes' => true,
- 'billing_address_collection' => 'required',
- 'client_reference_id' => Auth::id().':'.currentTeam()->id,
- 'line_items' => [[
- 'price' => $priceId,
- 'adjustable_quantity' => [
- 'enabled' => true,
- 'minimum' => 2,
- ],
- 'quantity' => 2,
- ]],
- 'tax_id_collection' => [
- 'enabled' => true,
- ],
- 'automatic_tax' => [
- 'enabled' => true,
- ],
- 'subscription_data' => [
- 'metadata' => [
- 'user_id' => Auth::id(),
- 'team_id' => currentTeam()->id,
- ],
- ],
- 'payment_method_collection' => 'if_required',
- 'mode' => 'subscription',
- 'success_url' => route('dashboard', ['success' => true]),
- 'cancel_url' => route('subscription.index', ['cancelled' => true]),
- ];
-
- $customer = currentTeam()->subscription?->stripe_customer_id ?? null;
- if ($customer) {
- $payload['customer'] = $customer;
- $payload['customer_update'] = [
- 'name' => 'auto',
- ];
- } else {
- $payload['customer_email'] = Auth::user()->email;
- }
- $session = Session::create($payload);
-
- return redirect($session->url, 303);
- }
-}
diff --git a/app/Livewire/Subscription/Show.php b/app/Livewire/Subscription/Show.php
deleted file mode 100644
index 96258c64e0..0000000000
--- a/app/Livewire/Subscription/Show.php
+++ /dev/null
@@ -1,26 +0,0 @@
-route('dashboard');
- }
- if (auth()->user()?->isMember()) {
- return redirect()->route('dashboard');
- }
- if (! data_get(currentTeam(), 'subscription')) {
- return redirect()->route('subscription.index');
- }
- }
-
- public function render()
- {
- return view('livewire.subscription.show');
- }
-}
diff --git a/app/Livewire/SwitchTeam.php b/app/Livewire/SwitchTeam.php
deleted file mode 100644
index 145c285ab5..0000000000
--- a/app/Livewire/SwitchTeam.php
+++ /dev/null
@@ -1,35 +0,0 @@
-selectedTeamId = auth()->user()->currentTeam()->id;
- }
-
- public function updatedSelectedTeamId()
- {
- $this->switch_to($this->selectedTeamId);
- }
-
- public function switch_to($team_id)
- {
- if (! auth()->user()->teams->contains($team_id)) {
- return;
- }
- $team_to_switch_to = Team::find($team_id);
- if (! $team_to_switch_to) {
- return;
- }
- refreshSession($team_to_switch_to);
-
- return redirect('dashboard');
- }
-}
diff --git a/app/Livewire/Tags/Deployments.php b/app/Livewire/Tags/Deployments.php
deleted file mode 100644
index e4afa5b606..0000000000
--- a/app/Livewire/Tags/Deployments.php
+++ /dev/null
@@ -1,37 +0,0 @@
-deploymentsPerTagPerServer = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->whereIn('application_id', $this->resourceIds)->get([
- 'id',
- 'application_id',
- 'application_name',
- 'deployment_url',
- 'pull_request_id',
- 'server_name',
- 'server_id',
- 'status',
- ])->sortBy('id')->groupBy('server_name')->toArray();
- $this->dispatch('deployments', $this->deploymentsPerTagPerServer);
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Tags/Show.php b/app/Livewire/Tags/Show.php
deleted file mode 100644
index fc5b133749..0000000000
--- a/app/Livewire/Tags/Show.php
+++ /dev/null
@@ -1,95 +0,0 @@
-tags = Tag::ownedByCurrentTeam()->get()->unique('name')->sortBy('name');
- if (str($this->tagName)->isNotEmpty()) {
- $tag = $this->tags->where('name', $this->tagName)->first();
- $this->webhook = generateTagDeployWebhook($tag->name);
- $this->applications = $tag->applications()->get();
- $this->services = $tag->services()->get();
- $this->tag = $tag;
- $this->getDeployments();
- }
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function getDeployments()
- {
- try {
- $resource_ids = $this->applications->pluck('id');
- $this->deploymentsPerTagPerServer = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->whereIn('application_id', $resource_ids)->get([
- 'id',
- 'application_id',
- 'application_name',
- 'deployment_url',
- 'pull_request_id',
- 'server_name',
- 'server_id',
- 'status',
- ])->sortBy('id')->groupBy('server_name')->toArray();
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function redeployAll()
- {
- try {
- $message = collect([]);
- $this->applications->each(function ($resource) use ($message) {
- $deploy = new DeployController;
- $message->push($deploy->deploy_resource($resource));
- });
- $this->services->each(function ($resource) use ($message) {
- $deploy = new DeployController;
- $message->push($deploy->deploy_resource($resource));
- });
- $this->dispatch('success', 'Mass deployment started.');
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.tags.show');
- }
-}
diff --git a/app/Livewire/Team/AdminView.php b/app/Livewire/Team/AdminView.php
deleted file mode 100644
index cfb47d9d83..0000000000
--- a/app/Livewire/Team/AdminView.php
+++ /dev/null
@@ -1,139 +0,0 @@
-route('dashboard');
- }
- $this->getUsers();
- }
-
- public function submitSearch()
- {
- if ($this->search !== '') {
- $this->users = User::where(function ($query) {
- $query->where('name', 'like', "%{$this->search}%")
- ->orWhere('email', 'like', "%{$this->search}%");
- })->get()->filter(function ($user) {
- return $user->id !== auth()->id();
- });
- } else {
- $this->getUsers();
- }
- }
-
- public function getUsers()
- {
- $users = User::where('id', '!=', auth()->id())->get();
- if ($users->count() > $this->number_of_users_to_show) {
- $this->lots_of_users = true;
- $this->users = $users->take($this->number_of_users_to_show);
- } else {
- $this->lots_of_users = false;
- $this->users = $users;
- }
- }
-
- private function finalizeDeletion(User $user, Team $team)
- {
- $servers = $team->servers;
- foreach ($servers as $server) {
- $resources = $server->definedResources();
- foreach ($resources as $resource) {
- $resource->forceDelete();
- }
- $server->forceDelete();
- }
-
- $projects = $team->projects;
- foreach ($projects as $project) {
- $project->forceDelete();
- }
- $team->members()->detach($user->id);
- $team->delete();
- }
-
- public function delete($id, $password)
- {
- if (! isInstanceAdmin()) {
- return redirect()->route('dashboard');
- }
- if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
- if (! Hash::check($password, Auth::user()->password)) {
- $this->addError('password', 'The provided password is incorrect.');
-
- return;
- }
- }
- if (! auth()->user()->isInstanceAdmin()) {
- return $this->dispatch('error', 'You are not authorized to delete users');
- }
- $user = User::find($id);
- $teams = $user->teams;
- foreach ($teams as $team) {
- $user_alone_in_team = $team->members->count() === 1;
- if ($team->id === 0) {
- if ($user_alone_in_team) {
- return $this->dispatch('error', 'User is alone in the root team, cannot delete');
- }
- }
- if ($user_alone_in_team) {
- $this->finalizeDeletion($user, $team);
-
- continue;
- }
- if ($user->isOwner()) {
- $found_other_owner_or_admin = $team->members->filter(function ($member) {
- return $member->pivot->role === 'owner' || $member->pivot->role === 'admin';
- })->where('id', '!=', $user->id)->first();
-
- if ($found_other_owner_or_admin) {
- $team->members()->detach($user->id);
-
- continue;
- } else {
- $found_other_member_who_is_not_owner = $team->members->filter(function ($member) {
- return $member->pivot->role === 'member';
- })->first();
- if ($found_other_member_who_is_not_owner) {
- $found_other_member_who_is_not_owner->pivot->role = 'owner';
- $found_other_member_who_is_not_owner->pivot->save();
- $team->members()->detach($user->id);
- } else {
- $this->finalizeDeletion($user, $team);
- }
-
- continue;
- }
- } else {
- $team->members()->detach($user->id);
- }
- }
- $user->delete();
- $this->getUsers();
- }
-
- public function render()
- {
- return view('livewire.team.admin-view');
- }
-}
diff --git a/app/Livewire/Team/Create.php b/app/Livewire/Team/Create.php
deleted file mode 100644
index f805d61222..0000000000
--- a/app/Livewire/Team/Create.php
+++ /dev/null
@@ -1,34 +0,0 @@
-validate();
- $team = Team::create([
- 'name' => $this->name,
- 'description' => $this->description,
- 'personal_team' => false,
- ]);
- auth()->user()->teams()->attach($team, ['role' => 'admin']);
- refreshSession();
-
- return redirect()->route('team.index');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/Team/Index.php b/app/Livewire/Team/Index.php
deleted file mode 100644
index 0972e7364f..0000000000
--- a/app/Livewire/Team/Index.php
+++ /dev/null
@@ -1,73 +0,0 @@
- 'required|min:3|max:255',
- 'team.description' => 'nullable|min:3|max:255',
- ];
-
- protected $validationAttributes = [
- 'team.name' => 'name',
- 'team.description' => 'description',
- ];
-
- public function mount()
- {
- $this->team = currentTeam();
-
- if (auth()->user()->isAdminFromSession()) {
- $this->invitations = TeamInvitation::whereTeamId(currentTeam()->id)->get();
- }
- }
-
- public function render()
- {
- return view('livewire.team.index');
- }
-
- public function submit()
- {
- $this->validate();
- try {
- $this->team->save();
- refreshSession();
- $this->dispatch('success', 'Team updated.');
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function delete()
- {
- $currentTeam = currentTeam();
- $currentTeam->delete();
-
- $currentTeam->members->each(function ($user) use ($currentTeam) {
- if ($user->id === Auth::id()) {
- return;
- }
- $user->teams()->detach($currentTeam);
- $session = DB::table('sessions')->where('user_id', $user->id)->first();
- if ($session) {
- DB::table('sessions')->where('id', $session->id)->delete();
- }
- });
-
- refreshSession();
-
- return redirect()->route('team.index');
- }
-}
diff --git a/app/Livewire/Team/Invitations.php b/app/Livewire/Team/Invitations.php
deleted file mode 100644
index 93432efc86..0000000000
--- a/app/Livewire/Team/Invitations.php
+++ /dev/null
@@ -1,30 +0,0 @@
-findOrFail($invitation_id);
- $initiation_found->delete();
- $this->refreshInvitations();
- $this->dispatch('success', 'Invitation revoked.');
- } catch (\Exception) {
- return $this->dispatch('error', 'Invitation not found.');
- }
- }
-
- public function refreshInvitations()
- {
- $this->invitations = TeamInvitation::ownedByCurrentTeam()->get();
- }
-}
diff --git a/app/Livewire/Team/InviteLink.php b/app/Livewire/Team/InviteLink.php
deleted file mode 100644
index 25f8a1ff51..0000000000
--- a/app/Livewire/Team/InviteLink.php
+++ /dev/null
@@ -1,109 +0,0 @@
- 'required|email',
- 'role' => 'required|string',
- ];
-
- public function mount()
- {
- $this->email = isDev() ? 'test3@example.com' : '';
- }
-
- public function viaEmail()
- {
- $this->generate_invite_link(sendEmail: true);
- }
-
- public function viaLink()
- {
- $this->generate_invite_link(sendEmail: false);
- }
-
- private function generate_invite_link(bool $sendEmail = false)
- {
- try {
- $this->validate();
- if (auth()->user()->role() === 'admin' && $this->role === 'owner') {
- throw new \Exception('Admins cannot invite owners.');
- }
- $member_emails = currentTeam()->members()->get()->pluck('email');
- if ($member_emails->contains($this->email)) {
- return handleError(livewire: $this, customErrorMessage: "$this->email is already a member of ".currentTeam()->name.'.');
- }
- $uuid = new Cuid2(32);
- $link = url('/').config('constants.invitation.link.base_url').$uuid;
- $user = User::whereEmail($this->email)->first();
-
- if (is_null($user)) {
- $password = Str::password();
- $user = User::create([
- 'name' => str($this->email)->before('@'),
- 'email' => $this->email,
- 'password' => Hash::make($password),
- 'force_password_reset' => true,
- ]);
- $token = Crypt::encryptString("{$user->email}@@@$password");
- $link = route('auth.link', ['token' => $token]);
- }
- $invitation = TeamInvitation::whereEmail($this->email)->first();
- if (! is_null($invitation)) {
- $invitationValid = $invitation->isValid();
- if ($invitationValid) {
- return handleError(livewire: $this, customErrorMessage: "Pending invitation already exists for $this->email.");
- } else {
- $invitation->delete();
- }
- }
-
- $invitation = TeamInvitation::firstOrCreate([
- 'team_id' => currentTeam()->id,
- 'uuid' => $uuid,
- 'email' => $this->email,
- 'role' => $this->role,
- 'link' => $link,
- 'via' => $sendEmail ? 'email' : 'link',
- ]);
- if ($sendEmail) {
- $mail = new MailMessage;
- $mail->view('emails.invitation-link', [
- 'team' => currentTeam()->name,
- 'invitation_link' => $link,
- ]);
- $mail->subject('You have been invited to '.currentTeam()->name.' on '.config('app.name').'.');
- send_user_an_email($mail, $this->email);
- $this->dispatch('success', 'Invitation sent via email.');
- $this->dispatch('refreshInvitations');
-
- return;
- } else {
- $this->dispatch('success', 'Invitation link generated.');
- $this->dispatch('refreshInvitations');
- }
- } catch (\Throwable $e) {
- $error_message = $e->getMessage();
- if ($e->getCode() === '23505') {
- $error_message = 'Invitation already sent.';
- }
-
- return handleError(error: $e, livewire: $this, customErrorMessage: $error_message);
- }
- }
-}
diff --git a/app/Livewire/Team/Member.php b/app/Livewire/Team/Member.php
deleted file mode 100644
index 890d640a07..0000000000
--- a/app/Livewire/Team/Member.php
+++ /dev/null
@@ -1,78 +0,0 @@
-user()->role())->lt(Role::ADMIN)
- || Role::from($this->getMemberRole())->gt(auth()->user()->role())) {
- throw new \Exception('You are not authorized to perform this action.');
- }
- $this->member->teams()->updateExistingPivot(currentTeam()->id, ['role' => Role::ADMIN->value]);
- $this->dispatch('reloadWindow');
- } catch (\Exception $e) {
- $this->dispatch('error', $e->getMessage());
- }
- }
-
- public function makeOwner()
- {
- try {
- if (Role::from(auth()->user()->role())->lt(Role::OWNER)
- || Role::from($this->getMemberRole())->gt(auth()->user()->role())) {
- throw new \Exception('You are not authorized to perform this action.');
- }
- $this->member->teams()->updateExistingPivot(currentTeam()->id, ['role' => Role::OWNER->value]);
- $this->dispatch('reloadWindow');
- } catch (\Exception $e) {
- $this->dispatch('error', $e->getMessage());
- }
- }
-
- public function makeReadonly()
- {
- try {
- if (Role::from(auth()->user()->role())->lt(Role::ADMIN)
- || Role::from($this->getMemberRole())->gt(auth()->user()->role())) {
- throw new \Exception('You are not authorized to perform this action.');
- }
- $this->member->teams()->updateExistingPivot(currentTeam()->id, ['role' => Role::MEMBER->value]);
- $this->dispatch('reloadWindow');
- } catch (\Exception $e) {
- $this->dispatch('error', $e->getMessage());
- }
- }
-
- public function remove()
- {
- try {
- if (Role::from(auth()->user()->role())->lt(Role::ADMIN)
- || Role::from($this->getMemberRole())->gt(auth()->user()->role())) {
- throw new \Exception('You are not authorized to perform this action.');
- }
- $this->member->teams()->detach(currentTeam());
- Cache::forget("team:{$this->member->id}");
- Cache::remember('team:'.$this->member->id, 3600, function () {
- return $this->member->teams()->first();
- });
- $this->dispatch('reloadWindow');
- } catch (\Exception $e) {
- $this->dispatch('error', $e->getMessage());
- }
- }
-
- private function getMemberRole()
- {
- return $this->member->teams()->where('teams.id', currentTeam()->id)->first()?->pivot?->role;
- }
-}
diff --git a/app/Livewire/Team/Member/Index.php b/app/Livewire/Team/Member/Index.php
deleted file mode 100644
index 00b745fe43..0000000000
--- a/app/Livewire/Team/Member/Index.php
+++ /dev/null
@@ -1,23 +0,0 @@
-user()->isAdminFromSession()) {
- $this->invitations = TeamInvitation::whereTeamId(currentTeam()->id)->get();
- }
- }
-
- public function render()
- {
- return view('livewire.team.member.index');
- }
-}
diff --git a/app/Livewire/Team/Storage/Show.php b/app/Livewire/Team/Storage/Show.php
deleted file mode 100644
index d3051afd42..0000000000
--- a/app/Livewire/Team/Storage/Show.php
+++ /dev/null
@@ -1,24 +0,0 @@
-storage = S3Storage::ownedByCurrentTeam()->whereUuid(request()->storage_uuid)->first();
- if (! $this->storage) {
- abort(404);
- }
- }
-
- public function render()
- {
- return view('livewire.storage.show');
- }
-}
diff --git a/app/Livewire/Terminal/Index.php b/app/Livewire/Terminal/Index.php
deleted file mode 100644
index a24a237c58..0000000000
--- a/app/Livewire/Terminal/Index.php
+++ /dev/null
@@ -1,88 +0,0 @@
-user()->isAdmin()) {
- abort(403);
- }
- $this->servers = Server::isReachable()->get();
- }
-
- public function loadContainers()
- {
- try {
- $this->containers = $this->getAllActiveContainers();
- } catch (\Exception $e) {
- return handleError($e, $this);
- } finally {
- $this->isLoadingContainers = false;
- }
- }
-
- private function getAllActiveContainers()
- {
- return collect($this->servers)->flatMap(function ($server) {
- if (! $server->isFunctional()) {
- return [];
- }
-
- return $server->loadAllContainers()->map(function ($container) use ($server) {
- $state = data_get_str($container, 'State')->lower();
- if ($state->contains('running')) {
- return [
- 'name' => data_get($container, 'Names'),
- 'connection_name' => data_get($container, 'Names'),
- 'uuid' => data_get($container, 'Names'),
- 'status' => data_get_str($container, 'State')->lower(),
- 'server' => $server,
- 'server_uuid' => $server->uuid,
- ];
- }
-
- return null;
- })->filter();
- });
- }
-
- public function updatedSelectedUuid()
- {
- $this->connectToContainer();
- }
-
- #[On('connectToContainer')]
- public function connectToContainer()
- {
- if ($this->selected_uuid === 'default') {
- $this->dispatch('error', 'Please select a server or a container.');
-
- return;
- }
- $container = collect($this->containers)->firstWhere('uuid', $this->selected_uuid);
- $this->dispatch('send-terminal-command',
- isset($container),
- $container['connection_name'] ?? $this->selected_uuid,
- $container['server_uuid'] ?? $this->selected_uuid
- );
- }
-
- public function render()
- {
- return view('livewire.terminal.index');
- }
-}
diff --git a/app/Livewire/Upgrade.php b/app/Livewire/Upgrade.php
deleted file mode 100644
index e50085c64e..0000000000
--- a/app/Livewire/Upgrade.php
+++ /dev/null
@@ -1,46 +0,0 @@
- 'checkUpdate'];
-
- public function checkUpdate()
- {
- try {
- $this->latestVersion = get_latest_version_of_coolify();
- $this->isUpgradeAvailable = data_get(InstanceSettings::get(), 'new_version_available', false);
- if (isDev()) {
- $this->isUpgradeAvailable = true;
- }
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-
- public function upgrade()
- {
- try {
- if ($this->updateInProgress) {
- return;
- }
- $this->updateInProgress = true;
- UpdateCoolify::run(manual_update: true);
- } catch (\Throwable $e) {
- return handleError($e, $this);
- }
- }
-}
diff --git a/app/Livewire/VerifyEmail.php b/app/Livewire/VerifyEmail.php
deleted file mode 100644
index fab3265b65..0000000000
--- a/app/Livewire/VerifyEmail.php
+++ /dev/null
@@ -1,27 +0,0 @@
-rateLimit(1, 300);
- auth()->user()->sendVerificationEmail();
- $this->dispatch('success', 'Email verification link sent!');
- } catch (\Exception $e) {
- return handleError($e, $this);
- }
- }
-
- public function render()
- {
- return view('livewire.verify-email');
- }
-}
diff --git a/app/Models/Application.php b/app/Models/Application.php
deleted file mode 100644
index 3913ce37a3..0000000000
--- a/app/Models/Application.php
+++ /dev/null
@@ -1,1700 +0,0 @@
- ['type' => 'integer', 'description' => 'The application identifier in the database.'],
- 'description' => ['type' => 'string', 'nullable' => true, 'description' => 'The application description.'],
- 'repository_project_id' => ['type' => 'integer', 'nullable' => true, 'description' => 'The repository project identifier.'],
- 'uuid' => ['type' => 'string', 'description' => 'The application UUID.'],
- 'name' => ['type' => 'string', 'description' => 'The application name.'],
- 'fqdn' => ['type' => 'string', 'nullable' => true, 'description' => 'The application domains.'],
- 'config_hash' => ['type' => 'string', 'description' => 'Configuration hash.'],
- 'git_repository' => ['type' => 'string', 'description' => 'Git repository URL.'],
- 'git_branch' => ['type' => 'string', 'description' => 'Git branch.'],
- 'git_commit_sha' => ['type' => 'string', 'description' => 'Git commit SHA.'],
- 'git_full_url' => ['type' => 'string', 'nullable' => true, 'description' => 'Git full URL.'],
- 'docker_registry_image_name' => ['type' => 'string', 'nullable' => true, 'description' => 'Docker registry image name.'],
- 'docker_registry_image_tag' => ['type' => 'string', 'nullable' => true, 'description' => 'Docker registry image tag.'],
- 'build_pack' => ['type' => 'string', 'description' => 'Build pack.', 'enum' => ['nixpacks', 'static', 'dockerfile', 'dockercompose']],
- 'static_image' => ['type' => 'string', 'description' => 'Static image used when static site is deployed.'],
- 'install_command' => ['type' => 'string', 'description' => 'Install command.'],
- 'build_command' => ['type' => 'string', 'description' => 'Build command.'],
- 'start_command' => ['type' => 'string', 'description' => 'Start command.'],
- 'ports_exposes' => ['type' => 'string', 'description' => 'Ports exposes.'],
- 'ports_mappings' => ['type' => 'string', 'nullable' => true, 'description' => 'Ports mappings.'],
- 'base_directory' => ['type' => 'string', 'description' => 'Base directory for all commands.'],
- 'publish_directory' => ['type' => 'string', 'description' => 'Publish directory.'],
- 'health_check_enabled' => ['type' => 'boolean', 'description' => 'Health check enabled.'],
- 'health_check_path' => ['type' => 'string', 'description' => 'Health check path.'],
- 'health_check_port' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check port.'],
- 'health_check_host' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check host.'],
- 'health_check_method' => ['type' => 'string', 'description' => 'Health check method.'],
- 'health_check_return_code' => ['type' => 'integer', 'description' => 'Health check return code.'],
- 'health_check_scheme' => ['type' => 'string', 'description' => 'Health check scheme.'],
- 'health_check_response_text' => ['type' => 'string', 'nullable' => true, 'description' => 'Health check response text.'],
- 'health_check_interval' => ['type' => 'integer', 'description' => 'Health check interval in seconds.'],
- 'health_check_timeout' => ['type' => 'integer', 'description' => 'Health check timeout in seconds.'],
- 'health_check_retries' => ['type' => 'integer', 'description' => 'Health check retries count.'],
- 'health_check_start_period' => ['type' => 'integer', 'description' => 'Health check start period in seconds.'],
- 'limits_memory' => ['type' => 'string', 'description' => 'Memory limit.'],
- 'limits_memory_swap' => ['type' => 'string', 'description' => 'Memory swap limit.'],
- 'limits_memory_swappiness' => ['type' => 'integer', 'description' => 'Memory swappiness.'],
- 'limits_memory_reservation' => ['type' => 'string', 'description' => 'Memory reservation.'],
- 'limits_cpus' => ['type' => 'string', 'description' => 'CPU limit.'],
- 'limits_cpuset' => ['type' => 'string', 'nullable' => true, 'description' => 'CPU set.'],
- 'limits_cpu_shares' => ['type' => 'integer', 'description' => 'CPU shares.'],
- 'status' => ['type' => 'string', 'description' => 'Application status.'],
- 'preview_url_template' => ['type' => 'string', 'description' => 'Preview URL template.'],
- 'destination_type' => ['type' => 'string', 'description' => 'Destination type.'],
- 'destination_id' => ['type' => 'integer', 'description' => 'Destination identifier.'],
- 'source_id' => ['type' => 'integer', 'nullable' => true, 'description' => 'Source identifier.'],
- 'private_key_id' => ['type' => 'integer', 'nullable' => true, 'description' => 'Private key identifier.'],
- 'environment_id' => ['type' => 'integer', 'description' => 'Environment identifier.'],
- 'dockerfile' => ['type' => 'string', 'nullable' => true, 'description' => 'Dockerfile content. Used for dockerfile build pack.'],
- 'dockerfile_location' => ['type' => 'string', 'description' => 'Dockerfile location.'],
- 'custom_labels' => ['type' => 'string', 'nullable' => true, 'description' => 'Custom labels.'],
- 'dockerfile_target_build' => ['type' => 'string', 'nullable' => true, 'description' => 'Dockerfile target build.'],
- 'manual_webhook_secret_github' => ['type' => 'string', 'nullable' => true, 'description' => 'Manual webhook secret for GitHub.'],
- 'manual_webhook_secret_gitlab' => ['type' => 'string', 'nullable' => true, 'description' => 'Manual webhook secret for GitLab.'],
- 'manual_webhook_secret_bitbucket' => ['type' => 'string', 'nullable' => true, 'description' => 'Manual webhook secret for Bitbucket.'],
- 'manual_webhook_secret_gitea' => ['type' => 'string', 'nullable' => true, 'description' => 'Manual webhook secret for Gitea.'],
- 'docker_compose_location' => ['type' => 'string', 'description' => 'Docker compose location.'],
- 'docker_compose' => ['type' => 'string', 'nullable' => true, 'description' => 'Docker compose content. Used for docker compose build pack.'],
- 'docker_compose_raw' => ['type' => 'string', 'nullable' => true, 'description' => 'Docker compose raw content.'],
- 'docker_compose_domains' => ['type' => 'string', 'nullable' => true, 'description' => 'Docker compose domains.'],
- 'docker_compose_custom_start_command' => ['type' => 'string', 'nullable' => true, 'description' => 'Docker compose custom start command.'],
- 'docker_compose_custom_build_command' => ['type' => 'string', 'nullable' => true, 'description' => 'Docker compose custom build command.'],
- 'swarm_replicas' => ['type' => 'integer', 'nullable' => true, 'description' => 'Swarm replicas. Only used for swarm deployments.'],
- 'swarm_placement_constraints' => ['type' => 'string', 'nullable' => true, 'description' => 'Swarm placement constraints. Only used for swarm deployments.'],
- 'custom_docker_run_options' => ['type' => 'string', 'nullable' => true, 'description' => 'Custom docker run options.'],
- 'post_deployment_command' => ['type' => 'string', 'nullable' => true, 'description' => 'Post deployment command.'],
- 'post_deployment_command_container' => ['type' => 'string', 'nullable' => true, 'description' => 'Post deployment command container.'],
- 'pre_deployment_command' => ['type' => 'string', 'nullable' => true, 'description' => 'Pre deployment command.'],
- 'pre_deployment_command_container' => ['type' => 'string', 'nullable' => true, 'description' => 'Pre deployment command container.'],
- 'watch_paths' => ['type' => 'string', 'nullable' => true, 'description' => 'Watch paths.'],
- 'custom_healthcheck_found' => ['type' => 'boolean', 'description' => 'Custom healthcheck found.'],
- 'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
- 'created_at' => ['type' => 'string', 'format' => 'date-time', 'description' => 'The date and time when the application was created.'],
- 'updated_at' => ['type' => 'string', 'format' => 'date-time', 'description' => 'The date and time when the application was last updated.'],
- 'deleted_at' => ['type' => 'string', 'format' => 'date-time', 'nullable' => true, 'description' => 'The date and time when the application was deleted.'],
- 'compose_parsing_version' => ['type' => 'string', 'description' => 'How Coolify parse the compose file.'],
- 'custom_nginx_configuration' => ['type' => 'string', 'nullable' => true, 'description' => 'Custom Nginx configuration base64 encoded.'],
- ]
-)]
-
-class Application extends BaseModel
-{
- use HasConfiguration, HasFactory, SoftDeletes;
-
- private static $parserVersion = '4';
-
- protected $guarded = [];
-
- protected $appends = ['server_status'];
-
- protected static function booted()
- {
- static::addGlobalScope('withRelations', function ($builder) {
- $builder->withCount([
- 'additional_servers',
- 'additional_networks',
- ]);
- });
- static::saving(function ($application) {
- $payload = [];
- if ($application->isDirty('fqdn')) {
- if ($application->fqdn === '') {
- $application->fqdn = null;
- }
- $payload['fqdn'] = $application->fqdn;
- }
- if ($application->isDirty('install_command')) {
- $payload['install_command'] = str($application->install_command)->trim();
- }
- if ($application->isDirty('build_command')) {
- $payload['build_command'] = str($application->build_command)->trim();
- }
- if ($application->isDirty('start_command')) {
- $payload['start_command'] = str($application->start_command)->trim();
- }
- if ($application->isDirty('base_directory')) {
- $payload['base_directory'] = str($application->base_directory)->trim();
- }
- if ($application->isDirty('publish_directory')) {
- $payload['publish_directory'] = str($application->publish_directory)->trim();
- }
- if ($application->isDirty('status')) {
- $payload['last_online_at'] = now();
- }
- if ($application->isDirty('custom_nginx_configuration')) {
- if ($application->custom_nginx_configuration === '') {
- $payload['custom_nginx_configuration'] = null;
- }
- }
- if (count($payload) > 0) {
- $application->forceFill($payload);
- }
- });
- static::created(function ($application) {
- ApplicationSetting::create([
- 'application_id' => $application->id,
- ]);
- $application->compose_parsing_version = self::$parserVersion;
- $application->save();
- });
- static::forceDeleting(function ($application) {
- $application->update(['fqdn' => null]);
- $application->settings()->delete();
- $application->persistentStorages()->delete();
- $application->environment_variables()->delete();
- $application->environment_variables_preview()->delete();
- foreach ($application->scheduled_tasks as $task) {
- $task->delete();
- }
- $application->tags()->detach();
- $application->previews()->delete();
- foreach ($application->deployment_queue as $deployment) {
- $deployment->delete();
- }
- });
- }
-
- public static function ownedByCurrentTeamAPI(int $teamId)
- {
- return Application::whereRelation('environment.project.team', 'id', $teamId)->orderBy('name');
- }
-
- public static function ownedByCurrentTeam()
- {
- return Application::whereRelation('environment.project.team', 'id', currentTeam()->id)->orderBy('name');
- }
-
- public function getContainersToStop(bool $previewDeployments = false): array
- {
- $containers = $previewDeployments
- ? getCurrentApplicationContainerStatus($this->destination->server, $this->id, includePullrequests: true)
- : getCurrentApplicationContainerStatus($this->destination->server, $this->id, 0);
-
- return $containers->pluck('Names')->toArray();
- }
-
- public function stopContainers(array $containerNames, $server, int $timeout = 600)
- {
- $processes = [];
- foreach ($containerNames as $containerName) {
- $processes[$containerName] = $this->stopContainer($containerName, $server, $timeout);
- }
-
- $startTime = time();
- while (count($processes) > 0) {
- $finishedProcesses = array_filter($processes, function ($process) {
- return ! $process->running();
- });
- foreach ($finishedProcesses as $containerName => $process) {
- unset($processes[$containerName]);
- $this->removeContainer($containerName, $server);
- }
-
- if (time() - $startTime >= $timeout) {
- $this->forceStopRemainingContainers(array_keys($processes), $server);
- break;
- }
-
- usleep(100000);
- }
- }
-
- public function stopContainer(string $containerName, $server, int $timeout): InvokedProcess
- {
- return Process::timeout($timeout)->start("docker stop --time=$timeout $containerName");
- }
-
- public function removeContainer(string $containerName, $server)
- {
- instant_remote_process(command: ["docker rm -f $containerName"], server: $server, throwError: false);
- }
-
- public function forceStopRemainingContainers(array $containerNames, $server)
- {
- foreach ($containerNames as $containerName) {
- instant_remote_process(command: ["docker kill $containerName"], server: $server, throwError: false);
- $this->removeContainer($containerName, $server);
- }
- }
-
- public function delete_configurations()
- {
- $server = data_get($this, 'destination.server');
- $workdir = $this->workdir();
- if (str($workdir)->endsWith($this->uuid)) {
- instant_remote_process(['rm -rf '.$this->workdir()], $server, false);
- }
- }
-
- public function delete_volumes(?Collection $persistentStorages)
- {
- if ($this->build_pack === 'dockercompose') {
- $server = data_get($this, 'destination.server');
- instant_remote_process(["cd {$this->dirOnServer()} && docker compose down -v"], $server, false);
- } else {
- if ($persistentStorages->count() === 0) {
- return;
- }
- $server = data_get($this, 'destination.server');
- foreach ($persistentStorages as $storage) {
- instant_remote_process(["docker volume rm -f $storage->name"], $server, false);
- }
- }
- }
-
- public function delete_connected_networks($uuid)
- {
- $server = data_get($this, 'destination.server');
- instant_remote_process(["docker network disconnect {$uuid} coolify-proxy"], $server, false);
- instant_remote_process(["docker network rm {$uuid}"], $server, false);
- }
-
- public function additional_servers()
- {
- return $this->belongsToMany(Server::class, 'additional_destinations')
- ->withPivot('standalone_docker_id', 'status');
- }
-
- public function additional_networks()
- {
- return $this->belongsToMany(StandaloneDocker::class, 'additional_destinations')
- ->withPivot('server_id', 'status');
- }
-
- public function is_public_repository(): bool
- {
- if (data_get($this, 'source.is_public')) {
- return true;
- }
-
- return false;
- }
-
- public function is_github_based(): bool
- {
- if (data_get($this, 'source')) {
- return true;
- }
-
- return false;
- }
-
- public function isForceHttpsEnabled()
- {
- return data_get($this, 'settings.is_force_https_enabled', false);
- }
-
- public function isStripprefixEnabled()
- {
- return data_get($this, 'settings.is_stripprefix_enabled', true);
- }
-
- public function isGzipEnabled()
- {
- return data_get($this, 'settings.is_gzip_enabled', true);
- }
-
- public function link()
- {
- if (data_get($this, 'environment.project.uuid')) {
- return route('project.application.configuration', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'application_uuid' => data_get($this, 'uuid'),
- ]);
- }
-
- return null;
- }
-
- public function taskLink($task_uuid)
- {
- if (data_get($this, 'environment.project.uuid')) {
- $route = route('project.application.scheduled-tasks', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'application_uuid' => data_get($this, 'uuid'),
- 'task_uuid' => $task_uuid,
- ]);
- $settings = instanceSettings();
- if (data_get($settings, 'fqdn')) {
- $url = Url::fromString($route);
- $url = $url->withPort(null);
- $fqdn = data_get($settings, 'fqdn');
- $fqdn = str_replace(['http://', 'https://'], '', $fqdn);
- $url = $url->withHost($fqdn);
-
- return $url->__toString();
- }
-
- return $route;
- }
-
- return null;
- }
-
- public function settings()
- {
- return $this->hasOne(ApplicationSetting::class);
- }
-
- public function persistentStorages()
- {
- return $this->morphMany(LocalPersistentVolume::class, 'resource');
- }
-
- public function fileStorages()
- {
- return $this->morphMany(LocalFileVolume::class, 'resource');
- }
-
- public function type()
- {
- return 'application';
- }
-
- public function publishDirectory(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => $value ? '/'.ltrim($value, '/') : null,
- );
- }
-
- public function gitBranchLocation(): Attribute
- {
- return Attribute::make(
- get: function () {
- if (! is_null($this->source?->html_url) && ! is_null($this->git_repository) && ! is_null($this->git_branch)) {
- if (str($this->git_repository)->contains('bitbucket')) {
- return "{$this->source->html_url}/{$this->git_repository}/src/{$this->git_branch}";
- }
-
- return "{$this->source->html_url}/{$this->git_repository}/tree/{$this->git_branch}";
- }
- // Convert the SSH URL to HTTPS URL
- if (strpos($this->git_repository, 'git@') === 0) {
- $git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository);
-
- if (str($this->git_repository)->contains('bitbucket')) {
- return "https://{$git_repository}/src/{$this->git_branch}";
- }
-
- return "https://{$git_repository}/tree/{$this->git_branch}";
- }
-
- return $this->git_repository;
- }
- );
- }
-
- public function gitWebhook(): Attribute
- {
- return Attribute::make(
- get: function () {
- if (! is_null($this->source?->html_url) && ! is_null($this->git_repository) && ! is_null($this->git_branch)) {
- return "{$this->source->html_url}/{$this->git_repository}/settings/hooks";
- }
- // Convert the SSH URL to HTTPS URL
- if (strpos($this->git_repository, 'git@') === 0) {
- $git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository);
-
- return "https://{$git_repository}/settings/hooks";
- }
-
- return $this->git_repository;
- }
- );
- }
-
- public function gitCommits(): Attribute
- {
- return Attribute::make(
- get: function () {
- if (! is_null($this->source?->html_url) && ! is_null($this->git_repository) && ! is_null($this->git_branch)) {
- return "{$this->source->html_url}/{$this->git_repository}/commits/{$this->git_branch}";
- }
- // Convert the SSH URL to HTTPS URL
- if (strpos($this->git_repository, 'git@') === 0) {
- $git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository);
-
- return "https://{$git_repository}/commits/{$this->git_branch}";
- }
-
- return $this->git_repository;
- }
- );
- }
-
- public function gitCommitLink($link): string
- {
- if (! is_null(data_get($this, 'source.html_url')) && ! is_null(data_get($this, 'git_repository')) && ! is_null(data_get($this, 'git_branch'))) {
- if (str($this->source->html_url)->contains('bitbucket')) {
- return "{$this->source->html_url}/{$this->git_repository}/commits/{$link}";
- }
-
- return "{$this->source->html_url}/{$this->git_repository}/commit/{$link}";
- }
- if (str($this->git_repository)->contains('bitbucket')) {
- $git_repository = str_replace('.git', '', $this->git_repository);
- $url = Url::fromString($git_repository);
- $url = $url->withUserInfo('');
- $url = $url->withPath($url->getPath().'/commits/'.$link);
-
- return $url->__toString();
- }
- if (strpos($this->git_repository, 'git@') === 0) {
- $git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository);
- if (data_get($this, 'source.html_url')) {
- return "{$this->source->html_url}/{$git_repository}/commit/{$link}";
- }
-
- return "{$git_repository}/commit/{$link}";
- }
-
- return $this->git_repository;
- }
-
- public function dockerfileLocation(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if (is_null($value) || $value === '') {
- return '/Dockerfile';
- } else {
- if ($value !== '/') {
- return Str::start(Str::replaceEnd('/', '', $value), '/');
- }
-
- return Str::start($value, '/');
- }
- }
- );
- }
-
- public function dockerComposeLocation(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if (is_null($value) || $value === '') {
- return '/docker-compose.yaml';
- } else {
- if ($value !== '/') {
- return Str::start(Str::replaceEnd('/', '', $value), '/');
- }
-
- return Str::start($value, '/');
- }
- }
- );
- }
-
- public function baseDirectory(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => '/'.ltrim($value, '/'),
- );
- }
-
- public function portsMappings(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => $value === '' ? null : $value,
- );
- }
-
- public function portsMappingsArray(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->ports_mappings)
- ? []
- : explode(',', $this->ports_mappings),
-
- );
- }
-
- public function isRunning()
- {
- return (bool) str($this->status)->startsWith('running');
- }
-
- public function isExited()
- {
- return (bool) str($this->status)->startsWith('exited');
- }
-
- public function realStatus()
- {
- return $this->getRawOriginal('status');
- }
-
- protected function serverStatus(): Attribute
- {
- return Attribute::make(
- get: function () {
- if (! $this->relationLoaded('additional_servers') || $this->additional_servers->count() === 0) {
- return $this->destination?->server?->isFunctional() ?? false;
- }
-
- $additional_servers_status = $this->additional_servers->pluck('pivot.status');
- $main_server_status = $this->destination?->server?->isFunctional() ?? false;
-
- foreach ($additional_servers_status as $status) {
- $server_status = str($status)->before(':')->value();
- if ($server_status !== 'running') {
- return false;
- }
- }
-
- return $main_server_status;
- }
- );
- }
-
- public function status(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if ($this->additional_servers->count() === 0) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- } else {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- }
- },
- get: function ($value) {
- if ($this->additional_servers->count() === 0) {
- // running (healthy)
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- } else {
- $complex_status = null;
- $complex_health = null;
- $complex_status = $main_server_status = str($value)->before(':')->value();
- $complex_health = $main_server_health = str($value)->after(':')->value() ?? 'unhealthy';
- $additional_servers_status = $this->additional_servers->pluck('pivot.status');
- foreach ($additional_servers_status as $status) {
- $server_status = str($status)->before(':')->value();
- $server_health = str($status)->after(':')->value() ?? 'unhealthy';
- if ($main_server_status !== $server_status) {
- $complex_status = 'degraded';
- }
- if ($main_server_health !== $server_health) {
- $complex_health = 'unhealthy';
- }
- }
-
- return "$complex_status:$complex_health";
- }
- },
- );
- }
-
- public function customNginxConfiguration(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => base64_encode($value),
- get: fn ($value) => base64_decode($value),
- );
- }
-
- public function portsExposesArray(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->ports_exposes)
- ? []
- : explode(',', $this->ports_exposes)
- );
- }
-
- public function tags()
- {
- return $this->morphToMany(Tag::class, 'taggable');
- }
-
- public function project()
- {
- return data_get($this, 'environment.project');
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function serviceType()
- {
- $found = str(collect(SPECIFIC_SERVICES)->filter(function ($service) {
- return str($this->image)->before(':')->value() === $service;
- })->first());
- if ($found->isNotEmpty()) {
- return $found;
- }
-
- return null;
- }
-
- public function main_port()
- {
- return $this->settings->is_static ? [80] : $this->ports_exposes_array;
- }
-
- public function environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->where('is_preview', false)
- ->orderBy('key', 'asc');
- }
-
- public function runtime_environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->where('is_preview', false)
- ->where('key', 'not like', 'NIXPACKS_%');
- }
-
- public function build_environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->where('is_preview', false)
- ->where('is_build_time', true)
- ->where('key', 'not like', 'NIXPACKS_%');
- }
-
- public function nixpacks_environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->where('is_preview', false)
- ->where('key', 'like', 'NIXPACKS_%');
- }
-
- public function environment_variables_preview()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->where('is_preview', true)
- ->orderByRaw("LOWER(key) LIKE LOWER('SERVICE%') DESC, LOWER(key) ASC");
- }
-
- public function runtime_environment_variables_preview()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->where('is_preview', true)
- ->where('key', 'not like', 'NIXPACKS_%');
- }
-
- public function build_environment_variables_preview()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->where('is_preview', true)
- ->where('is_build_time', true)
- ->where('key', 'not like', 'NIXPACKS_%');
- }
-
- public function nixpacks_environment_variables_preview()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->where('is_preview', true)
- ->where('key', 'like', 'NIXPACKS_%');
- }
-
- public function scheduled_tasks(): HasMany
- {
- return $this->hasMany(ScheduledTask::class)->orderBy('name', 'asc');
- }
-
- public function private_key()
- {
- return $this->belongsTo(PrivateKey::class);
- }
-
- public function environment()
- {
- return $this->belongsTo(Environment::class);
- }
-
- public function previews()
- {
- return $this->hasMany(ApplicationPreview::class);
- }
-
- public function deployment_queue()
- {
- return $this->hasMany(ApplicationDeploymentQueue::class);
- }
-
- public function destination()
- {
- return $this->morphTo();
- }
-
- public function source()
- {
- return $this->morphTo();
- }
-
- public function isDeploymentInprogress()
- {
- $deployments = ApplicationDeploymentQueue::where('application_id', $this->id)->whereIn('status', [ApplicationDeploymentStatus::IN_PROGRESS, ApplicationDeploymentStatus::QUEUED])->count();
- if ($deployments > 0) {
- return true;
- }
-
- return false;
- }
-
- public function get_last_successful_deployment()
- {
- return ApplicationDeploymentQueue::where('application_id', $this->id)->where('status', ApplicationDeploymentStatus::FINISHED)->where('pull_request_id', 0)->orderBy('created_at', 'desc')->first();
- }
-
- public function get_last_days_deployments()
- {
- return ApplicationDeploymentQueue::where('application_id', $this->id)->where('created_at', '>=', now()->subDays(7))->orderBy('created_at', 'desc')->get();
- }
-
- public function deployments(int $skip = 0, int $take = 10)
- {
- $deployments = ApplicationDeploymentQueue::where('application_id', $this->id)->orderBy('created_at', 'desc');
- $count = $deployments->count();
- $deployments = $deployments->skip($skip)->take($take)->get();
-
- return [
- 'count' => $count,
- 'deployments' => $deployments,
- ];
- }
-
- public function get_deployment(string $deployment_uuid)
- {
- return Activity::where('subject_id', $this->id)->where('properties->type_uuid', '=', $deployment_uuid)->first();
- }
-
- public function isDeployable(): bool
- {
- if ($this->settings->is_auto_deploy_enabled) {
- return true;
- }
-
- return false;
- }
-
- public function isPRDeployable(): bool
- {
- if ($this->settings->is_preview_deployments_enabled) {
- return true;
- }
-
- return false;
- }
-
- public function deploymentType()
- {
- if (isDev() && data_get($this, 'private_key_id') === 0) {
- return 'deploy_key';
- }
- if (data_get($this, 'private_key_id')) {
- return 'deploy_key';
- } elseif (data_get($this, 'source')) {
- return 'source';
- } else {
- return 'other';
- }
- throw new \Exception('No deployment type found');
- }
-
- public function could_set_build_commands(): bool
- {
- if ($this->build_pack === 'nixpacks') {
- return true;
- }
-
- return false;
- }
-
- public function git_based(): bool
- {
- if ($this->dockerfile) {
- return false;
- }
- if ($this->build_pack === 'dockerimage') {
- return false;
- }
-
- return true;
- }
-
- public function isHealthcheckDisabled(): bool
- {
- if (data_get($this, 'health_check_enabled') === false) {
- return true;
- }
-
- return false;
- }
-
- public function workdir()
- {
- return application_configuration_dir()."/{$this->uuid}";
- }
-
- public function isLogDrainEnabled()
- {
- return data_get($this, 'settings.is_log_drain_enabled', false);
- }
-
- public function isConfigurationChanged(bool $save = false)
- {
- $newConfigHash = base64_encode($this->fqdn.$this->git_repository.$this->git_branch.$this->git_commit_sha.$this->build_pack.$this->static_image.$this->install_command.$this->build_command.$this->start_command.$this->ports_exposes.$this->ports_mappings.$this->base_directory.$this->publish_directory.$this->dockerfile.$this->dockerfile_location.$this->custom_labels.$this->custom_docker_run_options.$this->dockerfile_target_build.$this->redirect.$this->custom_nginx_configuration);
- if ($this->pull_request_id === 0 || $this->pull_request_id === null) {
- $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort());
- } else {
- $newConfigHash .= json_encode($this->environment_variables_preview->get('value')->sort());
- }
- $newConfigHash = md5($newConfigHash);
- $oldConfigHash = data_get($this, 'config_hash');
- if ($oldConfigHash === null) {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- if ($oldConfigHash === $newConfigHash) {
- return false;
- } else {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- }
-
- public function customRepository()
- {
- return convertGitUrl($this->git_repository, $this->deploymentType(), $this->source);
- }
-
- public function generateBaseDir(string $uuid)
- {
- return "/artifacts/{$uuid}";
- }
-
- public function dirOnServer()
- {
- return application_configuration_dir()."/{$this->uuid}";
- }
-
- public function setGitImportSettings(string $deployment_uuid, string $git_clone_command, bool $public = false)
- {
- $baseDir = $this->generateBaseDir($deployment_uuid);
-
- if ($this->git_commit_sha !== 'HEAD') {
- $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git -c advice.detachedHead=false checkout {$this->git_commit_sha} >/dev/null 2>&1";
- }
- if ($this->settings->is_git_submodules_enabled) {
- if ($public) {
- $git_clone_command = "{$git_clone_command} && cd {$baseDir} && sed -i \"s#git@\(.*\):#https://\\1/#g\" {$baseDir}/.gitmodules || true";
- }
- $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git submodule update --init --recursive";
- }
- if ($this->settings->is_git_lfs_enabled) {
- $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git lfs pull";
- }
-
- return $git_clone_command;
- }
-
- public function getGitRemoteStatus(string $deployment_uuid)
- {
- try {
- ['commands' => $lsRemoteCommand] = $this->generateGitLsRemoteCommands(deployment_uuid: $deployment_uuid, exec_in_docker: false);
- instant_remote_process([$lsRemoteCommand], $this->destination->server, true);
-
- return [
- 'is_accessible' => true,
- 'error' => null,
- ];
- } catch (\RuntimeException $ex) {
- return [
- 'is_accessible' => false,
- 'error' => $ex->getMessage(),
- ];
- }
- }
-
- public function generateGitLsRemoteCommands(string $deployment_uuid, bool $exec_in_docker = true)
- {
- $branch = $this->git_branch;
- ['repository' => $customRepository, 'port' => $customPort] = $this->customRepository();
- $commands = collect([]);
- $base_command = 'git ls-remote';
-
- if ($this->deploymentType() === 'source') {
- $source_html_url = data_get($this, 'source.html_url');
- $url = parse_url(filter_var($source_html_url, FILTER_SANITIZE_URL));
- $source_html_url_host = $url['host'];
- $source_html_url_scheme = $url['scheme'];
-
- if ($this->source->getMorphClass() == 'App\Models\GithubApp') {
- if ($this->source->is_public) {
- $fullRepoUrl = "{$this->source->html_url}/{$customRepository}";
- $base_command = "{$base_command} {$this->source->html_url}/{$customRepository}";
- } else {
- $github_access_token = generateGithubInstallationToken($this->source);
-
- if ($exec_in_docker) {
- $base_command = "{$base_command} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}.git";
- $fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}.git";
- } else {
- $base_command = "{$base_command} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}";
- $fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}";
- }
- }
-
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, $base_command));
- } else {
- $commands->push($base_command);
- }
-
- return [
- 'commands' => $commands->implode(' && '),
- 'branch' => $branch,
- 'fullRepoUrl' => $fullRepoUrl,
- ];
- }
- }
-
- if ($this->deploymentType() === 'deploy_key') {
- $fullRepoUrl = $customRepository;
- $private_key = data_get($this, 'private_key.private_key');
- if (is_null($private_key)) {
- throw new RuntimeException('Private key not found. Please add a private key to the application and try again.');
- }
- $private_key = base64_encode($private_key);
- $base_comamnd = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$base_command} {$customRepository}";
-
- if ($exec_in_docker) {
- $commands = collect([
- executeInDocker($deployment_uuid, 'mkdir -p /root/.ssh'),
- executeInDocker($deployment_uuid, "echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null"),
- executeInDocker($deployment_uuid, 'chmod 600 /root/.ssh/id_rsa'),
- ]);
- } else {
- $commands = collect([
- 'mkdir -p /root/.ssh',
- "echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null",
- 'chmod 600 /root/.ssh/id_rsa',
- ]);
- }
-
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, $base_comamnd));
- } else {
- $commands->push($base_comamnd);
- }
-
- return [
- 'commands' => $commands->implode(' && '),
- 'branch' => $branch,
- 'fullRepoUrl' => $fullRepoUrl,
- ];
- }
-
- if ($this->deploymentType() === 'other') {
- $fullRepoUrl = $customRepository;
- $base_command = "{$base_command} {$customRepository}";
- $base_command = $this->setGitImportSettings($deployment_uuid, $base_command, public: true);
-
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, $base_command));
- } else {
- $commands->push($base_command);
- }
-
- return [
- 'commands' => $commands->implode(' && '),
- 'branch' => $branch,
- 'fullRepoUrl' => $fullRepoUrl,
- ];
- }
- }
-
- public function generateGitImportCommands(string $deployment_uuid, int $pull_request_id = 0, ?string $git_type = null, bool $exec_in_docker = true, bool $only_checkout = false, ?string $custom_base_dir = null, ?string $commit = null)
- {
- $branch = $this->git_branch;
- ['repository' => $customRepository, 'port' => $customPort] = $this->customRepository();
- $baseDir = $custom_base_dir ?? $this->generateBaseDir($deployment_uuid);
- $commands = collect([]);
- $git_clone_command = "git clone -b \"{$this->git_branch}\"";
- if ($only_checkout) {
- $git_clone_command = "git clone --no-checkout -b \"{$this->git_branch}\"";
- }
- if ($pull_request_id !== 0) {
- $pr_branch_name = "pr-{$pull_request_id}-coolify";
- }
- if ($this->deploymentType() === 'source') {
- $source_html_url = data_get($this, 'source.html_url');
- $url = parse_url(filter_var($source_html_url, FILTER_SANITIZE_URL));
- $source_html_url_host = $url['host'];
- $source_html_url_scheme = $url['scheme'];
-
- if ($this->source->getMorphClass() === \App\Models\GithubApp::class) {
- if ($this->source->is_public) {
- $fullRepoUrl = "{$this->source->html_url}/{$customRepository}";
- $git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$customRepository} {$baseDir}";
- if (! $only_checkout) {
- $git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command, public: true);
- }
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, $git_clone_command));
- } else {
- $commands->push($git_clone_command);
- }
- } else {
- $github_access_token = generateGithubInstallationToken($this->source);
- if ($exec_in_docker) {
- $git_clone_command = "{$git_clone_command} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}.git {$baseDir}";
- $fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}.git";
- } else {
- $git_clone_command = "{$git_clone_command} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository} {$baseDir}";
- $fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}";
- }
- if (! $only_checkout) {
- $git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command, public: false);
- }
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, $git_clone_command));
- } else {
- $commands->push($git_clone_command);
- }
- }
- if ($pull_request_id !== 0) {
- $branch = "pull/{$pull_request_id}/head:$pr_branch_name";
-
- $git_checkout_command = $this->buildGitCheckoutCommand($pr_branch_name);
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, "cd {$baseDir} && git fetch origin {$branch} && $git_checkout_command"));
- } else {
- $commands->push("cd {$baseDir} && git fetch origin {$branch} && $git_checkout_command");
- }
- }
-
- return [
- 'commands' => $commands->implode(' && '),
- 'branch' => $branch,
- 'fullRepoUrl' => $fullRepoUrl,
- ];
- }
- }
- if ($this->deploymentType() === 'deploy_key') {
- $fullRepoUrl = $customRepository;
- $private_key = data_get($this, 'private_key.private_key');
- if (is_null($private_key)) {
- throw new RuntimeException('Private key not found. Please add a private key to the application and try again.');
- }
- $private_key = base64_encode($private_key);
- $git_clone_command_base = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$customRepository} {$baseDir}";
- if ($only_checkout) {
- $git_clone_command = $git_clone_command_base;
- } else {
- $git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command_base);
- }
- if ($exec_in_docker) {
- $commands = collect([
- executeInDocker($deployment_uuid, 'mkdir -p /root/.ssh'),
- executeInDocker($deployment_uuid, "echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null"),
- executeInDocker($deployment_uuid, 'chmod 600 /root/.ssh/id_rsa'),
- ]);
- } else {
- $commands = collect([
- 'mkdir -p /root/.ssh',
- "echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null",
- 'chmod 600 /root/.ssh/id_rsa',
- ]);
- }
- if ($pull_request_id !== 0) {
- if ($git_type === 'gitlab') {
- $branch = "merge-requests/{$pull_request_id}/head:$pr_branch_name";
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, "echo 'Checking out $branch'"));
- } else {
- $commands->push("echo 'Checking out $branch'");
- }
- $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name);
- } elseif ($git_type === 'github' || $git_type === 'gitea') {
- $branch = "pull/{$pull_request_id}/head:$pr_branch_name";
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, "echo 'Checking out $branch'"));
- } else {
- $commands->push("echo 'Checking out $branch'");
- }
- $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name);
- } elseif ($git_type === 'bitbucket') {
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, "echo 'Checking out $branch'"));
- } else {
- $commands->push("echo 'Checking out $branch'");
- }
- $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" ".$this->buildGitCheckoutCommand($commit);
- }
- }
-
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, $git_clone_command));
- } else {
- $commands->push($git_clone_command);
- }
-
- return [
- 'commands' => $commands->implode(' && '),
- 'branch' => $branch,
- 'fullRepoUrl' => $fullRepoUrl,
- ];
- }
- if ($this->deploymentType() === 'other') {
- $fullRepoUrl = $customRepository;
- $git_clone_command = "{$git_clone_command} {$customRepository} {$baseDir}";
- $git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command, public: true);
-
- if ($pull_request_id !== 0) {
- if ($git_type === 'gitlab') {
- $branch = "merge-requests/{$pull_request_id}/head:$pr_branch_name";
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, "echo 'Checking out $branch'"));
- } else {
- $commands->push("echo 'Checking out $branch'");
- }
- $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name);
- } elseif ($git_type === 'github' || $git_type === 'gitea') {
- $branch = "pull/{$pull_request_id}/head:$pr_branch_name";
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, "echo 'Checking out $branch'"));
- } else {
- $commands->push("echo 'Checking out $branch'");
- }
- $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name);
- } elseif ($git_type === 'bitbucket') {
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, "echo 'Checking out $branch'"));
- } else {
- $commands->push("echo 'Checking out $branch'");
- }
- $git_clone_command = "{$git_clone_command} && cd {$baseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" ".$this->buildGitCheckoutCommand($commit);
- }
- }
-
- if ($exec_in_docker) {
- $commands->push(executeInDocker($deployment_uuid, $git_clone_command));
- } else {
- $commands->push($git_clone_command);
- }
-
- return [
- 'commands' => $commands->implode(' && '),
- 'branch' => $branch,
- 'fullRepoUrl' => $fullRepoUrl,
- ];
- }
- }
-
- public function oldRawParser()
- {
- try {
- $yaml = Yaml::parse($this->docker_compose_raw);
- } catch (\Exception $e) {
- throw new \Exception($e->getMessage());
- }
- $services = data_get($yaml, 'services');
-
- $commands = collect([]);
- $services = collect($services)->map(function ($service) use ($commands) {
- $serviceVolumes = collect(data_get($service, 'volumes', []));
- if ($serviceVolumes->count() > 0) {
- foreach ($serviceVolumes as $volume) {
- $workdir = $this->workdir();
- $type = null;
- $source = null;
- if (is_string($volume)) {
- $source = str($volume)->before(':');
- if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
- $type = str('bind');
- }
- } elseif (is_array($volume)) {
- $type = data_get_str($volume, 'type');
- $source = data_get_str($volume, 'source');
- }
- if ($type?->value() === 'bind') {
- if ($source->value() === '/var/run/docker.sock') {
- continue;
- }
- if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
- continue;
- }
- if ($source->startsWith('.')) {
- $source = $source->after('.');
- $source = $workdir.$source;
- }
- $commands->push("mkdir -p $source > /dev/null 2>&1 || true");
- }
- }
- }
- $labels = collect(data_get($service, 'labels', []));
- if (! $labels->contains('coolify.managed')) {
- $labels->push('coolify.managed=true');
- }
- if (! $labels->contains('coolify.applicationId')) {
- $labels->push('coolify.applicationId='.$this->id);
- }
- if (! $labels->contains('coolify.type')) {
- $labels->push('coolify.type=application');
- }
- data_set($service, 'labels', $labels->toArray());
-
- return $service;
- });
- data_set($yaml, 'services', $services->toArray());
- $this->docker_compose_raw = Yaml::dump($yaml, 10, 2);
-
- instant_remote_process($commands, $this->destination->server, false);
- }
-
- public function parse(int $pull_request_id = 0, ?int $preview_id = null)
- {
- if ((int) $this->compose_parsing_version >= 3) {
- return newParser($this, $pull_request_id, $preview_id);
- } elseif ($this->docker_compose_raw) {
- return parseDockerComposeFile(resource: $this, isNew: false, pull_request_id: $pull_request_id, preview_id: $preview_id);
- } else {
- return collect([]);
- }
- }
-
- public function loadComposeFile($isInit = false)
- {
- $initialDockerComposeLocation = $this->docker_compose_location;
- if ($isInit && $this->docker_compose_raw) {
- return;
- }
- $uuid = new Cuid2;
- ['commands' => $cloneCommand] = $this->generateGitImportCommands(deployment_uuid: $uuid, only_checkout: true, exec_in_docker: false, custom_base_dir: '.');
- $workdir = rtrim($this->base_directory, '/');
- $composeFile = $this->docker_compose_location;
- $fileList = collect([".$workdir$composeFile"]);
- $gitRemoteStatus = $this->getGitRemoteStatus(deployment_uuid: $uuid);
- if (! $gitRemoteStatus['is_accessible']) {
- throw new \RuntimeException("Failed to read Git source:\n\n{$gitRemoteStatus['error']}");
- }
- $getGitVersion = instant_remote_process(['git --version'], $this->destination->server, false);
- $gitVersion = str($getGitVersion)->explode(' ')->last();
-
- if (version_compare($gitVersion, '2.35.1', '<')) {
- $fileList = $fileList->map(function ($file) {
- $parts = explode('/', trim($file, '.'));
- $paths = collect();
- $currentPath = '';
- foreach ($parts as $part) {
- $currentPath .= ($currentPath ? '/' : '').$part;
- if (str($currentPath)->isNotEmpty()) {
- $paths->push($currentPath);
- }
- }
-
- return $paths;
- })->flatten()->unique()->values();
- $commands = collect([
- "rm -rf /tmp/{$uuid}",
- "mkdir -p /tmp/{$uuid}",
- "cd /tmp/{$uuid}",
- $cloneCommand,
- 'git sparse-checkout init',
- "git sparse-checkout set {$fileList->implode(' ')}",
- 'git read-tree -mu HEAD',
- "cat .$workdir$composeFile",
- ]);
- } else {
- $commands = collect([
- "rm -rf /tmp/{$uuid}",
- "mkdir -p /tmp/{$uuid}",
- "cd /tmp/{$uuid}",
- $cloneCommand,
- 'git sparse-checkout init --cone',
- "git sparse-checkout set {$fileList->implode(' ')}",
- 'git read-tree -mu HEAD',
- "cat .$workdir$composeFile",
- ]);
- }
- try {
- $composeFileContent = instant_remote_process($commands, $this->destination->server);
- } catch (\Exception $e) {
- if (str($e->getMessage())->contains('No such file')) {
- throw new \RuntimeException("Docker Compose file not found at: $workdir$composeFile Check if you used the right extension (.yaml or .yml) in the compose file name.");
- }
- if (str($e->getMessage())->contains('fatal: repository') && str($e->getMessage())->contains('does not exist')) {
- if ($this->deploymentType() === 'deploy_key') {
- throw new \RuntimeException('Your deploy key does not have access to the repository. Please check your deploy key and try again.');
- }
- throw new \RuntimeException('Repository does not exist. Please check your repository URL and try again.');
- }
- throw new \RuntimeException($e->getMessage());
- } finally {
- $this->docker_compose_location = $initialDockerComposeLocation;
- $this->save();
- $commands = collect([
- "rm -rf /tmp/{$uuid}",
- ]);
- instant_remote_process($commands, $this->destination->server, false);
- }
- if ($composeFileContent) {
- $this->docker_compose_raw = $composeFileContent;
- $this->save();
- $parsedServices = $this->parse();
- if ($this->docker_compose_domains) {
- $json = collect(json_decode($this->docker_compose_domains));
- $names = collect(data_get($parsedServices, 'services'))->keys()->toArray();
- $jsonNames = $json->keys()->toArray();
- $diff = array_diff($jsonNames, $names);
- $json = $json->filter(function ($value, $key) use ($diff) {
- return ! in_array($key, $diff);
- });
- if ($json) {
- $this->docker_compose_domains = json_encode($json);
- } else {
- $this->docker_compose_domains = null;
- }
- $this->save();
- }
-
- return [
- 'parsedServices' => $parsedServices,
- 'initialDockerComposeLocation' => $this->docker_compose_location,
- ];
- } else {
- throw new \RuntimeException("Docker Compose file not found at: $workdir$composeFile Check if you used the right extension (.yaml or .yml) in the compose file name.");
- }
- }
-
- public function parseContainerLabels(?ApplicationPreview $preview = null)
- {
- $customLabels = data_get($this, 'custom_labels');
- if (! $customLabels) {
- return;
- }
- if (base64_encode(base64_decode($customLabels, true)) !== $customLabels) {
- $this->custom_labels = str($customLabels)->replace(',', "\n");
- $this->custom_labels = base64_encode($customLabels);
- }
- $customLabels = base64_decode($this->custom_labels);
- if (mb_detect_encoding($customLabels, 'ASCII', true) === false) {
- $customLabels = str(implode('|coolify|', generateLabelsApplication($this, $preview)))->replace('|coolify|', "\n");
- }
- $this->custom_labels = base64_encode($customLabels);
- $this->save();
-
- return $customLabels;
- }
-
- public function fqdns(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->fqdn)
- ? []
- : explode(',', $this->fqdn),
- );
- }
-
- protected function buildGitCheckoutCommand($target): string
- {
- $command = "git checkout $target";
-
- if ($this->settings->is_git_submodules_enabled) {
- $command .= ' && git submodule update --init --recursive';
- }
-
- return $command;
- }
-
- public function watchPaths(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if ($value) {
- return trim($value);
- }
- }
- );
- }
-
- public function isWatchPathsTriggered(Collection $modified_files): bool
- {
- if (is_null($this->watch_paths)) {
- return false;
- }
- $watch_paths = collect(explode("\n", $this->watch_paths));
- $matches = $modified_files->filter(function ($file) use ($watch_paths) {
- return $watch_paths->contains(function ($glob) use ($file) {
- return fnmatch($glob, $file);
- });
- });
-
- return $matches->count() > 0;
- }
-
- public function getFilesFromServer(bool $isInit = false)
- {
- getFilesystemVolumesFromServer($this, $isInit);
- }
-
- public function parseHealthcheckFromDockerfile($dockerfile, bool $isInit = false)
- {
- if (str($dockerfile)->contains('HEALTHCHECK') && ($this->isHealthcheckDisabled() || $isInit)) {
- $healthcheckCommand = null;
- $lines = $dockerfile->toArray();
- foreach ($lines as $line) {
- $trimmedLine = trim($line);
- if (str_starts_with($trimmedLine, 'HEALTHCHECK')) {
- $healthcheckCommand .= trim($trimmedLine, '\\ ');
-
- continue;
- }
- if (isset($healthcheckCommand) && str_contains($trimmedLine, '\\')) {
- $healthcheckCommand .= ' '.trim($trimmedLine, '\\ ');
- }
- if (isset($healthcheckCommand) && ! str_contains($trimmedLine, '\\') && ! empty($healthcheckCommand)) {
- $healthcheckCommand .= ' '.$trimmedLine;
- break;
- }
- }
- if (str($healthcheckCommand)->isNotEmpty()) {
- $interval = str($healthcheckCommand)->match('/--interval=(\d+)/');
- $timeout = str($healthcheckCommand)->match('/--timeout=(\d+)/');
- $start_period = str($healthcheckCommand)->match('/--start-period=(\d+)/');
- $start_interval = str($healthcheckCommand)->match('/--start-interval=(\d+)/');
- $retries = str($healthcheckCommand)->match('/--retries=(\d+)/');
- if ($interval->isNotEmpty()) {
- $this->health_check_interval = $interval->toInteger();
- }
- if ($timeout->isNotEmpty()) {
- $this->health_check_timeout = $timeout->toInteger();
- }
- if ($start_period->isNotEmpty()) {
- $this->health_check_start_period = $start_period->toInteger();
- }
- // if ($start_interval) {
- // $this->health_check_start_interval = $start_interval->value();
- // }
- if ($retries->isNotEmpty()) {
- $this->health_check_retries = $retries->toInteger();
- }
- if ($interval || $timeout || $start_period || $start_interval || $retries) {
- $this->custom_healthcheck_found = true;
- $this->save();
- }
- }
- }
- }
-
- public function generate_preview_fqdn(int $pull_request_id)
- {
- $preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->id, $pull_request_id);
- if (is_null(data_get($preview, 'fqdn')) && $this->fqdn) {
- if (str($this->fqdn)->contains(',')) {
- $url = Url::fromString(str($this->fqdn)->explode(',')[0]);
- $preview_fqdn = getFqdnWithoutPort(str($this->fqdn)->explode(',')[0]);
- } else {
- $url = Url::fromString($this->fqdn);
- if (data_get($preview, 'fqdn')) {
- $preview_fqdn = getFqdnWithoutPort(data_get($preview, 'fqdn'));
- }
- }
- $template = $this->preview_url_template;
- $host = $url->getHost();
- $schema = $url->getScheme();
- $random = new Cuid2;
- $preview_fqdn = str_replace('{{random}}', $random, $template);
- $preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
- $preview_fqdn = str_replace('{{pr_id}}', $pull_request_id, $preview_fqdn);
- $preview_fqdn = "$schema://$preview_fqdn";
- $preview->fqdn = $preview_fqdn;
- $preview->save();
- }
-
- return $preview;
- }
-
- public static function getDomainsByUuid(string $uuid): array
- {
- $application = self::where('uuid', $uuid)->first();
-
- if ($application) {
- return $application->fqdns;
- }
-
- return [];
- }
-
- public function getCpuMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- if ($server->isMetricsEnabled()) {
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['percent']];
- });
-
- return $parsedCollection->toArray();
- }
- }
-
- public function getMemoryMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- if ($server->isMetricsEnabled()) {
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['used']];
- });
-
- return $parsedCollection->toArray();
- }
- }
-
- public function getLimits(): array
- {
- return [
- 'limits_memory' => $this->limits_memory,
- 'limits_memory_swap' => $this->limits_memory_swap,
- 'limits_memory_swappiness' => $this->limits_memory_swappiness,
- 'limits_memory_reservation' => $this->limits_memory_reservation,
- 'limits_cpus' => $this->limits_cpus,
- 'limits_cpuset' => $this->limits_cpuset,
- 'limits_cpu_shares' => $this->limits_cpu_shares,
- ];
- }
-
- public function generateConfig($is_json = false)
- {
- $generator = new ConfigurationGenerator($this);
-
- if ($is_json) {
- return $generator->toJson();
- }
-
- return $generator->toArray();
- }
-
- public function setConfig($config)
- {
- $validator = Validator::make(['config' => $config], [
- 'config' => 'required|json',
- ]);
- if ($validator->fails()) {
- throw new \Exception('Invalid JSON format');
- }
- $config = json_decode($config, true);
-
- $deepValidator = Validator::make(['config' => $config], [
- 'config.build_pack' => 'required|string',
- 'config.base_directory' => 'required|string',
- 'config.publish_directory' => 'required|string',
- 'config.ports_exposes' => 'required|string',
- 'config.settings.is_static' => 'required|boolean',
- ]);
- if ($deepValidator->fails()) {
- throw new \Exception('Invalid data');
- }
- $config = $deepValidator->validated()['config'];
-
- try {
- $settings = data_get($config, 'settings', []);
- data_forget($config, 'settings');
- $this->update($config);
- $this->settings()->update($settings);
- } catch (\Exception $e) {
- throw new \Exception('Failed to update application settings');
- }
- }
-}
diff --git a/app/Models/ApplicationDeploymentQueue.php b/app/Models/ApplicationDeploymentQueue.php
deleted file mode 100644
index fd8f1cba2e..0000000000
--- a/app/Models/ApplicationDeploymentQueue.php
+++ /dev/null
@@ -1,117 +0,0 @@
- ['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 = [];
-
- public function application(): Attribute
- {
- return Attribute::make(
- get: fn () => Application::find($this->application_id),
- );
- }
-
- public function server(): Attribute
- {
- return Attribute::make(
- get: fn () => Server::find($this->server_id),
- );
- }
-
- public function setStatus(string $status)
- {
- $this->update([
- 'status' => $status,
- ]);
- }
-
- public function getOutput($name)
- {
- if (! $this->logs) {
- return null;
- }
-
- return collect(json_decode($this->logs))->where('name', $name)->first()?->output ?? null;
- }
-
- public function getHorizonJobStatus()
- {
- return getJobStatus($this->horizon_job_id);
- }
-
- public function commitMessage()
- {
- if (empty($this->commit_message) || is_null($this->commit_message)) {
- return null;
- }
-
- return str($this->commit_message)->value();
- }
-
- public function addLogEntry(string $message, string $type = 'stdout', bool $hidden = false)
- {
- if ($type === 'error') {
- $type = 'stderr';
- }
- $message = str($message)->trim();
- if ($message->startsWith('╔')) {
- $message = "\n".$message;
- }
- $newLogEntry = [
- 'command' => null,
- 'output' => remove_iip($message),
- 'type' => $type,
- 'timestamp' => Carbon::now('UTC'),
- 'hidden' => $hidden,
- 'batch' => 1,
- ];
- if ($this->logs) {
- $previousLogs = json_decode($this->logs, associative: true, flags: JSON_THROW_ON_ERROR);
- $newLogEntry['order'] = count($previousLogs) + 1;
- $previousLogs[] = $newLogEntry;
- $this->update([
- 'logs' => json_encode($previousLogs, flags: JSON_THROW_ON_ERROR),
- ]);
- } else {
- $this->update([
- 'logs' => json_encode([$newLogEntry], flags: JSON_THROW_ON_ERROR),
- ]);
- }
- }
-}
diff --git a/app/Models/ApplicationPreview.php b/app/Models/ApplicationPreview.php
deleted file mode 100644
index bf2bf05bf1..0000000000
--- a/app/Models/ApplicationPreview.php
+++ /dev/null
@@ -1,75 +0,0 @@
-application->destination->server;
- $composeFile = $preview->application->parse(pull_request_id: $preview->pull_request_id);
- $volumes = data_get($composeFile, 'volumes');
- $networks = data_get($composeFile, 'networks');
- $networkKeys = collect($networks)->keys();
- $volumeKeys = collect($volumes)->keys();
- $volumeKeys->each(function ($key) use ($server) {
- instant_remote_process(["docker volume rm -f $key"], $server, false);
- });
- $networkKeys->each(function ($key) use ($server) {
- instant_remote_process(["docker network disconnect $key coolify-proxy"], $server, false);
- instant_remote_process(["docker network rm $key"], $server, false);
- });
- }
- });
- static::saving(function ($preview) {
- if ($preview->isDirty('status')) {
- $preview->forceFill(['last_online_at' => now()]);
- }
- });
- }
-
- public static function findPreviewByApplicationAndPullId(int $application_id, int $pull_request_id)
- {
- return self::where('application_id', $application_id)->where('pull_request_id', $pull_request_id)->firstOrFail();
- }
-
- public function isRunning()
- {
- return (bool) str($this->status)->startsWith('running');
- }
-
- public function application()
- {
- return $this->belongsTo(Application::class);
- }
-
- public function generate_preview_fqdn_compose()
- {
- $domains = collect(json_decode($this->application->docker_compose_domains)) ?? collect();
- foreach ($domains as $service_name => $domain) {
- $domain = data_get($domain, 'domain');
- $url = Url::fromString($domain);
- $template = $this->application->preview_url_template;
- $host = $url->getHost();
- $schema = $url->getScheme();
- $random = new Cuid2;
- $preview_fqdn = str_replace('{{random}}', $random, $template);
- $preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
- $preview_fqdn = str_replace('{{pr_id}}', $this->pull_request_id, $preview_fqdn);
- $preview_fqdn = "$schema://$preview_fqdn";
- $docker_compose_domains = data_get($this, 'docker_compose_domains');
- $docker_compose_domains = json_decode($docker_compose_domains, true);
- $docker_compose_domains[$service_name]['domain'] = $preview_fqdn;
- $docker_compose_domains = json_encode($docker_compose_domains);
- $this->docker_compose_domains = $docker_compose_domains;
- $this->save();
- }
- }
-}
diff --git a/app/Models/ApplicationSetting.php b/app/Models/ApplicationSetting.php
deleted file mode 100644
index c7624fdaa1..0000000000
--- a/app/Models/ApplicationSetting.php
+++ /dev/null
@@ -1,40 +0,0 @@
- 'boolean',
- 'is_auto_deploy_enabled' => 'boolean',
- 'is_force_https_enabled' => 'boolean',
- 'is_debug_enabled' => 'boolean',
- 'is_preview_deployments_enabled' => 'boolean',
- 'is_git_submodules_enabled' => 'boolean',
- 'is_git_lfs_enabled' => 'boolean',
- ];
-
- protected $guarded = [];
-
- public function isStatic(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if ($value) {
- $this->application->ports_exposes = 80;
- }
- $this->application->save();
-
- return $value;
- }
- );
- }
-
- public function application()
- {
- return $this->belongsTo(Application::class);
- }
-}
diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php
deleted file mode 100644
index 727abed5fe..0000000000
--- a/app/Models/BaseModel.php
+++ /dev/null
@@ -1,36 +0,0 @@
-uuid) {
- $model->uuid = (string) new Cuid2;
- }
- });
- }
-
- public function sanitizedName(): Attribute
- {
- return new Attribute(
- get: fn () => sanitize_string($this->getRawOriginal('name')),
- );
- }
-
- public function image(): Attribute
- {
- return new Attribute(
- get: fn () => sanitize_string($this->getRawOriginal('image')),
- );
- }
-}
diff --git a/app/Models/DiscordNotificationSettings.php b/app/Models/DiscordNotificationSettings.php
deleted file mode 100644
index 619393ddc0..0000000000
--- a/app/Models/DiscordNotificationSettings.php
+++ /dev/null
@@ -1,59 +0,0 @@
- 'boolean',
- 'discord_webhook_url' => 'encrypted',
-
- 'deployment_success_discord_notifications' => 'boolean',
- 'deployment_failure_discord_notifications' => 'boolean',
- 'status_change_discord_notifications' => 'boolean',
- 'backup_success_discord_notifications' => 'boolean',
- 'backup_failure_discord_notifications' => 'boolean',
- 'scheduled_task_success_discord_notifications' => 'boolean',
- 'scheduled_task_failure_discord_notifications' => 'boolean',
- 'docker_cleanup_discord_notifications' => 'boolean',
- 'server_disk_usage_discord_notifications' => 'boolean',
- 'server_reachable_discord_notifications' => 'boolean',
- 'server_unreachable_discord_notifications' => 'boolean',
- ];
-
- public function team()
- {
- return $this->belongsTo(Team::class);
- }
-
- public function isEnabled()
- {
- return $this->discord_enabled;
- }
-}
diff --git a/app/Models/DockerCleanupExecution.php b/app/Models/DockerCleanupExecution.php
deleted file mode 100644
index 405037e307..0000000000
--- a/app/Models/DockerCleanupExecution.php
+++ /dev/null
@@ -1,15 +0,0 @@
-belongsTo(Server::class);
- }
-}
diff --git a/app/Models/EmailNotificationSettings.php b/app/Models/EmailNotificationSettings.php
deleted file mode 100644
index ae118986fc..0000000000
--- a/app/Models/EmailNotificationSettings.php
+++ /dev/null
@@ -1,79 +0,0 @@
- 'boolean',
- 'smtp_from_address' => 'encrypted',
- 'smtp_from_name' => 'encrypted',
- 'smtp_recipients' => 'encrypted',
- 'smtp_host' => 'encrypted',
- 'smtp_port' => 'integer',
- 'smtp_username' => 'encrypted',
- 'smtp_password' => 'encrypted',
- 'smtp_timeout' => 'integer',
-
- 'resend_enabled' => 'boolean',
- 'resend_api_key' => 'encrypted',
-
- 'use_instance_email_settings' => 'boolean',
-
- 'deployment_success_email_notifications' => 'boolean',
- 'deployment_failure_email_notifications' => 'boolean',
- 'status_change_email_notifications' => 'boolean',
- 'backup_success_email_notifications' => 'boolean',
- 'backup_failure_email_notifications' => 'boolean',
- 'scheduled_task_success_email_notifications' => 'boolean',
- 'scheduled_task_failure_email_notifications' => 'boolean',
- 'server_disk_usage_email_notifications' => 'boolean',
- ];
-
- public function team()
- {
- return $this->belongsTo(Team::class);
- }
-
- public function isEnabled()
- {
- if (isCloud()) {
- return true;
- }
-
- return $this->smtp_enabled || $this->resend_enabled || $this->use_instance_email_settings;
- }
-}
diff --git a/app/Models/Environment.php b/app/Models/Environment.php
deleted file mode 100644
index b8f1090d8d..0000000000
--- a/app/Models/Environment.php
+++ /dev/null
@@ -1,128 +0,0 @@
- ['type' => 'integer'],
- 'name' => ['type' => 'string'],
- 'project_id' => ['type' => 'integer'],
- 'created_at' => ['type' => 'string'],
- 'updated_at' => ['type' => 'string'],
- 'description' => ['type' => 'string'],
- ]
-)]
-class Environment extends BaseModel
-{
- protected $guarded = [];
-
- protected static function booted()
- {
- static::deleting(function ($environment) {
- $shared_variables = $environment->environment_variables();
- foreach ($shared_variables as $shared_variable) {
- $shared_variable->delete();
- }
- });
- }
-
- public function isEmpty()
- {
- return $this->applications()->count() == 0 &&
- $this->redis()->count() == 0 &&
- $this->postgresqls()->count() == 0 &&
- $this->mysqls()->count() == 0 &&
- $this->keydbs()->count() == 0 &&
- $this->dragonflies()->count() == 0 &&
- $this->clickhouses()->count() == 0 &&
- $this->mariadbs()->count() == 0 &&
- $this->mongodbs()->count() == 0 &&
- $this->services()->count() == 0;
- }
-
- public function environment_variables()
- {
- return $this->hasMany(SharedEnvironmentVariable::class);
- }
-
- public function applications()
- {
- return $this->hasMany(Application::class);
- }
-
- public function postgresqls()
- {
- return $this->hasMany(StandalonePostgresql::class);
- }
-
- public function redis()
- {
- return $this->hasMany(StandaloneRedis::class);
- }
-
- public function mongodbs()
- {
- return $this->hasMany(StandaloneMongodb::class);
- }
-
- public function mysqls()
- {
- return $this->hasMany(StandaloneMysql::class);
- }
-
- public function mariadbs()
- {
- return $this->hasMany(StandaloneMariadb::class);
- }
-
- public function keydbs()
- {
- return $this->hasMany(StandaloneKeydb::class);
- }
-
- public function dragonflies()
- {
- return $this->hasMany(StandaloneDragonfly::class);
- }
-
- public function clickhouses()
- {
- return $this->hasMany(StandaloneClickhouse::class);
- }
-
- public function databases()
- {
- $postgresqls = $this->postgresqls;
- $redis = $this->redis;
- $mongodbs = $this->mongodbs;
- $mysqls = $this->mysqls;
- $mariadbs = $this->mariadbs;
- $keydbs = $this->keydbs;
- $dragonflies = $this->dragonflies;
- $clickhouses = $this->clickhouses;
-
- return $postgresqls->concat($redis)->concat($mongodbs)->concat($mysqls)->concat($mariadbs)->concat($keydbs)->concat($dragonflies)->concat($clickhouses);
- }
-
- public function project()
- {
- return $this->belongsTo(Project::class);
- }
-
- public function services()
- {
- return $this->hasMany(Service::class);
- }
-
- protected function name(): Attribute
- {
- return Attribute::make(
- set: fn (string $value) => str($value)->lower()->trim()->replace('/', '-')->toString(),
- );
- }
-}
diff --git a/app/Models/EnvironmentVariable.php b/app/Models/EnvironmentVariable.php
deleted file mode 100644
index 5f686de60d..0000000000
--- a/app/Models/EnvironmentVariable.php
+++ /dev/null
@@ -1,218 +0,0 @@
- ['type' => 'integer'],
- 'uuid' => ['type' => 'string'],
- 'resourceable_type' => ['type' => 'string'],
- 'resourceable_id' => ['type' => 'integer'],
- 'is_build_time' => ['type' => 'boolean'],
- 'is_literal' => ['type' => 'boolean'],
- 'is_multiline' => ['type' => 'boolean'],
- 'is_preview' => ['type' => 'boolean'],
- 'is_shared' => ['type' => 'boolean'],
- 'is_shown_once' => ['type' => 'boolean'],
- 'key' => ['type' => 'string'],
- 'value' => ['type' => 'string'],
- 'real_value' => ['type' => 'string'],
- 'version' => ['type' => 'string'],
- 'created_at' => ['type' => 'string'],
- 'updated_at' => ['type' => 'string'],
- ]
-)]
-class EnvironmentVariable extends BaseModel
-{
- protected $guarded = [];
-
- protected $casts = [
- 'key' => 'string',
- 'value' => 'encrypted',
- 'is_build_time' => 'boolean',
- 'is_multiline' => 'boolean',
- 'is_preview' => 'boolean',
- 'version' => 'string',
- 'resourceable_type' => 'string',
- 'resourceable_id' => 'integer',
- ];
-
- protected $appends = ['real_value', 'is_shared', 'is_really_required'];
-
- protected static function booted()
- {
- static::created(function (EnvironmentVariable $environment_variable) {
- if ($environment_variable->resourceable_type === Application::class && ! $environment_variable->is_preview) {
- $found = ModelsEnvironmentVariable::where('key', $environment_variable->key)
- ->where('resourceable_type', Application::class)
- ->where('resourceable_id', $environment_variable->resourceable_id)
- ->where('is_preview', true)
- ->first();
-
- if (! $found) {
- $application = Application::find($environment_variable->resourceable_id);
- if ($application && $application->build_pack !== 'dockerfile') {
- ModelsEnvironmentVariable::create([
- 'key' => $environment_variable->key,
- 'value' => $environment_variable->value,
- 'is_build_time' => $environment_variable->is_build_time,
- 'is_multiline' => $environment_variable->is_multiline ?? false,
- 'resourceable_type' => Application::class,
- 'resourceable_id' => $environment_variable->resourceable_id,
- 'is_preview' => true,
- ]);
- }
- }
- }
- $environment_variable->update([
- 'version' => config('constants.coolify.version'),
- ]);
- });
-
- static::saving(function (EnvironmentVariable $environmentVariable) {
- $environmentVariable->updateIsShared();
- });
- }
-
- public function service()
- {
- return $this->belongsTo(Service::class);
- }
-
- protected function value(): Attribute
- {
- return Attribute::make(
- get: fn (?string $value = null) => $this->get_environment_variables($value),
- set: fn (?string $value = null) => $this->set_environment_variables($value),
- );
- }
-
- /**
- * Get the parent resourceable model.
- */
- public function resourceable()
- {
- return $this->morphTo();
- }
-
- public function resource()
- {
- return $this->resourceable;
- }
-
- public function realValue(): Attribute
- {
- return Attribute::make(
- get: function () {
- if (! $this->relationLoaded('resourceable')) {
- $this->load('resourceable');
- }
- $resource = $this->resourceable;
- if (! $resource) {
- return null;
- }
-
- return $this->get_real_environment_variables($this->value, $resource);
- }
- );
- }
-
- protected function isReallyRequired(): Attribute
- {
- return Attribute::make(
- get: fn () => $this->is_required && str($this->real_value)->isEmpty(),
- );
- }
-
- protected function isShared(): Attribute
- {
- return Attribute::make(
- get: function () {
- $type = str($this->value)->after('{{')->before('.')->value;
- if (str($this->value)->startsWith('{{'.$type) && str($this->value)->endsWith('}}')) {
- return true;
- }
-
- return false;
- }
- );
- }
-
- private function get_real_environment_variables(?string $environment_variable = null, $resource = null)
- {
- if ((is_null($environment_variable) && $environment_variable === '') || is_null($resource)) {
- return null;
- }
- $environment_variable = trim($environment_variable);
- $sharedEnvsFound = str($environment_variable)->matchAll('/{{(.*?)}}/');
- if ($sharedEnvsFound->isEmpty()) {
- return $environment_variable;
- }
- foreach ($sharedEnvsFound as $sharedEnv) {
- $type = str($sharedEnv)->match('/(.*?)\./');
- if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
- continue;
- }
- $variable = str($sharedEnv)->match('/\.(.*)/');
- if ($type->value() === 'environment') {
- $id = $resource->environment->id;
- } elseif ($type->value() === 'project') {
- $id = $resource->environment->project->id;
- } elseif ($type->value() === 'team') {
- $id = $resource->team()->id;
- }
- if (is_null($id)) {
- continue;
- }
- $environment_variable_found = SharedEnvironmentVariable::where('type', $type)->where('key', $variable)->where('team_id', $resource->team()->id)->where("{$type}_id", $id)->first();
- if ($environment_variable_found) {
- $environment_variable = str($environment_variable)->replace("{{{$sharedEnv}}}", $environment_variable_found->value);
- }
- }
-
- return str($environment_variable)->value();
- }
-
- private function get_environment_variables(?string $environment_variable = null): ?string
- {
- if (! $environment_variable) {
- return null;
- }
-
- return trim(decrypt($environment_variable));
- }
-
- private function set_environment_variables(?string $environment_variable = null): ?string
- {
- if (is_null($environment_variable) && $environment_variable === '') {
- return null;
- }
- $environment_variable = trim($environment_variable);
- $type = str($environment_variable)->after('{{')->before('.')->value;
- if (str($environment_variable)->startsWith('{{'.$type) && str($environment_variable)->endsWith('}}')) {
- return encrypt((string) str($environment_variable)->replace(' ', ''));
- }
-
- return encrypt($environment_variable);
- }
-
- protected function key(): Attribute
- {
- return Attribute::make(
- set: fn (string $value) => str($value)->trim()->replace(' ', '_')->value,
- );
- }
-
- protected function updateIsShared(): void
- {
- $type = str($this->value)->after('{{')->before('.')->value;
- $isShared = str($this->value)->startsWith('{{'.$type) && str($this->value)->endsWith('}}');
- $this->is_shared = $isShared;
- }
-}
diff --git a/app/Models/GithubApp.php b/app/Models/GithubApp.php
deleted file mode 100644
index 5550df81f2..0000000000
--- a/app/Models/GithubApp.php
+++ /dev/null
@@ -1,87 +0,0 @@
- 'boolean',
- 'type' => 'string',
- ];
-
- protected $hidden = [
- 'client_secret',
- 'webhook_secret',
- ];
-
- protected static function booted(): void
- {
- static::deleting(function (GithubApp $github_app) {
- $applications_count = Application::where('source_id', $github_app->id)->count();
- if ($applications_count > 0) {
- throw new \Exception('You cannot delete this GitHub App because it is in use by '.$applications_count.' application(s). Delete them first.');
- }
- $github_app->privateKey()->delete();
- });
- }
-
- public static function ownedByCurrentTeam()
- {
- return GithubApp::where(function ($query) {
- $query->where('team_id', currentTeam()->id)
- ->orWhere('is_system_wide', true);
- });
- }
-
- public static function public()
- {
- return GithubApp::where(function ($query) {
- $query->where(function ($q) {
- $q->where('team_id', currentTeam()->id)
- ->orWhere('is_system_wide', true);
- })->where('is_public', true);
- })->whereNotNull('app_id')->get();
- }
-
- public static function private()
- {
- return GithubApp::where(function ($query) {
- $query->where(function ($q) {
- $q->where('team_id', currentTeam()->id)
- ->orWhere('is_system_wide', true);
- })->where('is_public', false);
- })->whereNotNull('app_id')->get();
- }
-
- public function team()
- {
- return $this->belongsTo(Team::class);
- }
-
- public function applications()
- {
- return $this->morphMany(Application::class, 'source');
- }
-
- public function privateKey()
- {
- return $this->belongsTo(PrivateKey::class);
- }
-
- public function type(): Attribute
- {
- return Attribute::make(
- get: function () {
- if ($this->getMorphClass() === \App\Models\GithubApp::class) {
- return 'github';
- }
- },
- );
- }
-}
diff --git a/app/Models/GitlabApp.php b/app/Models/GitlabApp.php
deleted file mode 100644
index 2112a4a664..0000000000
--- a/app/Models/GitlabApp.php
+++ /dev/null
@@ -1,26 +0,0 @@
-id);
- }
-
- public function applications()
- {
- return $this->morphMany(Application::class, 'source');
- }
-
- public function privateKey()
- {
- return $this->belongsTo(PrivateKey::class);
- }
-}
diff --git a/app/Models/InstanceSettings.php b/app/Models/InstanceSettings.php
deleted file mode 100644
index 5b89bb401c..0000000000
--- a/app/Models/InstanceSettings.php
+++ /dev/null
@@ -1,127 +0,0 @@
- 'boolean',
- 'smtp_from_address' => 'encrypted',
- 'smtp_from_name' => 'encrypted',
- 'smtp_recipients' => 'encrypted',
- 'smtp_host' => 'encrypted',
- 'smtp_port' => 'integer',
- 'smtp_username' => 'encrypted',
- 'smtp_password' => 'encrypted',
- 'smtp_timeout' => 'integer',
-
- 'resend_enabled' => 'boolean',
- 'resend_api_key' => 'encrypted',
-
- 'allowed_ip_ranges' => 'array',
- 'is_auto_update_enabled' => 'boolean',
- 'auto_update_frequency' => 'string',
- 'update_check_frequency' => 'string',
- 'sentinel_token' => 'encrypted',
- ];
-
- protected static function booted(): void
- {
- static::updated(function ($settings) {
- if ($settings->isDirty('helper_version')) {
- Server::chunkById(100, function ($servers) {
- foreach ($servers as $server) {
- PullHelperImageJob::dispatch($server);
- }
- });
- }
- });
- }
-
- public function fqdn(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if ($value) {
- $url = Url::fromString($value);
- $host = $url->getHost();
-
- return $url->getScheme().'://'.$host;
- }
- }
- );
- }
-
- public function updateCheckFrequency(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- return translate_cron_expression($value);
- },
- get: function ($value) {
- return translate_cron_expression($value);
- }
- );
- }
-
- public function autoUpdateFrequency(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- return translate_cron_expression($value);
- },
- get: function ($value) {
- return translate_cron_expression($value);
- }
- );
- }
-
- public static function get()
- {
- return InstanceSettings::findOrFail(0);
- }
-
- public function getRecipients($notification)
- {
- $recipients = data_get($notification, 'emails', null);
- if (is_null($recipients) || $recipients === '') {
- return [];
- }
-
- return explode(',', $recipients);
- }
-
- public function getTitleDisplayName(): string
- {
- $instanceName = $this->instance_name;
- if (! $instanceName) {
- return '';
- }
-
- return "[{$instanceName}]";
- }
-
- // public function helperVersion(): Attribute
- // {
- // return Attribute::make(
- // get: function ($value) {
- // if (isDev()) {
- // return 'latest';
- // }
-
- // return $value;
- // }
- // );
- // }
-}
diff --git a/app/Models/Kubernetes.php b/app/Models/Kubernetes.php
deleted file mode 100644
index 174cb5bc86..0000000000
--- a/app/Models/Kubernetes.php
+++ /dev/null
@@ -1,5 +0,0 @@
-load(['service']);
- dispatch(new \App\Jobs\ServerStorageSaveJob($fileVolume));
- });
- }
-
- protected function isBinary(): Attribute
- {
- return Attribute::make(
- get: function () {
- return $this->content === '[binary file]';
- }
- );
- }
-
- public function service()
- {
- return $this->morphTo('resource');
- }
-
- public function loadStorageOnServer()
- {
- $this->load(['service']);
- $isService = data_get($this->resource, 'service');
- if ($isService) {
- $workdir = $this->resource->service->workdir();
- $server = $this->resource->service->server;
- } else {
- $workdir = $this->resource->workdir();
- $server = $this->resource->destination->server;
- }
- $commands = collect([]);
- $path = data_get_str($this, 'fs_path');
- if ($path->startsWith('.')) {
- $path = $path->after('.');
- $path = $workdir.$path;
- }
- $isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
- if ($isFile === 'OK') {
- $content = instant_remote_process(["cat $path"], $server, false);
- // Check if content contains binary data by looking for null bytes or non-printable characters
- if (str_contains($content, "\0") || preg_match('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', $content)) {
- $content = '[binary file]';
- }
- $this->content = $content;
- $this->is_directory = false;
- $this->save();
- }
- }
-
- public function deleteStorageOnServer()
- {
- $this->load(['service']);
- $isService = data_get($this->resource, 'service');
- if ($isService) {
- $workdir = $this->resource->service->workdir();
- $server = $this->resource->service->server;
- } else {
- $workdir = $this->resource->workdir();
- $server = $this->resource->destination->server;
- }
- $commands = collect([]);
- $path = data_get_str($this, 'fs_path');
- if ($path->startsWith('.')) {
- $path = $path->after('.');
- $path = $workdir.$path;
- }
- $isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
- $isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
- if ($path && $path != '/' && $path != '.' && $path != '..') {
- if ($isFile === 'OK') {
- $commands->push("rm -rf $path > /dev/null 2>&1 || true");
- } elseif ($isDir === 'OK') {
- $commands->push("rm -rf $path > /dev/null 2>&1 || true");
- $commands->push("rmdir $path > /dev/null 2>&1 || true");
- }
- }
- if ($commands->count() > 0) {
- return instant_remote_process($commands, $server);
- }
- }
-
- public function saveStorageOnServer()
- {
- $this->load(['service']);
- $isService = data_get($this->resource, 'service');
- if ($isService) {
- $workdir = $this->resource->service->workdir();
- $server = $this->resource->service->server;
- } else {
- $workdir = $this->resource->workdir();
- $server = $this->resource->destination->server;
- }
- $commands = collect([]);
- if ($this->is_directory) {
- $commands->push("mkdir -p $this->fs_path > /dev/null 2>&1 || true");
- $commands->push("cd $workdir");
- }
- if (str($this->fs_path)->startsWith('.') || str($this->fs_path)->startsWith('/') || str($this->fs_path)->startsWith('~')) {
- $parent_dir = str($this->fs_path)->beforeLast('/');
- if ($parent_dir != '') {
- $commands->push("mkdir -p $parent_dir > /dev/null 2>&1 || true");
- }
- }
- $path = data_get_str($this, 'fs_path');
- $content = data_get($this, 'content');
- if ($path->startsWith('.')) {
- $path = $path->after('.');
- $path = $workdir.$path;
- }
- $isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
- $isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
- if ($isFile === 'OK' && $this->is_directory) {
- $content = instant_remote_process(["cat $path"], $server, false);
- $this->is_directory = false;
- $this->content = $content;
- $this->save();
- FileStorageChanged::dispatch(data_get($server, 'team_id'));
- throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
- } elseif ($isDir === 'OK' && ! $this->is_directory) {
- if ($path === '/' || $path === '.' || $path === '..' || $path === '' || str($path)->isEmpty() || is_null($path)) {
- $this->is_directory = true;
- $this->save();
- throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file. Please delete the directory on the server or mark it as directory.');
- }
- instant_remote_process([
- "rm -fr $path",
- "touch $path",
- ], $server, false);
- FileStorageChanged::dispatch(data_get($server, 'team_id'));
- }
- if ($isDir === 'NOK' && ! $this->is_directory) {
- $chmod = data_get($this, 'chmod');
- $chown = data_get($this, 'chown');
- if ($content) {
- $content = base64_encode($content);
- $commands->push("echo '$content' | base64 -d | tee $path > /dev/null");
- } else {
- $commands->push("touch $path");
- }
- $commands->push("chmod +x $path");
- if ($chown) {
- $commands->push("chown $chown $path");
- }
- if ($chmod) {
- $commands->push("chmod $chmod $path");
- }
- } elseif ($isDir === 'NOK' && $this->is_directory) {
- $commands->push("mkdir -p $path > /dev/null 2>&1 || true");
- }
-
- return instant_remote_process($commands, $server);
- }
-}
diff --git a/app/Models/LocalPersistentVolume.php b/app/Models/LocalPersistentVolume.php
deleted file mode 100644
index 68e476365a..0000000000
--- a/app/Models/LocalPersistentVolume.php
+++ /dev/null
@@ -1,58 +0,0 @@
-morphTo('resource');
- }
-
- public function service()
- {
- return $this->morphTo('resource');
- }
-
- public function database()
- {
- return $this->morphTo('resource');
- }
-
- public function standalone_postgresql()
- {
- return $this->morphTo('resource');
- }
-
- protected function name(): Attribute
- {
- return Attribute::make(
- set: fn (string $value) => str($value)->trim()->value,
- );
- }
-
- protected function mountPath(): Attribute
- {
- return Attribute::make(
- set: fn (string $value) => str($value)->trim()->start('/')->value
- );
- }
-
- protected function hostPath(): Attribute
- {
- return Attribute::make(
- set: function (?string $value) {
- if ($value) {
- return str($value)->trim()->start('/')->value;
- } else {
- return $value;
- }
- }
- );
- }
-}
diff --git a/app/Models/OauthSetting.php b/app/Models/OauthSetting.php
deleted file mode 100644
index 3d82e89f29..0000000000
--- a/app/Models/OauthSetting.php
+++ /dev/null
@@ -1,35 +0,0 @@
- empty($value) ? null : Crypt::decryptString($value),
- set: fn (?string $value) => empty($value) ? null : Crypt::encryptString($value),
- );
- }
-
- public function couldBeEnabled(): bool
- {
- switch ($this->provider) {
- case 'azure':
- return filled($this->client_id) && filled($this->client_secret) && filled($this->redirect_uri) && filled($this->tenant);
- case 'authentik':
- return filled($this->client_id) && filled($this->client_secret) && filled($this->redirect_uri) && filled($this->base_url);
- default:
- return filled($this->client_id) && filled($this->client_secret) && filled($this->redirect_uri);
- }
- }
-}
diff --git a/app/Models/PersonalAccessToken.php b/app/Models/PersonalAccessToken.php
deleted file mode 100644
index 398046a7cd..0000000000
--- a/app/Models/PersonalAccessToken.php
+++ /dev/null
@@ -1,16 +0,0 @@
- ['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
-{
- use WithRateLimiting;
-
- protected $fillable = [
- 'name',
- 'description',
- 'private_key',
- 'is_git_related',
- 'team_id',
- 'fingerprint',
- ];
-
- protected $casts = [
- 'private_key' => 'encrypted',
- ];
-
- protected $appends = ['public_key'];
-
- protected static function booted()
- {
- static::saving(function ($key) {
- $key->private_key = formatPrivateKey($key->private_key);
-
- if (! self::validatePrivateKey($key->private_key)) {
- throw ValidationException::withMessages([
- 'private_key' => ['The private key is invalid.'],
- ]);
- }
-
- $key->fingerprint = self::generateFingerprint($key->private_key);
- if (self::fingerprintExists($key->fingerprint, $key->id)) {
- throw ValidationException::withMessages([
- 'private_key' => ['This private key already exists.'],
- ]);
- }
- });
-
- static::deleted(function ($key) {
- self::deleteFromStorage($key);
- });
- }
-
- public function getPublicKeyAttribute()
- {
- return self::extractPublicKeyFromPrivate($this->private_key) ?? 'Error loading private key';
- }
-
- public function getPublicKey()
- {
- return self::extractPublicKeyFromPrivate($this->private_key) ?? 'Error loading private key';
- }
-
- public static function ownedByCurrentTeam(array $select = ['*'])
- {
- $selectArray = collect($select)->concat(['id']);
-
- return self::whereTeamId(currentTeam()->id)->select($selectArray->all());
- }
-
- public static function validatePrivateKey($privateKey)
- {
- try {
- PublicKeyLoader::load($privateKey);
-
- return true;
- } catch (\Throwable $e) {
- return false;
- }
- }
-
- public static function createAndStore(array $data)
- {
- $privateKey = new self($data);
- $privateKey->save();
- $privateKey->storeInFileSystem();
-
- return $privateKey;
- }
-
- public static function generateNewKeyPair($type = 'rsa')
- {
- try {
- $instance = new self;
- $instance->rateLimit(10);
- $name = generate_random_name();
- $description = 'Created by Coolify';
- $keyPair = generateSSHKey($type === 'ed25519' ? 'ed25519' : 'rsa');
-
- return [
- 'name' => $name,
- 'description' => $description,
- 'private_key' => $keyPair['private'],
- 'public_key' => $keyPair['public'],
- ];
- } catch (\Throwable $e) {
- throw new \Exception("Failed to generate new {$type} key: ".$e->getMessage());
- }
- }
-
- public static function extractPublicKeyFromPrivate($privateKey)
- {
- try {
- $key = PublicKeyLoader::load($privateKey);
-
- return $key->getPublicKey()->toString('OpenSSH', ['comment' => '']);
- } catch (\Throwable $e) {
- return null;
- }
- }
-
- public static function validateAndExtractPublicKey($privateKey)
- {
- $isValid = self::validatePrivateKey($privateKey);
- $publicKey = $isValid ? self::extractPublicKeyFromPrivate($privateKey) : '';
-
- return [
- 'isValid' => $isValid,
- 'publicKey' => $publicKey,
- ];
- }
-
- public function storeInFileSystem()
- {
- $filename = "ssh_key@{$this->uuid}";
- Storage::disk('ssh-keys')->put($filename, $this->private_key);
-
- return "/var/www/html/storage/app/ssh/keys/{$filename}";
- }
-
- public static function deleteFromStorage(self $privateKey)
- {
- $filename = "ssh_key@{$privateKey->uuid}";
- Storage::disk('ssh-keys')->delete($filename);
- }
-
- public function getKeyLocation()
- {
- return "/var/www/html/storage/app/ssh/keys/ssh_key@{$this->uuid}";
- }
-
- public function updatePrivateKey(array $data)
- {
- $this->update($data);
- $this->storeInFileSystem();
-
- return $this;
- }
-
- public function servers()
- {
- return $this->hasMany(Server::class);
- }
-
- public function applications()
- {
- return $this->hasMany(Application::class);
- }
-
- public function githubApps()
- {
- return $this->hasMany(GithubApp::class);
- }
-
- public function gitlabApps()
- {
- return $this->hasMany(GitlabApp::class);
- }
-
- public function isInUse()
- {
- return $this->servers()->exists()
- || $this->applications()->exists()
- || $this->githubApps()->exists()
- || $this->gitlabApps()->exists();
- }
-
- public function safeDelete()
- {
- if (! $this->isInUse()) {
- $this->delete();
-
- return true;
- }
-
- return false;
- }
-
- public static function generateFingerprint($privateKey)
- {
- try {
- $key = PublicKeyLoader::load($privateKey);
-
- return $key->getPublicKey()->getFingerprint('sha256');
- } catch (\Throwable $e) {
- return null;
- }
- }
-
- public static function fingerprintExists($fingerprint, $excludeId = null)
- {
- $query = self::query()
- ->where('fingerprint', $fingerprint)
- ->where('id', '!=', $excludeId);
-
- if (currentTeam()) {
- $query->where('team_id', currentTeam()->id);
- }
-
- return $query->exists();
- }
-
- public static function cleanupUnusedKeys()
- {
- self::ownedByCurrentTeam()->each(function ($privateKey) {
- $privateKey->safeDelete();
- });
- }
-}
diff --git a/app/Models/Project.php b/app/Models/Project.php
deleted file mode 100644
index 2e4d458593..0000000000
--- a/app/Models/Project.php
+++ /dev/null
@@ -1,155 +0,0 @@
- ['type' => 'integer'],
- 'uuid' => ['type' => 'string'],
- 'name' => ['type' => 'string'],
- 'description' => ['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 = [];
-
- public static function ownedByCurrentTeam()
- {
- return Project::whereTeamId(currentTeam()->id)->orderByRaw('LOWER(name)');
- }
-
- protected static function booted()
- {
- static::created(function ($project) {
- ProjectSetting::create([
- 'project_id' => $project->id,
- ]);
- Environment::create([
- 'name' => 'production',
- 'project_id' => $project->id,
- 'uuid' => (string) new Cuid2,
- ]);
- });
- static::deleting(function ($project) {
- $project->environments()->delete();
- $project->settings()->delete();
- $shared_variables = $project->environment_variables();
- foreach ($shared_variables as $shared_variable) {
- $shared_variable->delete();
- }
- });
- }
-
- public function environment_variables()
- {
- return $this->hasMany(SharedEnvironmentVariable::class);
- }
-
- public function environments()
- {
- return $this->hasMany(Environment::class);
- }
-
- public function settings()
- {
- return $this->hasOne(ProjectSetting::class);
- }
-
- public function team()
- {
- return $this->belongsTo(Team::class);
- }
-
- public function services()
- {
- return $this->hasManyThrough(Service::class, Environment::class);
- }
-
- public function applications()
- {
- return $this->hasManyThrough(Application::class, Environment::class);
- }
-
- public function postgresqls()
- {
- return $this->hasManyThrough(StandalonePostgresql::class, Environment::class);
- }
-
- public function redis()
- {
- return $this->hasManyThrough(StandaloneRedis::class, Environment::class);
- }
-
- public function keydbs()
- {
- return $this->hasManyThrough(StandaloneKeydb::class, Environment::class);
- }
-
- public function dragonflies()
- {
- return $this->hasManyThrough(StandaloneDragonfly::class, Environment::class);
- }
-
- public function clickhouses()
- {
- return $this->hasManyThrough(StandaloneClickhouse::class, Environment::class);
- }
-
- public function mongodbs()
- {
- return $this->hasManyThrough(StandaloneMongodb::class, Environment::class);
- }
-
- public function mysqls()
- {
- return $this->hasManyThrough(StandaloneMysql::class, Environment::class);
- }
-
- public function mariadbs()
- {
- return $this->hasManyThrough(StandaloneMariadb::class, Environment::class);
- }
-
- public function isEmpty()
- {
- return $this->applications()->count() == 0 &&
- $this->redis()->count() == 0 &&
- $this->postgresqls()->count() == 0 &&
- $this->mysqls()->count() == 0 &&
- $this->keydbs()->count() == 0 &&
- $this->dragonflies()->count() == 0 &&
- $this->clickhouses()->count() == 0 &&
- $this->mariadbs()->count() == 0 &&
- $this->mongodbs()->count() == 0 &&
- $this->services()->count() == 0;
- }
-
- public function databases()
- {
- return $this->postgresqls()->get()->merge($this->redis()->get())->merge($this->mongodbs()->get())->merge($this->mysqls()->get())->merge($this->mariadbs()->get())->merge($this->keydbs()->get())->merge($this->dragonflies()->get())->merge($this->clickhouses()->get());
- }
-
- public function navigateTo()
- {
- if ($this->environments->count() === 1) {
- return route('project.resource.index', [
- 'project_uuid' => $this->uuid,
- 'environment_uuid' => $this->environments->first()->uuid,
- ]);
- }
-
- return route('project.show', ['project_uuid' => $this->uuid]);
- }
-}
diff --git a/app/Models/ProjectSetting.php b/app/Models/ProjectSetting.php
deleted file mode 100644
index d93bea05b6..0000000000
--- a/app/Models/ProjectSetting.php
+++ /dev/null
@@ -1,15 +0,0 @@
-belongsTo(Project::class);
- }
-}
diff --git a/app/Models/PushoverNotificationSettings.php b/app/Models/PushoverNotificationSettings.php
deleted file mode 100644
index e3191dcc34..0000000000
--- a/app/Models/PushoverNotificationSettings.php
+++ /dev/null
@@ -1,61 +0,0 @@
- 'boolean',
- 'pushover_user_key' => 'encrypted',
- 'pushover_api_token' => 'encrypted',
-
- 'deployment_success_pushover_notifications' => 'boolean',
- 'deployment_failure_pushover_notifications' => 'boolean',
- 'status_change_pushover_notifications' => 'boolean',
- 'backup_success_pushover_notifications' => 'boolean',
- 'backup_failure_pushover_notifications' => 'boolean',
- 'scheduled_task_success_pushover_notifications' => 'boolean',
- 'scheduled_task_failure_pushover_notifications' => 'boolean',
- 'docker_cleanup_pushover_notifications' => 'boolean',
- 'server_disk_usage_pushover_notifications' => 'boolean',
- 'server_reachable_pushover_notifications' => 'boolean',
- 'server_unreachable_pushover_notifications' => 'boolean',
- ];
-
- public function team()
- {
- return $this->belongsTo(Team::class);
- }
-
- public function isEnabled()
- {
- return $this->pushover_enabled;
- }
-}
diff --git a/app/Models/S3Storage.php b/app/Models/S3Storage.php
deleted file mode 100644
index e9d6746502..0000000000
--- a/app/Models/S3Storage.php
+++ /dev/null
@@ -1,87 +0,0 @@
- 'boolean',
- 'key' => 'encrypted',
- 'secret' => 'encrypted',
- ];
-
- public static function ownedByCurrentTeam(array $select = ['*'])
- {
- $selectArray = collect($select)->concat(['id']);
-
- return S3Storage::whereTeamId(currentTeam()->id)->select($selectArray->all())->orderBy('name');
- }
-
- public function isUsable()
- {
- return $this->is_usable;
- }
-
- public function team()
- {
- return $this->belongsTo(Team::class);
- }
-
- public function awsUrl()
- {
- return "{$this->endpoint}/{$this->bucket}";
- }
-
- public function testConnection(bool $shouldSave = false)
- {
- try {
- $disk = Storage::build([
- 'driver' => 's3',
- 'region' => $this['region'],
- 'key' => $this['key'],
- 'secret' => $this['secret'],
- 'bucket' => $this['bucket'],
- 'endpoint' => $this['endpoint'],
- 'use_path_style_endpoint' => true,
- ]);
- // Test the connection by listing files with ListObjectsV2 (S3)
- $disk->files();
-
- $this->unusable_email_sent = false;
- $this->is_usable = true;
- } catch (\Throwable $e) {
- $this->is_usable = false;
- if ($this->unusable_email_sent === false && is_transactional_emails_enabled()) {
- $mail = new MailMessage;
- $mail->subject('Coolify: S3 Storage Connection Error');
- $mail->view('emails.s3-connection-error', ['name' => $this->name, 'reason' => $e->getMessage(), 'url' => route('storage.show', ['storage_uuid' => $this->uuid])]);
-
- // Load the team with its members and their roles explicitly
- $team = $this->team()->with(['members' => function ($query) {
- $query->withPivot('role');
- }])->first();
-
- // Get admins directly from the pivot relationship for this specific team
- $users = $team->members()->wherePivotIn('role', ['admin', 'owner'])->get(['users.id', 'users.email']);
- foreach ($users as $user) {
- send_user_an_email($mail, $user->email);
- }
- $this->unusable_email_sent = true;
- }
-
- throw $e;
- } finally {
- if ($shouldSave) {
- $this->save();
- }
- }
- }
-}
diff --git a/app/Models/ScheduledDatabaseBackup.php b/app/Models/ScheduledDatabaseBackup.php
deleted file mode 100644
index 473fc7b4bb..0000000000
--- a/app/Models/ScheduledDatabaseBackup.php
+++ /dev/null
@@ -1,56 +0,0 @@
-morphTo();
- }
-
- public function latest_log(): HasOne
- {
- return $this->hasOne(ScheduledDatabaseBackupExecution::class)->latest();
- }
-
- public function executions(): HasMany
- {
- // Last execution first
- return $this->hasMany(ScheduledDatabaseBackupExecution::class)->orderBy('created_at', 'desc');
- }
-
- public function s3()
- {
- return $this->belongsTo(S3Storage::class, 's3_storage_id');
- }
-
- public function get_last_days_backup_status($days = 7)
- {
- return $this->hasMany(ScheduledDatabaseBackupExecution::class)->where('created_at', '>=', now()->subDays($days))->get();
- }
-
- public function server()
- {
- if ($this->database) {
- if ($this->database instanceof ServiceDatabase) {
- $destination = data_get($this->database->service, 'destination');
- $server = data_get($destination, 'server');
- } else {
- $destination = data_get($this->database, 'destination');
- $server = data_get($destination, 'server');
- }
- if ($server) {
- return $server;
- }
- }
-
- return null;
- }
-}
diff --git a/app/Models/ScheduledDatabaseBackupExecution.php b/app/Models/ScheduledDatabaseBackupExecution.php
deleted file mode 100644
index b06dd5b45d..0000000000
--- a/app/Models/ScheduledDatabaseBackupExecution.php
+++ /dev/null
@@ -1,15 +0,0 @@
-belongsTo(ScheduledDatabaseBackup::class);
- }
-}
diff --git a/app/Models/ScheduledTask.php b/app/Models/ScheduledTask.php
deleted file mode 100644
index 264a04d1f7..0000000000
--- a/app/Models/ScheduledTask.php
+++ /dev/null
@@ -1,51 +0,0 @@
-belongsTo(Service::class);
- }
-
- public function application()
- {
- return $this->belongsTo(Application::class);
- }
-
- public function latest_log(): HasOne
- {
- return $this->hasOne(ScheduledTaskExecution::class)->latest();
- }
-
- public function executions(): HasMany
- {
- // Last execution first
- return $this->hasMany(ScheduledTaskExecution::class)->orderBy('created_at', 'desc');
- }
-
- public function server()
- {
- if ($this->application) {
- if ($this->application->destination && $this->application->destination->server) {
- return $this->application->destination->server;
- }
- } elseif ($this->service) {
- if ($this->service->destination && $this->service->destination->server) {
- return $this->service->destination->server;
- }
- } elseif ($this->database) {
- if ($this->database->destination && $this->database->destination->server) {
- return $this->database->destination->server;
- }
- }
-
- return null;
- }
-}
diff --git a/app/Models/ScheduledTaskExecution.php b/app/Models/ScheduledTaskExecution.php
deleted file mode 100644
index de13fefb05..0000000000
--- a/app/Models/ScheduledTaskExecution.php
+++ /dev/null
@@ -1,15 +0,0 @@
-belongsTo(ScheduledTask::class);
- }
-}
diff --git a/app/Models/Server.php b/app/Models/Server.php
deleted file mode 100644
index 828500c40b..0000000000
--- a/app/Models/Server.php
+++ /dev/null
@@ -1,1333 +0,0 @@
- ['type' => 'integer', 'description' => 'The server ID.'],
- 'uuid' => ['type' => 'string', 'description' => 'The server UUID.'],
- 'name' => ['type' => 'string', 'description' => 'The server name.'],
- 'description' => ['type' => 'string', 'description' => 'The server description.'],
- 'ip' => ['type' => 'string', 'description' => 'The IP address.'],
- 'user' => ['type' => 'string', 'description' => 'The user.'],
- 'port' => ['type' => 'integer', 'description' => 'The port number.'],
- 'proxy' => ['type' => 'object', 'description' => 'The proxy configuration.'],
- 'proxy_type' => ['type' => 'string', 'enum' => ['traefik', 'caddy', 'none'], 'description' => 'The proxy type.'],
- 'high_disk_usage_notification_sent' => ['type' => 'boolean', 'description' => 'The flag to indicate if the high disk usage notification has been sent.'],
- 'unreachable_notification_sent' => ['type' => 'boolean', 'description' => 'The flag to indicate if the unreachable notification has been sent.'],
- 'unreachable_count' => ['type' => 'integer', 'description' => 'The unreachable count for your server.'],
- 'validation_logs' => ['type' => 'string', 'description' => 'The validation logs.'],
- 'log_drain_notification_sent' => ['type' => 'boolean', 'description' => 'The flag to indicate if the log drain notification has been sent.'],
- 'swarm_cluster' => ['type' => 'string', 'description' => 'The swarm cluster configuration.'],
- 'settings' => ['$ref' => '#/components/schemas/ServerSetting'],
- ]
-)]
-
-class Server extends BaseModel
-{
- use HasFactory, SchemalessAttributesTrait, SoftDeletes;
-
- public static $batch_counter = 0;
-
- protected $appends = ['is_coolify_host'];
-
- protected static function booted()
- {
- static::saving(function ($server) {
- $payload = [];
- if ($server->user) {
- $payload['user'] = str($server->user)->trim();
- }
- if ($server->ip) {
- $payload['ip'] = str($server->ip)->trim();
- }
- $server->forceFill($payload);
- });
- static::saved(function ($server) {
- if ($server->privateKey?->isDirty()) {
- refresh_server_connection($server->privateKey);
- }
- });
- static::created(function ($server) {
- ServerSetting::create([
- 'server_id' => $server->id,
- ]);
- if ($server->id === 0) {
- if ($server->isSwarm()) {
- SwarmDocker::create([
- 'id' => 0,
- 'name' => 'coolify',
- 'network' => 'coolify-overlay',
- 'server_id' => $server->id,
- ]);
- } else {
- StandaloneDocker::create([
- 'id' => 0,
- 'name' => 'coolify',
- 'network' => 'coolify',
- 'server_id' => $server->id,
- ]);
- }
- } else {
- if ($server->isSwarm()) {
- SwarmDocker::create([
- 'name' => 'coolify-overlay',
- 'network' => 'coolify-overlay',
- 'server_id' => $server->id,
- ]);
- } else {
- $standaloneDocker = new StandaloneDocker([
- 'name' => 'coolify',
- 'uuid' => (string) new Cuid2,
- 'network' => 'coolify',
- 'server_id' => $server->id,
- ]);
- $standaloneDocker->saveQuietly();
- }
- }
- if (! isset($server->proxy->redirect_enabled)) {
- $server->proxy->redirect_enabled = true;
- }
- });
- static::retrieved(function ($server) {
- if (! isset($server->proxy->redirect_enabled)) {
- $server->proxy->redirect_enabled = true;
- }
- });
-
- static::forceDeleting(function ($server) {
- $server->destinations()->each(function ($destination) {
- $destination->delete();
- });
- $server->settings()->delete();
- });
- }
-
- protected $casts = [
- 'proxy' => SchemalessAttributes::class,
- 'logdrain_axiom_api_key' => 'encrypted',
- 'logdrain_newrelic_license_key' => 'encrypted',
- 'delete_unused_volumes' => 'boolean',
- 'delete_unused_networks' => 'boolean',
- 'unreachable_notification_sent' => 'boolean',
- 'is_build_server' => 'boolean',
- 'force_disabled' => 'boolean',
- ];
-
- protected $schemalessAttributes = [
- 'proxy',
- ];
-
- protected $fillable = [
- 'name',
- 'ip',
- 'port',
- 'user',
- 'description',
- 'private_key_id',
- 'team_id',
- ];
-
- protected $guarded = [];
-
- public function type()
- {
- return 'server';
- }
-
- protected function isCoolifyHost(): Attribute
- {
- return Attribute::make(
- get: function () {
- return $this->id === 0;
- }
- );
- }
-
- public static function isReachable()
- {
- return Server::ownedByCurrentTeam()->whereRelation('settings', 'is_reachable', true);
- }
-
- public static function ownedByCurrentTeam(array $select = ['*'])
- {
- $teamId = currentTeam()->id;
- $selectArray = collect($select)->concat(['id']);
-
- return Server::whereTeamId($teamId)->with('settings', 'swarmDockers', 'standaloneDockers')->select($selectArray->all())->orderBy('name');
- }
-
- public static function isUsable()
- {
- return Server::ownedByCurrentTeam()->whereRelation('settings', 'is_reachable', true)->whereRelation('settings', 'is_usable', true)->whereRelation('settings', 'is_swarm_worker', false)->whereRelation('settings', 'is_build_server', false)->whereRelation('settings', 'force_disabled', false);
- }
-
- public static function destinationsByServer(string $server_id)
- {
- $server = Server::ownedByCurrentTeam()->get()->where('id', $server_id)->firstOrFail();
- $standaloneDocker = collect($server->standaloneDockers->all());
- $swarmDocker = collect($server->swarmDockers->all());
-
- return $standaloneDocker->concat($swarmDocker);
- }
-
- public function settings()
- {
- return $this->hasOne(ServerSetting::class);
- }
-
- public function dockerCleanupExecutions()
- {
- return $this->hasMany(DockerCleanupExecution::class);
- }
-
- public function proxySet()
- {
- return $this->proxyType() && $this->proxyType() !== 'NONE' && $this->isFunctional() && ! $this->isSwarmWorker() && ! $this->settings->is_build_server;
- }
-
- public function setupDefaultRedirect()
- {
- $banner =
- "# This file is generated by Coolify, do not edit it manually.\n".
- "# Disable the default redirect to customize (only if you know what are you doing).\n\n";
- $dynamic_conf_path = $this->proxyPath().'/dynamic';
- $proxy_type = $this->proxyType();
- $redirect_enabled = $this->proxy->redirect_enabled ?? true;
- $redirect_url = $this->proxy->redirect_url;
- if (isDev()) {
- if ($proxy_type === ProxyTypes::CADDY->value) {
- $dynamic_conf_path = '/data/coolify/proxy/caddy/dynamic';
- }
- }
- if ($proxy_type === ProxyTypes::TRAEFIK->value) {
- $default_redirect_file = "$dynamic_conf_path/default_redirect_503.yaml";
- } elseif ($proxy_type === ProxyTypes::CADDY->value) {
- $default_redirect_file = "$dynamic_conf_path/default_redirect_503.caddy";
- }
-
- instant_remote_process([
- "mkdir -p $dynamic_conf_path",
- "rm -f $dynamic_conf_path/default_redirect_404.yaml",
- "rm -f $dynamic_conf_path/default_redirect_404.caddy",
- ], $this);
-
- if ($redirect_enabled === false) {
- instant_remote_process(["rm -f $default_redirect_file"], $this);
- } else {
- if ($proxy_type === ProxyTypes::CADDY->value) {
- if (filled($redirect_url)) {
- $conf = ":80, :443 {
- redir $redirect_url
-}";
- } else {
- $conf = ':80, :443 {
- respond 503
-}';
- }
- } elseif ($proxy_type === ProxyTypes::TRAEFIK->value) {
- $dynamic_conf = [
- 'http' => [
- 'routers' => [
- 'catchall' => [
- 'entryPoints' => [
- 0 => 'http',
- 1 => 'https',
- ],
- 'service' => 'noop',
- 'rule' => 'PathPrefix(`/`)',
- 'tls' => [
- 'certResolver' => 'letsencrypt',
- ],
- 'priority' => -1000,
- ],
- ],
- 'services' => [
- 'noop' => [
- 'loadBalancer' => [
- 'servers' => [],
- ],
- ],
- ],
- ],
- ];
- if (filled($redirect_url)) {
- $dynamic_conf['http']['routers']['catchall']['middlewares'] = [
- 0 => 'redirect-regexp',
- ];
-
- $dynamic_conf['http']['services']['noop']['loadBalancer']['servers'][0] = [
- 'url' => '',
- ];
- $dynamic_conf['http']['middlewares'] = [
- 'redirect-regexp' => [
- 'redirectRegex' => [
- 'regex' => '(.*)',
- 'replacement' => $redirect_url,
- 'permanent' => false,
- ],
- ],
- ];
- }
- $conf = Yaml::dump($dynamic_conf, 12, 2);
- }
- $conf = $banner.$conf;
- $base64 = base64_encode($conf);
- instant_remote_process([
- "echo '$base64' | base64 -d | tee $default_redirect_file > /dev/null",
- ], $this);
- }
-
- if ($proxy_type === 'CADDY') {
- $this->reloadCaddy();
- }
- }
-
- public function setupDynamicProxyConfiguration()
- {
- $settings = instanceSettings();
- $dynamic_config_path = $this->proxyPath().'/dynamic';
- if ($this->proxyType() === ProxyTypes::TRAEFIK->value) {
- $file = "$dynamic_config_path/coolify.yaml";
- if (empty($settings->fqdn) || (isCloud() && $this->id !== 0) || ! $this->isLocalhost()) {
- instant_remote_process([
- "rm -f $file",
- ], $this);
- } else {
- $url = Url::fromString($settings->fqdn);
- $host = $url->getHost();
- $schema = $url->getScheme();
- $traefik_dynamic_conf = [
- 'http' => [
- 'middlewares' => [
- 'redirect-to-https' => [
- 'redirectscheme' => [
- 'scheme' => 'https',
- ],
- ],
- 'gzip' => [
- 'compress' => true,
- ],
- ],
- 'routers' => [
- 'coolify-http' => [
- 'middlewares' => [
- 0 => 'gzip',
- ],
- 'entryPoints' => [
- 0 => 'http',
- ],
- 'service' => 'coolify',
- 'rule' => "Host(`{$host}`)",
- ],
- 'coolify-realtime-ws' => [
- 'entryPoints' => [
- 0 => 'http',
- ],
- 'service' => 'coolify-realtime',
- 'rule' => "Host(`{$host}`) && PathPrefix(`/app`)",
- ],
- 'coolify-terminal-ws' => [
- 'entryPoints' => [
- 0 => 'http',
- ],
- 'service' => 'coolify-terminal',
- 'rule' => "Host(`{$host}`) && PathPrefix(`/terminal/ws`)",
- ],
- ],
- 'services' => [
- 'coolify' => [
- 'loadBalancer' => [
- 'servers' => [
- 0 => [
- 'url' => 'http://coolify:8080',
- ],
- ],
- ],
- ],
- 'coolify-realtime' => [
- 'loadBalancer' => [
- 'servers' => [
- 0 => [
- 'url' => 'http://coolify-realtime:6001',
- ],
- ],
- ],
- ],
- 'coolify-terminal' => [
- 'loadBalancer' => [
- 'servers' => [
- 0 => [
- 'url' => 'http://coolify-realtime:6002',
- ],
- ],
- ],
- ],
- ],
- ],
- ];
-
- if ($schema === 'https') {
- $traefik_dynamic_conf['http']['routers']['coolify-http']['middlewares'] = [
- 0 => 'redirect-to-https',
- ];
-
- $traefik_dynamic_conf['http']['routers']['coolify-https'] = [
- 'entryPoints' => [
- 0 => 'https',
- ],
- 'service' => 'coolify',
- 'rule' => "Host(`{$host}`)",
- 'tls' => [
- 'certresolver' => 'letsencrypt',
- ],
- ];
- $traefik_dynamic_conf['http']['routers']['coolify-realtime-wss'] = [
- 'entryPoints' => [
- 0 => 'https',
- ],
- 'service' => 'coolify-realtime',
- 'rule' => "Host(`{$host}`) && PathPrefix(`/app`)",
- 'tls' => [
- 'certresolver' => 'letsencrypt',
- ],
- ];
- $traefik_dynamic_conf['http']['routers']['coolify-terminal-wss'] = [
- 'entryPoints' => [
- 0 => 'https',
- ],
- 'service' => 'coolify-terminal',
- 'rule' => "Host(`{$host}`) && PathPrefix(`/terminal/ws`)",
- 'tls' => [
- 'certresolver' => 'letsencrypt',
- ],
- ];
- }
- $yaml = Yaml::dump($traefik_dynamic_conf, 12, 2);
- $yaml =
- "# This file is automatically generated by Coolify.\n".
- "# Do not edit it manually (only if you know what are you doing).\n\n".
- $yaml;
-
- $base64 = base64_encode($yaml);
- instant_remote_process([
- "mkdir -p $dynamic_config_path",
- "echo '$base64' | base64 -d | tee $file > /dev/null",
- ], $this);
- }
- } elseif ($this->proxyType() === 'CADDY') {
- $file = "$dynamic_config_path/coolify.caddy";
- if (empty($settings->fqdn) || (isCloud() && $this->id !== 0) || ! $this->isLocalhost()) {
- instant_remote_process([
- "rm -f $file",
- ], $this);
- $this->reloadCaddy();
- } else {
- $url = Url::fromString($settings->fqdn);
- $host = $url->getHost();
- $schema = $url->getScheme();
- $caddy_file = "
-$schema://$host {
- handle /app/* {
- reverse_proxy coolify-realtime:6001
- }
- handle /terminal/ws {
- reverse_proxy coolify-realtime:6002
- }
- reverse_proxy coolify:8080
-}";
- $base64 = base64_encode($caddy_file);
- instant_remote_process([
- "echo '$base64' | base64 -d | tee $file > /dev/null",
- ], $this);
- $this->reloadCaddy();
- }
- }
- }
-
- public function reloadCaddy()
- {
- return instant_remote_process([
- 'docker exec coolify-proxy caddy reload --config /config/caddy/Caddyfile.autosave',
- ], $this);
- }
-
- public function proxyPath()
- {
- $base_path = config('constants.coolify.base_config_path');
- $proxyType = $this->proxyType();
- $proxy_path = "$base_path/proxy";
- // TODO: should use /traefik for already exisiting configurations?
- // Should move everything except /caddy and /nginx to /traefik
- // The code needs to be modified as well, so maybe it does not worth it
- if ($proxyType === ProxyTypes::TRAEFIK->value) {
- // Do nothing
- } elseif ($proxyType === ProxyTypes::CADDY->value) {
- if (isDev()) {
- $proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/caddy';
- } else {
- $proxy_path = $proxy_path.'/caddy';
- }
- } elseif ($proxyType === ProxyTypes::NGINX->value) {
- if (isDev()) {
- $proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/nginx';
- } else {
- $proxy_path = $proxy_path.'/nginx';
- }
- }
-
- return $proxy_path;
- }
-
- public function proxyType()
- {
- return data_get($this->proxy, 'type');
- }
-
- public function scopeWithProxy(): Builder
- {
- return $this->proxy->modelScope();
- }
-
- public function isLocalhost()
- {
- return $this->ip === 'host.docker.internal' || $this->id === 0;
- }
-
- public static function buildServers($teamId)
- {
- return Server::whereTeamId($teamId)->whereRelation('settings', 'is_reachable', true)->whereRelation('settings', 'is_build_server', true);
- }
-
- public function isForceDisabled()
- {
- return $this->settings->force_disabled;
- }
-
- public function forceEnableServer()
- {
- $this->settings->force_disabled = false;
- $this->settings->save();
- }
-
- public function forceDisableServer()
- {
- $this->settings->force_disabled = true;
- $this->settings->save();
- $sshKeyFileLocation = "id.root@{$this->uuid}";
- Storage::disk('ssh-keys')->delete($sshKeyFileLocation);
- Storage::disk('ssh-mux')->delete($this->muxFilename());
- }
-
- public function sentinelHeartbeat(bool $isReset = false)
- {
- $this->sentinel_updated_at = $isReset ? now()->subMinutes(6000) : now();
- $this->save();
- }
-
- /**
- * Get the wait time for Sentinel to push before performing an SSH check.
- *
- * @return int The wait time in seconds.
- */
- public function waitBeforeDoingSshCheck(): int
- {
- $wait = $this->settings->sentinel_push_interval_seconds * 3;
- if ($wait < 120) {
- $wait = 120;
- }
-
- return $wait;
- }
-
- public function isSentinelLive()
- {
- return Carbon::parse($this->sentinel_updated_at)->isAfter(now()->subSeconds($this->waitBeforeDoingSshCheck()));
- }
-
- public function isSentinelEnabled()
- {
- return ($this->isMetricsEnabled() || $this->isServerApiEnabled()) && ! $this->isBuildServer();
- }
-
- public function isMetricsEnabled()
- {
- return $this->settings->is_metrics_enabled;
- }
-
- public function isServerApiEnabled()
- {
- return $this->settings->is_sentinel_enabled;
- }
-
- public function checkSentinel()
- {
- CheckAndStartSentinelJob::dispatch($this);
- }
-
- public function getCpuMetrics(int $mins = 5)
- {
- if ($this->isMetricsEnabled()) {
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $cpu = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://localhost:8888/api/cpu/history?from=$from'"], $this, false);
- if (str($cpu)->contains('error')) {
- $error = json_decode($cpu, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $cpu = json_decode($cpu, true);
-
- return collect($cpu)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['percent']];
- });
- }
- }
-
- public function getMemoryMetrics(int $mins = 5)
- {
- if ($this->isMetricsEnabled()) {
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $memory = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://localhost:8888/api/memory/history?from=$from'"], $this, false);
- if (str($memory)->contains('error')) {
- $error = json_decode($memory, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $memory = json_decode($memory, true);
- $parsedCollection = collect($memory)->map(function ($metric) {
- $usedPercent = $metric['usedPercent'] ?? 0.0;
-
- return [(int) $metric['time'], (float) $usedPercent];
- });
-
- return $parsedCollection->toArray();
- }
- }
-
- public function getDiskUsage(): ?string
- {
- return instant_remote_process(['df / --output=pcent | tr -cd 0-9'], $this, false);
- // return instant_remote_process(["df /| tail -1 | awk '{ print $5}' | sed 's/%//g'"], $this, false);
- }
-
- public function definedResources()
- {
- $applications = $this->applications();
- $databases = $this->databases();
- $services = $this->services();
-
- return $applications->concat($databases)->concat($services->get());
- }
-
- public function stopUnmanaged($id)
- {
- return instant_remote_process(["docker stop -t 0 $id"], $this);
- }
-
- public function restartUnmanaged($id)
- {
- return instant_remote_process(["docker restart $id"], $this);
- }
-
- public function startUnmanaged($id)
- {
- return instant_remote_process(["docker start $id"], $this);
- }
-
- public function getContainers()
- {
- $containers = collect([]);
- $containerReplicates = collect([]);
- if ($this->isSwarm()) {
- $containers = instant_remote_process_with_timeout(["docker service inspect $(docker service ls -q) --format '{{json .}}'"], $this, false);
- $containers = format_docker_command_output_to_json($containers);
- $containerReplicates = instant_remote_process_with_timeout(["docker service ls --format '{{json .}}'"], $this, false);
- if ($containerReplicates) {
- $containerReplicates = format_docker_command_output_to_json($containerReplicates);
- foreach ($containerReplicates as $containerReplica) {
- $name = data_get($containerReplica, 'Name');
- $containers = $containers->map(function ($container) use ($name, $containerReplica) {
- if (data_get($container, 'Spec.Name') === $name) {
- $replicas = data_get($containerReplica, 'Replicas');
- $running = str($replicas)->explode('/')[0];
- $total = str($replicas)->explode('/')[1];
- if ($running === $total) {
- data_set($container, 'State.Status', 'running');
- data_set($container, 'State.Health.Status', 'healthy');
- } else {
- data_set($container, 'State.Status', 'starting');
- data_set($container, 'State.Health.Status', 'unhealthy');
- }
- }
-
- return $container;
- });
- }
- }
- } else {
- $containers = instant_remote_process_with_timeout(["docker container inspect $(docker container ls -aq) --format '{{json .}}'"], $this, false);
- $containers = format_docker_command_output_to_json($containers);
- $containerReplicates = collect([]);
- }
-
- return [
- 'containers' => collect($containers) ?? collect([]),
- 'containerReplicates' => collect($containerReplicates) ?? collect([]),
- ];
- }
-
- public function loadAllContainers(): Collection
- {
- if ($this->isFunctional()) {
- $containers = instant_remote_process(["docker ps -a --format '{{json .}}'"], $this);
- $containers = format_docker_command_output_to_json($containers);
-
- return collect($containers);
- }
-
- return collect([]);
- }
-
- public function loadUnmanagedContainers(): Collection
- {
- if ($this->isFunctional()) {
- $containers = instant_remote_process(["docker ps -a --format '{{json .}}'"], $this);
- $containers = format_docker_command_output_to_json($containers);
- $containers = $containers->map(function ($container) {
- $labels = data_get($container, 'Labels');
- if (! str($labels)->contains('coolify.managed')) {
- return $container;
- }
-
- return null;
- });
- $containers = $containers->filter();
-
- return collect($containers);
- } else {
- return collect([]);
- }
- }
-
- public function hasDefinedResources()
- {
- $applications = $this->applications()->count() > 0;
- $databases = $this->databases()->count() > 0;
- $services = $this->services()->count() > 0;
- if ($applications || $databases || $services) {
- return true;
- }
-
- return false;
- }
-
- public function databases()
- {
- return $this->destinations()->map(function ($standaloneDocker) {
- $postgresqls = data_get($standaloneDocker, 'postgresqls', collect([]));
- $redis = data_get($standaloneDocker, 'redis', collect([]));
- $mongodbs = data_get($standaloneDocker, 'mongodbs', collect([]));
- $mysqls = data_get($standaloneDocker, 'mysqls', collect([]));
- $mariadbs = data_get($standaloneDocker, 'mariadbs', collect([]));
- $keydbs = data_get($standaloneDocker, 'keydbs', collect([]));
- $dragonflies = data_get($standaloneDocker, 'dragonflies', collect([]));
- $clickhouses = data_get($standaloneDocker, 'clickhouses', collect([]));
-
- return $postgresqls->concat($redis)->concat($mongodbs)->concat($mysqls)->concat($mariadbs)->concat($keydbs)->concat($dragonflies)->concat($clickhouses);
- })->flatten()->filter(function ($item) {
- return data_get($item, 'name') !== 'coolify-db';
- });
- }
-
- public function applications()
- {
- $applications = $this->destinations()->map(function ($standaloneDocker) {
- return $standaloneDocker->applications;
- })->flatten();
- $additionalApplicationIds = DB::table('additional_destinations')->where('server_id', $this->id)->get('application_id');
- $additionalApplicationIds = collect($additionalApplicationIds)->map(function ($item) {
- return $item->application_id;
- });
- Application::whereIn('id', $additionalApplicationIds)->get()->each(function ($application) use ($applications) {
- $applications->push($application);
- });
-
- return $applications;
- }
-
- public function dockerComposeBasedApplications()
- {
- return $this->applications()->filter(function ($application) {
- return data_get($application, 'build_pack') === 'dockercompose';
- });
- }
-
- public function dockerComposeBasedPreviewDeployments()
- {
- return $this->previews()->filter(function ($preview) {
- $applicationId = data_get($preview, 'application_id');
- $application = Application::find($applicationId);
- if (! $application) {
- return false;
- }
-
- return data_get($application, 'build_pack') === 'dockercompose';
- });
- }
-
- public function services()
- {
- return $this->hasMany(Service::class);
- }
-
- public function port(): Attribute
- {
- return Attribute::make(
- get: function ($value) {
- return (int) preg_replace('/[^0-9]/', '', $value);
- }
- );
- }
-
- public function user(): Attribute
- {
- return Attribute::make(
- get: function ($value) {
- return preg_replace('/[^A-Za-z0-9\-_]/', '', $value);
- }
- );
- }
-
- public function ip(): Attribute
- {
- return Attribute::make(
- get: function ($value) {
- return preg_replace('/[^0-9a-zA-Z.:%-]/', '', $value);
- }
- );
- }
-
- public function getIp(): Attribute
- {
- return Attribute::make(
- get: function () {
- if (isDev()) {
- return '127.0.0.1';
- }
- if ($this->isLocalhost()) {
- return base_ip();
- }
-
- return $this->ip;
- }
- );
- }
-
- public function previews()
- {
- return $this->destinations()->map(function ($standaloneDocker) {
- return $standaloneDocker->applications->map(function ($application) {
- return $application->previews;
- })->flatten();
- })->flatten();
- }
-
- public function destinations()
- {
- $standalone_docker = $this->hasMany(StandaloneDocker::class)->get();
- $swarm_docker = $this->hasMany(SwarmDocker::class)->get();
-
- return $standalone_docker->concat($swarm_docker);
- }
-
- public function standaloneDockers()
- {
- return $this->hasMany(StandaloneDocker::class);
- }
-
- public function swarmDockers()
- {
- return $this->hasMany(SwarmDocker::class);
- }
-
- public function privateKey()
- {
- return $this->belongsTo(PrivateKey::class);
- }
-
- public function muxFilename()
- {
- return $this->uuid;
- }
-
- public function team()
- {
- return $this->belongsTo(Team::class);
- }
-
- public function isProxyShouldRun()
- {
- // TODO: Do we need "|| $this->proxy->force_stop" here?
- if ($this->proxyType() === ProxyTypes::NONE->value || $this->isBuildServer()) {
- return false;
- }
-
- return true;
- }
-
- public function skipServer()
- {
- if ($this->ip === '1.2.3.4') {
- return true;
- }
- if ($this->settings->force_disabled === true) {
- return true;
- }
-
- return false;
- }
-
- public function isFunctional()
- {
- $isFunctional = $this->settings->is_reachable && $this->settings->is_usable && $this->settings->force_disabled === false && $this->ip !== '1.2.3.4';
-
- if ($isFunctional === false) {
- Storage::disk('ssh-mux')->delete($this->muxFilename());
- }
-
- return $isFunctional;
- }
-
- public function isLogDrainEnabled()
- {
- return $this->settings->is_logdrain_newrelic_enabled || $this->settings->is_logdrain_highlight_enabled || $this->settings->is_logdrain_axiom_enabled || $this->settings->is_logdrain_custom_enabled;
- }
-
- public function validateOS(): bool|Stringable
- {
- $os_release = instant_remote_process(['cat /etc/os-release'], $this);
- $releaseLines = collect(explode("\n", $os_release));
- $collectedData = collect([]);
- foreach ($releaseLines as $line) {
- $item = str($line)->trim();
- $collectedData->put($item->before('=')->value(), $item->after('=')->lower()->replace('"', '')->value());
- }
- $ID = data_get($collectedData, 'ID');
- // $ID_LIKE = data_get($collectedData, 'ID_LIKE');
- // $VERSION_ID = data_get($collectedData, 'VERSION_ID');
- $supported = collect(SUPPORTED_OS)->filter(function ($supportedOs) use ($ID) {
- if (str($supportedOs)->contains($ID)) {
- return str($ID);
- }
- });
- if ($supported->count() === 1) {
- return str($supported->first());
- } else {
- return false;
- }
- }
-
- public function isSwarm()
- {
- return data_get($this, 'settings.is_swarm_manager') || data_get($this, 'settings.is_swarm_worker');
- }
-
- public function isSwarmManager()
- {
- return data_get($this, 'settings.is_swarm_manager');
- }
-
- public function isSwarmWorker()
- {
- return data_get($this, 'settings.is_swarm_worker');
- }
-
- public function serverStatus(): bool
- {
- if ($this->status() === false) {
- return false;
- }
- if ($this->isFunctional() === false) {
- return false;
- }
-
- return true;
- }
-
- public function status(): bool
- {
- ['uptime' => $uptime] = $this->validateConnection();
- if ($uptime === false) {
- foreach ($this->applications() as $application) {
- $application->status = 'exited';
- $application->save();
- }
- foreach ($this->databases() as $database) {
- $database->status = 'exited';
- $database->save();
- }
- foreach ($this->services() as $service) {
- $apps = $service->applications()->get();
- $dbs = $service->databases()->get();
- foreach ($apps as $app) {
- $app->status = 'exited';
- $app->save();
- }
- foreach ($dbs as $db) {
- $db->status = 'exited';
- $db->save();
- }
- }
-
- return false;
- }
-
- return true;
- }
-
- public function isReachableChanged()
- {
- $this->refresh();
- $unreachableNotificationSent = (bool) $this->unreachable_notification_sent;
- $isReachable = (bool) $this->settings->is_reachable;
-
- Log::debug('Server reachability check', [
- 'server_id' => $this->id,
- 'is_reachable' => $isReachable,
- 'notification_sent' => $unreachableNotificationSent,
- 'unreachable_count' => $this->unreachable_count,
- ]);
-
- if ($isReachable === true) {
- $this->unreachable_count = 0;
- $this->save();
-
- if ($unreachableNotificationSent === true) {
- Log::debug('Server is now reachable, sending notification', [
- 'server_id' => $this->id,
- ]);
- $this->sendReachableNotification();
- }
-
- return;
- }
-
- $this->increment('unreachable_count');
- Log::debug('Incremented unreachable count', [
- 'server_id' => $this->id,
- 'new_count' => $this->unreachable_count,
- ]);
-
- if ($this->unreachable_count === 1) {
- $this->settings->is_reachable = true;
- $this->settings->save();
- Log::debug('First unreachable attempt, marking as reachable', [
- 'server_id' => $this->id,
- ]);
-
- return;
- }
-
- if ($this->unreachable_count >= 2 && ! $unreachableNotificationSent) {
- $failedChecks = 0;
- for ($i = 0; $i < 3; $i++) {
- $status = $this->serverStatus();
- Log::debug('Additional reachability check', [
- 'server_id' => $this->id,
- 'attempt' => $i + 1,
- 'status' => $status,
- ]);
- sleep(5);
- if (! $status) {
- $failedChecks++;
- }
- }
-
- if ($failedChecks === 3 && ! $unreachableNotificationSent) {
- Log::debug('Server confirmed unreachable after 3 attempts, sending notification', [
- 'server_id' => $this->id,
- ]);
- $this->sendUnreachableNotification();
- }
- }
- }
-
- public function sendReachableNotification()
- {
- $this->unreachable_notification_sent = false;
- $this->save();
- $this->refresh();
- $this->team->notify(new Reachable($this));
- }
-
- public function sendUnreachableNotification()
- {
- $this->unreachable_notification_sent = true;
- $this->save();
- $this->refresh();
- $this->team->notify(new Unreachable($this));
- }
-
- public function validateConnection(bool $justCheckingNewKey = false)
- {
- config()->set('constants.ssh.mux_enabled', false);
-
- if ($this->skipServer()) {
- return ['uptime' => false, 'error' => 'Server skipped.'];
- }
- try {
- instant_remote_process(['ls /'], $this);
- if ($this->settings->is_reachable === false) {
- $this->settings->is_reachable = true;
- $this->settings->save();
- ServerReachabilityChanged::dispatch($this);
- }
-
- return ['uptime' => true, 'error' => null];
- } catch (\Throwable $e) {
- if ($justCheckingNewKey) {
- return ['uptime' => false, 'error' => 'This key is not valid for this server.'];
- }
- if ($this->settings->is_reachable === true) {
- $this->settings->is_reachable = false;
- $this->settings->save();
- ServerReachabilityChanged::dispatch($this);
- }
-
- return ['uptime' => false, 'error' => $e->getMessage()];
- }
- }
-
- public function installDocker()
- {
- return InstallDocker::run($this);
- }
-
- public function validateDockerEngine($throwError = false)
- {
- $dockerBinary = instant_remote_process(['command -v docker'], $this, false, no_sudo: true);
- if (is_null($dockerBinary)) {
- $this->settings->is_usable = false;
- $this->settings->save();
- if ($throwError) {
- throw new \Exception('Server is not usable. Docker Engine is not installed.');
- }
-
- return false;
- }
- try {
- instant_remote_process(['docker version'], $this);
- } catch (\Throwable $e) {
- $this->settings->is_usable = false;
- $this->settings->save();
- if ($throwError) {
- throw new \Exception('Server is not usable. Docker Engine is not running.');
- }
-
- return false;
- }
- $this->settings->is_usable = true;
- $this->settings->save();
- $this->validateCoolifyNetwork(isSwarm: false, isBuildServer: $this->settings->is_build_server);
-
- return true;
- }
-
- public function validateDockerCompose($throwError = false)
- {
- $dockerCompose = instant_remote_process(['docker compose version'], $this, false);
- if (is_null($dockerCompose)) {
- $this->settings->is_usable = false;
- $this->settings->save();
- if ($throwError) {
- throw new \Exception('Server is not usable. Docker Compose is not installed.');
- }
-
- return false;
- }
- $this->settings->is_usable = true;
- $this->settings->save();
-
- return true;
- }
-
- public function validateDockerSwarm()
- {
- $swarmStatus = instant_remote_process(['docker info|grep -i swarm'], $this, false);
- $swarmStatus = str($swarmStatus)->trim()->after(':')->trim();
- if ($swarmStatus === 'inactive') {
- throw new \Exception('Docker Swarm is not initiated. Please join the server to a swarm before continuing.');
-
- return false;
- }
- $this->settings->is_usable = true;
- $this->settings->save();
- $this->validateCoolifyNetwork(isSwarm: true);
-
- return true;
- }
-
- public function validateDockerEngineVersion()
- {
- $dockerVersionRaw = instant_remote_process(['docker version --format json'], $this, false);
- $dockerVersionJson = json_decode($dockerVersionRaw, true);
- $dockerVersion = data_get($dockerVersionJson, 'Server.Version', '0.0.0');
- $dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
- if (is_null($dockerVersion)) {
- $this->settings->is_usable = false;
- $this->settings->save();
-
- return false;
- }
- $this->settings->is_reachable = true;
- $this->settings->is_usable = true;
- $this->settings->save();
- ServerReachabilityChanged::dispatch($this);
-
- return true;
- }
-
- public function validateCoolifyNetwork($isSwarm = false, $isBuildServer = false)
- {
- if ($isBuildServer) {
- return;
- }
- if ($isSwarm) {
- return instant_remote_process(['docker network create --attachable --driver overlay coolify-overlay >/dev/null 2>&1 || true'], $this, false);
- } else {
- return instant_remote_process(['docker network create coolify --attachable >/dev/null 2>&1 || true'], $this, false);
- }
- }
-
- public function isNonRoot()
- {
- if ($this->user instanceof Stringable) {
- return $this->user->value() !== 'root';
- }
-
- return $this->user !== 'root';
- }
-
- public function isBuildServer()
- {
- return $this->settings->is_build_server;
- }
-
- public static function createWithPrivateKey(array $data, PrivateKey $privateKey)
- {
- $server = new self($data);
- $server->privateKey()->associate($privateKey);
- $server->save();
-
- return $server;
- }
-
- public function updateWithPrivateKey(array $data, ?PrivateKey $privateKey = null)
- {
- $this->update($data);
- if ($privateKey) {
- $this->privateKey()->associate($privateKey);
- $this->save();
- }
-
- return $this;
- }
-
- public function storageCheck(): ?string
- {
- $commands = [
- 'df / --output=pcent | tr -cd 0-9',
- ];
-
- return instant_remote_process($commands, $this, false);
- }
-
- public function isIpv6(): bool
- {
- return str($this->ip)->contains(':');
- }
-
- public function restartSentinel(bool $async = true)
- {
- try {
- if ($async) {
- StartSentinel::dispatch($this, true);
- } else {
- StartSentinel::run($this, true);
- }
- } catch (\Throwable $e) {
- return handleError($e);
- }
- }
-
- public function url()
- {
- return base_url().'/server/'.$this->uuid;
- }
-
- public function restartContainer(string $containerName)
- {
- return instant_remote_process(['docker restart '.$containerName], $this, false);
- }
-
- public function changeProxy(string $proxyType, bool $async = true)
- {
- $validProxyTypes = collect(ProxyTypes::cases())->map(function ($proxyType) {
- return str($proxyType->value)->lower();
- });
- if ($validProxyTypes->contains(str($proxyType)->lower())) {
- $this->proxy->set('type', str($proxyType)->upper());
- $this->proxy->set('status', 'exited');
- $this->save();
- if ($this->proxySet()) {
- if ($async) {
- StartProxy::dispatch($this);
- } else {
- StartProxy::run($this);
- }
- }
- } else {
- throw new \Exception('Invalid proxy type.');
- }
- }
-
- public function isEmpty()
- {
- return $this->applications()->count() == 0 &&
- $this->databases()->count() == 0 &&
- $this->services()->count() == 0;
- }
-}
diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php
deleted file mode 100644
index f4b776cca0..0000000000
--- a/app/Models/ServerSetting.php
+++ /dev/null
@@ -1,151 +0,0 @@
- ['type' => 'integer'],
- 'concurrent_builds' => ['type' => 'integer'],
- 'dynamic_timeout' => ['type' => 'integer'],
- 'force_disabled' => ['type' => 'boolean'],
- 'force_server_cleanup' => ['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_sentinel_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'],
- 'sentinel_metrics_history_days' => ['type' => 'integer'],
- 'sentinel_metrics_refresh_rate_seconds' => ['type' => 'integer'],
- 'sentinel_token' => ['type' => 'string'],
- 'docker_cleanup_frequency' => ['type' => 'string'],
- 'docker_cleanup_threshold' => ['type' => 'integer'],
- 'server_id' => ['type' => 'integer'],
- 'wildcard_domain' => ['type' => 'string'],
- 'created_at' => ['type' => 'string'],
- 'updated_at' => ['type' => 'string'],
- 'delete_unused_volumes' => ['type' => 'boolean', 'description' => 'The flag to indicate if the unused volumes should be deleted.'],
- 'delete_unused_networks' => ['type' => 'boolean', 'description' => 'The flag to indicate if the unused networks should be deleted.'],
- ]
-)]
-class ServerSetting extends Model
-{
- protected $guarded = [];
-
- protected $casts = [
- 'force_docker_cleanup' => 'boolean',
- 'docker_cleanup_threshold' => 'integer',
- 'sentinel_token' => 'encrypted',
- 'is_reachable' => 'boolean',
- 'is_usable' => 'boolean',
- ];
-
- protected static function booted()
- {
- static::creating(function ($setting) {
- try {
- if (str($setting->sentinel_token)->isEmpty()) {
- $setting->generateSentinelToken(save: false, ignoreEvent: true);
- }
- if (str($setting->sentinel_custom_url)->isEmpty()) {
- $setting->generateSentinelUrl(save: false, ignoreEvent: true);
- }
- } catch (\Throwable $e) {
- Log::error('Error creating server setting: '.$e->getMessage());
- }
- });
- static::updated(function ($settings) {
- if (
- $settings->isDirty('sentinel_token') ||
- $settings->isDirty('sentinel_custom_url') ||
- $settings->isDirty('sentinel_metrics_refresh_rate_seconds') ||
- $settings->isDirty('sentinel_metrics_history_days') ||
- $settings->isDirty('sentinel_push_interval_seconds')
- ) {
- $settings->server->restartSentinel();
- }
- });
- }
-
- public function generateSentinelToken(bool $save = true, bool $ignoreEvent = false)
- {
- $data = [
- 'server_uuid' => $this->server->uuid,
- ];
- $token = json_encode($data);
- $encrypted = encrypt($token);
- $this->sentinel_token = $encrypted;
- if ($save) {
- if ($ignoreEvent) {
- $this->saveQuietly();
- } else {
- $this->save();
- }
- }
-
- return $token;
- }
-
- public function generateSentinelUrl(bool $save = true, bool $ignoreEvent = false)
- {
- $domain = null;
- $settings = InstanceSettings::get();
- if ($this->server->isLocalhost()) {
- $domain = 'http://host.docker.internal:8000';
- } elseif ($settings->fqdn) {
- $domain = $settings->fqdn;
- } elseif ($settings->public_ipv4) {
- $domain = 'http://'.$settings->public_ipv4.':8000';
- } elseif ($settings->public_ipv6) {
- $domain = 'http://'.$settings->public_ipv6.':8000';
- }
- $this->sentinel_custom_url = $domain;
- if ($save) {
- if ($ignoreEvent) {
- $this->saveQuietly();
- } else {
- $this->save();
- }
- }
-
- return $domain;
- }
-
- public function server()
- {
- return $this->belongsTo(Server::class);
- }
-
- public function dockerCleanupFrequency(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- return translate_cron_expression($value);
- },
- get: function ($value) {
- return translate_cron_expression($value);
- }
- );
- }
-}
diff --git a/app/Models/Service.php b/app/Models/Service.php
deleted file mode 100644
index 25e6b92ea5..0000000000
--- a/app/Models/Service.php
+++ /dev/null
@@ -1,1355 +0,0 @@
- ['type' => 'integer', 'description' => 'The unique identifier of the service. Only used for database identification.'],
- 'uuid' => ['type' => 'string', 'description' => 'The unique identifier of the service.'],
- 'name' => ['type' => 'string', 'description' => 'The name of the service.'],
- 'environment_id' => ['type' => 'integer', 'description' => 'The unique identifier of the environment where the service is attached to.'],
- 'server_id' => ['type' => 'integer', 'description' => 'The unique identifier of the server where the service is running.'],
- 'description' => ['type' => 'string', 'description' => 'The description of the service.'],
- 'docker_compose_raw' => ['type' => 'string', 'description' => 'The raw docker-compose.yml file of the service.'],
- 'docker_compose' => ['type' => 'string', 'description' => 'The docker-compose.yml file that is parsed and modified by Coolify.'],
- 'destination_type' => ['type' => 'string', 'description' => 'Destination type.'],
- 'destination_id' => ['type' => 'integer', 'description' => 'The unique identifier of the destination where the service is running.'],
- 'connect_to_docker_network' => ['type' => 'boolean', 'description' => 'The flag to connect the service to the predefined Docker network.'],
- 'is_container_label_escape_enabled' => ['type' => 'boolean', 'description' => 'The flag to enable the container label escape.'],
- 'is_container_label_readonly_enabled' => ['type' => 'boolean', 'description' => 'The flag to enable the container label readonly.'],
- 'config_hash' => ['type' => 'string', 'description' => 'The hash of the service configuration.'],
- 'service_type' => ['type' => 'string', 'description' => 'The type of the service.'],
- 'created_at' => ['type' => 'string', 'description' => 'The date and time when the service was created.'],
- 'updated_at' => ['type' => 'string', 'description' => 'The date and time when the service was last updated.'],
- 'deleted_at' => ['type' => 'string', 'description' => 'The date and time when the service was deleted.'],
- ],
-)]
-class Service extends BaseModel
-{
- use HasFactory, SoftDeletes;
-
- private static $parserVersion = '4';
-
- protected $guarded = [];
-
- protected $appends = ['server_status', 'status'];
-
- protected static function booted()
- {
- static::created(function ($service) {
- $service->compose_parsing_version = self::$parserVersion;
- $service->save();
- });
- }
-
- public function isConfigurationChanged(bool $save = false)
- {
- $domains = $this->applications()->get()->pluck('fqdn')->sort()->toArray();
- $domains = implode(',', $domains);
-
- $applicationImages = $this->applications()->get()->pluck('image')->sort();
- $databaseImages = $this->databases()->get()->pluck('image')->sort();
- $images = $applicationImages->merge($databaseImages);
- $images = implode(',', $images->toArray());
-
- $applicationStorages = $this->applications()->get()->pluck('persistentStorages')->flatten()->sortBy('id');
- $databaseStorages = $this->databases()->get()->pluck('persistentStorages')->flatten()->sortBy('id');
- $storages = $applicationStorages->merge($databaseStorages)->implode('updated_at');
-
- $newConfigHash = $images.$domains.$images.$storages;
- $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort());
- $newConfigHash = md5($newConfigHash);
- $oldConfigHash = data_get($this, 'config_hash');
- if ($oldConfigHash === null) {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- if ($oldConfigHash === $newConfigHash) {
- return false;
- } else {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- }
-
- protected function serverStatus(): Attribute
- {
- return Attribute::make(
- get: function () {
- return $this->server->isFunctional();
- }
- );
- }
-
- public function isRunning()
- {
- return (bool) str($this->status)->contains('running');
- }
-
- public function isExited()
- {
- return (bool) str($this->status)->contains('exited');
- }
-
- public function type()
- {
- return 'service';
- }
-
- public function project()
- {
- return data_get($this, 'environment.project');
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function tags()
- {
- return $this->morphToMany(Tag::class, 'taggable');
- }
-
- public static function ownedByCurrentTeam()
- {
- return Service::whereRelation('environment.project.team', 'id', currentTeam()->id)->orderBy('name');
- }
-
- public function getContainersToStop(): array
- {
- $containersToStop = [];
- $applications = $this->applications()->get();
- foreach ($applications as $application) {
- $containersToStop[] = "{$application->name}-{$this->uuid}";
- }
- $dbs = $this->databases()->get();
- foreach ($dbs as $db) {
- $containersToStop[] = "{$db->name}-{$this->uuid}";
- }
-
- return $containersToStop;
- }
-
- public function stopContainers(array $containerNames, $server, int $timeout = 300)
- {
- $processes = [];
- foreach ($containerNames as $containerName) {
- $processes[$containerName] = $this->stopContainer($containerName, $timeout);
- }
-
- $startTime = time();
- while (count($processes) > 0) {
- $finishedProcesses = array_filter($processes, function ($process) {
- return ! $process->running();
- });
- foreach (array_keys($finishedProcesses) as $containerName) {
- unset($processes[$containerName]);
- $this->removeContainer($containerName, $server);
- }
-
- if (time() - $startTime >= $timeout) {
- $this->forceStopRemainingContainers(array_keys($processes), $server);
- break;
- }
-
- usleep(100000);
- }
- }
-
- public function stopContainer(string $containerName, int $timeout): InvokedProcess
- {
- return Process::timeout($timeout)->start("docker stop --time=$timeout $containerName");
- }
-
- public function removeContainer(string $containerName, $server)
- {
- instant_remote_process(command: ["docker rm -f $containerName"], server: $server, throwError: false);
- }
-
- public function forceStopRemainingContainers(array $containerNames, $server)
- {
- foreach ($containerNames as $containerName) {
- instant_remote_process(command: ["docker kill $containerName"], server: $server, throwError: false);
- $this->removeContainer($containerName, $server);
- }
- }
-
- public function delete_configurations()
- {
- $server = data_get($this, 'destination.server');
- $workdir = $this->workdir();
- if (str($workdir)->endsWith($this->uuid)) {
- instant_remote_process(['rm -rf '.$this->workdir()], $server, false);
- }
- }
-
- public function delete_connected_networks($uuid)
- {
- $server = data_get($this, 'destination.server');
- instant_remote_process(["docker network disconnect {$uuid} coolify-proxy"], $server, false);
- instant_remote_process(["docker network rm {$uuid}"], $server, false);
- }
-
- public function getStatusAttribute()
- {
- $applications = $this->applications;
- $databases = $this->databases;
-
- $complexStatus = null;
- $complexHealth = null;
-
- foreach ($applications as $application) {
- if ($application->exclude_from_status) {
- continue;
- }
- $status = str($application->status)->before('(')->trim();
- $health = str($application->status)->between('(', ')')->trim();
- if ($complexStatus === 'degraded') {
- continue;
- }
- if ($status->startsWith('running')) {
- if ($complexStatus === 'exited') {
- $complexStatus = 'degraded';
- } else {
- $complexStatus = 'running';
- }
- } elseif ($status->startsWith('restarting')) {
- $complexStatus = 'degraded';
- } elseif ($status->startsWith('exited')) {
- $complexStatus = 'exited';
- }
- if ($health->value() === 'healthy') {
- if ($complexHealth === 'unhealthy') {
- continue;
- }
- $complexHealth = 'healthy';
- } else {
- $complexHealth = 'unhealthy';
- }
- }
- foreach ($databases as $database) {
- if ($database->exclude_from_status) {
- continue;
- }
- $status = str($database->status)->before('(')->trim();
- $health = str($database->status)->between('(', ')')->trim();
- if ($complexStatus === 'degraded') {
- continue;
- }
- if ($status->startsWith('running')) {
- if ($complexStatus === 'exited') {
- $complexStatus = 'degraded';
- } else {
- $complexStatus = 'running';
- }
- } elseif ($status->startsWith('restarting')) {
- $complexStatus = 'degraded';
- } elseif ($status->startsWith('exited')) {
- $complexStatus = 'exited';
- }
- if ($health->value() === 'healthy') {
- if ($complexHealth === 'unhealthy') {
- continue;
- }
- $complexHealth = 'healthy';
- } else {
- $complexHealth = 'unhealthy';
- }
- }
-
- return "{$complexStatus}:{$complexHealth}";
- }
-
- public function extraFields()
- {
- $fields = collect([]);
- $applications = $this->applications()->get();
- foreach ($applications as $application) {
- $image = str($application->image)->before(':');
- if ($image->isEmpty()) {
- continue;
- }
- switch ($image) {
- case $image->contains('castopod'):
- $data = collect([]);
- $disable_https = $this->environment_variables()->where('key', 'CP_DISABLE_HTTPS')->first();
- if ($disable_https) {
- $data = $data->merge([
- 'Disable HTTPS' => [
- 'key' => 'CP_DISABLE_HTTPS',
- 'value' => data_get($disable_https, 'value'),
- 'rules' => 'required',
- 'customHelper' => 'If you want to use https, set this to 0. Variable name: CP_DISABLE_HTTPS',
- ],
- ]);
- }
- $fields->put('Castopod', $data->toArray());
- break;
- case $image->contains('label-studio'):
- $data = collect([]);
- $username = $this->environment_variables()->where('key', 'LABEL_STUDIO_USERNAME')->first();
- $password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_LABELSTUDIO')->first();
- if ($username) {
- $data = $data->merge([
- 'Username' => [
- 'key' => 'LABEL_STUDIO_USERNAME',
- 'value' => data_get($username, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- if ($password) {
- $data = $data->merge([
- 'Password' => [
- 'key' => data_get($password, 'key'),
- 'value' => data_get($password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('Label Studio', $data->toArray());
- break;
- case $image->contains('litellm'):
- $data = collect([]);
- $username = $this->environment_variables()->where('key', 'SERVICE_USER_UI')->first();
- $password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_UI')->first();
- if ($username) {
- $data = $data->merge([
- 'Username' => [
- 'key' => data_get($username, 'key'),
- 'value' => data_get($username, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- if ($password) {
- $data = $data->merge([
- 'Password' => [
- 'key' => data_get($password, 'key'),
- 'value' => data_get($password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('Litellm', $data->toArray());
- break;
- case $image->contains('langfuse'):
- $data = collect([]);
- $email = $this->environment_variables()->where('key', 'LANGFUSE_INIT_USER_EMAIL')->first();
- if ($email) {
- $data = $data->merge([
- 'Admin Email' => [
- 'key' => data_get($email, 'key'),
- 'value' => data_get($email, 'value'),
- 'rules' => 'required|email',
- ],
- ]);
- }
- $password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_LANGFUSE')->first();
- if ($password) {
- $data = $data->merge([
- 'Admin Password' => [
- 'key' => data_get($password, 'key'),
- 'value' => data_get($password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('Langfuse', $data->toArray());
- break;
- case $image->contains('invoiceninja'):
- $data = collect([]);
- $email = $this->environment_variables()->where('key', 'IN_USER_EMAIL')->first();
- $data = $data->merge([
- 'Email' => [
- 'key' => data_get($email, 'key'),
- 'value' => data_get($email, 'value'),
- 'rules' => 'required|email',
- ],
- ]);
- $password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_INVOICENINJAUSER')->first();
- $data = $data->merge([
- 'Password' => [
- 'key' => data_get($password, 'key'),
- 'value' => data_get($password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- $fields->put('Invoice Ninja', $data->toArray());
- break;
- case $image->contains('argilla'):
- $data = collect([]);
- $api_key = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_APIKEY')->first();
- $data = $data->merge([
- 'API Key' => [
- 'key' => data_get($api_key, 'key'),
- 'value' => data_get($api_key, 'value'),
- 'isPassword' => true,
- 'rules' => 'required',
- ],
- ]);
- $data = $data->merge([
- 'API Key' => [
- 'key' => data_get($api_key, 'key'),
- 'value' => data_get($api_key, 'value'),
- 'isPassword' => true,
- 'rules' => 'required',
- ],
- ]);
- $username = $this->environment_variables()->where('key', 'ARGILLA_USERNAME')->first();
- $data = $data->merge([
- 'Username' => [
- 'key' => data_get($username, 'key'),
- 'value' => data_get($username, 'value'),
- 'rules' => 'required',
- ],
- ]);
- $password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_ARGILLA')->first();
- $data = $data->merge([
- 'Password' => [
- 'key' => data_get($password, 'key'),
- 'value' => data_get($password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- $fields->put('Argilla', $data->toArray());
- break;
- case $image->contains('rabbitmq'):
- $data = collect([]);
- $host_port = $this->environment_variables()->where('key', 'PORT')->first();
- $username = $this->environment_variables()->where('key', 'SERVICE_USER_RABBITMQ')->first();
- $password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_RABBITMQ')->first();
- if ($host_port) {
- $data = $data->merge([
- 'Host Port Binding' => [
- 'key' => data_get($host_port, 'key'),
- 'value' => data_get($host_port, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- if ($username) {
- $data = $data->merge([
- 'Username' => [
- 'key' => data_get($username, 'key'),
- 'value' => data_get($username, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- if ($password) {
- $data = $data->merge([
- 'Password' => [
- 'key' => data_get($password, 'key'),
- 'value' => data_get($password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('RabbitMQ', $data->toArray());
- break;
- case $image->contains('tolgee'):
- $data = collect([]);
- $admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_TOLGEE')->first();
- $data = $data->merge([
- 'Admin User' => [
- 'key' => 'TOLGEE_AUTHENTICATION_INITIAL_USERNAME',
- 'value' => 'admin',
- 'readonly' => true,
- 'rules' => 'required',
- ],
- ]);
- if ($admin_password) {
- $data = $data->merge([
- 'Admin Password' => [
- 'key' => data_get($admin_password, 'key'),
- 'value' => data_get($admin_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('Tolgee', $data->toArray());
- break;
- case $image->contains('logto'):
- $data = collect([]);
- $logto_endpoint = $this->environment_variables()->where('key', 'LOGTO_ENDPOINT')->first();
- $logto_admin_endpoint = $this->environment_variables()->where('key', 'LOGTO_ADMIN_ENDPOINT')->first();
- if ($logto_endpoint) {
- $data = $data->merge([
- 'Endpoint' => [
- 'key' => data_get($logto_endpoint, 'key'),
- 'value' => data_get($logto_endpoint, 'value'),
- 'rules' => 'required|url',
- ],
- ]);
- }
- if ($logto_admin_endpoint) {
- $data = $data->merge([
- 'Admin Endpoint' => [
- 'key' => data_get($logto_admin_endpoint, 'key'),
- 'value' => data_get($logto_admin_endpoint, 'value'),
- 'rules' => 'required|url',
- ],
- ]);
- }
- $fields->put('Logto', $data->toArray());
- break;
- case $image->contains('unleash-server'):
- $data = collect([]);
- $admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_UNLEASH')->first();
- $data = $data->merge([
- 'Admin User' => [
- 'key' => 'SERVICE_USER_UNLEASH',
- 'value' => 'admin',
- 'readonly' => true,
- 'rules' => 'required',
- ],
- ]);
- if ($admin_password) {
- $data = $data->merge([
- 'Admin Password' => [
- 'key' => data_get($admin_password, 'key'),
- 'value' => data_get($admin_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('Unleash', $data->toArray());
- break;
- case $image->contains('grafana'):
- $data = collect([]);
- $admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_GRAFANA')->first();
- $data = $data->merge([
- 'Admin User' => [
- 'key' => 'GF_SECURITY_ADMIN_USER',
- 'value' => 'admin',
- 'readonly' => true,
- 'rules' => 'required',
- ],
- ]);
- if ($admin_password) {
- $data = $data->merge([
- 'Admin Password' => [
- 'key' => data_get($admin_password, 'key'),
- 'value' => data_get($admin_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('Grafana', $data->toArray());
- break;
- case $image->contains('directus'):
- $data = collect([]);
- $admin_email = $this->environment_variables()->where('key', 'ADMIN_EMAIL')->first();
- $admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_ADMIN')->first();
-
- if ($admin_email) {
- $data = $data->merge([
- 'Admin Email' => [
- 'key' => data_get($admin_email, 'key'),
- 'value' => data_get($admin_email, 'value'),
- 'rules' => 'required|email',
- ],
- ]);
- }
- if ($admin_password) {
- $data = $data->merge([
- 'Admin Password' => [
- 'key' => data_get($admin_password, 'key'),
- 'value' => data_get($admin_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('Directus', $data->toArray());
- break;
- case $image->contains('kong'):
- $data = collect([]);
- $dashboard_user = $this->environment_variables()->where('key', 'SERVICE_USER_ADMIN')->first();
- $dashboard_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_ADMIN')->first();
- if ($dashboard_user) {
- $data = $data->merge([
- 'Dashboard User' => [
- 'key' => data_get($dashboard_user, 'key'),
- 'value' => data_get($dashboard_user, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- if ($dashboard_password) {
- $data = $data->merge([
- 'Dashboard Password' => [
- 'key' => data_get($dashboard_password, 'key'),
- 'value' => data_get($dashboard_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('Supabase', $data->toArray());
- case $image->contains('minio'):
- $data = collect([]);
- $console_url = $this->environment_variables()->where('key', 'MINIO_BROWSER_REDIRECT_URL')->first();
- $s3_api_url = $this->environment_variables()->where('key', 'MINIO_SERVER_URL')->first();
- $admin_user = $this->environment_variables()->where('key', 'SERVICE_USER_MINIO')->first();
- if (is_null($admin_user)) {
- $admin_user = $this->environment_variables()->where('key', 'MINIO_ROOT_USER')->first();
- }
- $admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_MINIO')->first();
- if (is_null($admin_password)) {
- $admin_password = $this->environment_variables()->where('key', 'MINIO_ROOT_PASSWORD')->first();
- }
-
- if ($console_url) {
- $data = $data->merge([
- 'Console URL' => [
- 'key' => data_get($console_url, 'key'),
- 'value' => data_get($console_url, 'value'),
- 'rules' => 'required|url',
- ],
- ]);
- }
- if ($s3_api_url) {
- $data = $data->merge([
- 'S3 API URL' => [
- 'key' => data_get($s3_api_url, 'key'),
- 'value' => data_get($s3_api_url, 'value'),
- 'rules' => 'required|url',
- ],
- ]);
- }
- if ($admin_user) {
- $data = $data->merge([
- 'Admin User' => [
- 'key' => data_get($admin_user, 'key'),
- 'value' => data_get($admin_user, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- if ($admin_password) {
- $data = $data->merge([
- 'Admin Password' => [
- 'key' => data_get($admin_password, 'key'),
- 'value' => data_get($admin_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
-
- $fields->put('MinIO', $data->toArray());
- break;
- case $image->contains('weblate'):
- $data = collect([]);
- $admin_email = $this->environment_variables()->where('key', 'WEBLATE_ADMIN_EMAIL')->first();
- $admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_WEBLATE')->first();
-
- if ($admin_email) {
- $data = $data->merge([
- 'Admin Email' => [
- 'key' => data_get($admin_email, 'key'),
- 'value' => data_get($admin_email, 'value'),
- 'rules' => 'required|email',
- ],
- ]);
- }
- if ($admin_password) {
- $data = $data->merge([
- 'Admin Password' => [
- 'key' => data_get($admin_password, 'key'),
- 'value' => data_get($admin_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('Weblate', $data->toArray());
- break;
- case $image->contains('meilisearch'):
- $data = collect([]);
- $SERVICE_PASSWORD_MEILISEARCH = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_MEILISEARCH')->first();
- if ($SERVICE_PASSWORD_MEILISEARCH) {
- $data = $data->merge([
- 'API Key' => [
- 'key' => data_get($SERVICE_PASSWORD_MEILISEARCH, 'key'),
- 'value' => data_get($SERVICE_PASSWORD_MEILISEARCH, 'value'),
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('Meilisearch', $data->toArray());
- break;
- case $image->contains('ghost'):
- $data = collect([]);
- $MAIL_OPTIONS_AUTH_PASS = $this->environment_variables()->where('key', 'MAIL_OPTIONS_AUTH_PASS')->first();
- $MAIL_OPTIONS_AUTH_USER = $this->environment_variables()->where('key', 'MAIL_OPTIONS_AUTH_USER')->first();
- $MAIL_OPTIONS_SECURE = $this->environment_variables()->where('key', 'MAIL_OPTIONS_SECURE')->first();
- $MAIL_OPTIONS_PORT = $this->environment_variables()->where('key', 'MAIL_OPTIONS_PORT')->first();
- $MAIL_OPTIONS_SERVICE = $this->environment_variables()->where('key', 'MAIL_OPTIONS_SERVICE')->first();
- $MAIL_OPTIONS_HOST = $this->environment_variables()->where('key', 'MAIL_OPTIONS_HOST')->first();
- if ($MAIL_OPTIONS_AUTH_PASS) {
- $data = $data->merge([
- 'Mail Password' => [
- 'key' => data_get($MAIL_OPTIONS_AUTH_PASS, 'key'),
- 'value' => data_get($MAIL_OPTIONS_AUTH_PASS, 'value'),
- 'isPassword' => true,
- ],
- ]);
- }
- if ($MAIL_OPTIONS_AUTH_USER) {
- $data = $data->merge([
- 'Mail User' => [
- 'key' => data_get($MAIL_OPTIONS_AUTH_USER, 'key'),
- 'value' => data_get($MAIL_OPTIONS_AUTH_USER, 'value'),
- ],
- ]);
- }
- if ($MAIL_OPTIONS_SECURE) {
- $data = $data->merge([
- 'Mail Secure' => [
- 'key' => data_get($MAIL_OPTIONS_SECURE, 'key'),
- 'value' => data_get($MAIL_OPTIONS_SECURE, 'value'),
- ],
- ]);
- }
- if ($MAIL_OPTIONS_PORT) {
- $data = $data->merge([
- 'Mail Port' => [
- 'key' => data_get($MAIL_OPTIONS_PORT, 'key'),
- 'value' => data_get($MAIL_OPTIONS_PORT, 'value'),
- ],
- ]);
- }
- if ($MAIL_OPTIONS_SERVICE) {
- $data = $data->merge([
- 'Mail Service' => [
- 'key' => data_get($MAIL_OPTIONS_SERVICE, 'key'),
- 'value' => data_get($MAIL_OPTIONS_SERVICE, 'value'),
- ],
- ]);
- }
- if ($MAIL_OPTIONS_HOST) {
- $data = $data->merge([
- 'Mail Host' => [
- 'key' => data_get($MAIL_OPTIONS_HOST, 'key'),
- 'value' => data_get($MAIL_OPTIONS_HOST, 'value'),
- ],
- ]);
- }
-
- $fields->put('Ghost', $data->toArray());
- break;
-
- case $image->contains('vaultwarden'):
- $data = collect([]);
-
- $DATABASE_URL = $this->environment_variables()->where('key', 'DATABASE_URL')->first();
- $ADMIN_TOKEN = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_64_ADMIN')->first();
- $SIGNUP_ALLOWED = $this->environment_variables()->where('key', 'SIGNUP_ALLOWED')->first();
- $PUSH_ENABLED = $this->environment_variables()->where('key', 'PUSH_ENABLED')->first();
- $PUSH_INSTALLATION_ID = $this->environment_variables()->where('key', 'PUSH_SERVICE_ID')->first();
- $PUSH_INSTALLATION_KEY = $this->environment_variables()->where('key', 'PUSH_SERVICE_KEY')->first();
-
- if ($DATABASE_URL) {
- $data = $data->merge([
- 'Database URL' => [
- 'key' => data_get($DATABASE_URL, 'key'),
- 'value' => data_get($DATABASE_URL, 'value'),
- ],
- ]);
- }
- if ($ADMIN_TOKEN) {
- $data = $data->merge([
- 'Admin Password' => [
- 'key' => data_get($ADMIN_TOKEN, 'key'),
- 'value' => data_get($ADMIN_TOKEN, 'value'),
- 'isPassword' => true,
- ],
- ]);
- }
- if ($SIGNUP_ALLOWED) {
- $data = $data->merge([
- 'Signup Allowed' => [
- 'key' => data_get($SIGNUP_ALLOWED, 'key'),
- 'value' => data_get($SIGNUP_ALLOWED, 'value'),
- 'rules' => 'required|string|in:true,false',
- ],
- ]);
- }
-
- if ($PUSH_ENABLED) {
- $data = $data->merge([
- 'Push Enabled' => [
- 'key' => data_get($PUSH_ENABLED, 'key'),
- 'value' => data_get($PUSH_ENABLED, 'value'),
- 'rules' => 'required|string|in:true,false',
- ],
- ]);
- }
- if ($PUSH_INSTALLATION_ID) {
- $data = $data->merge([
- 'Push Installation ID' => [
- 'key' => data_get($PUSH_INSTALLATION_ID, 'key'),
- 'value' => data_get($PUSH_INSTALLATION_ID, 'value'),
- ],
- ]);
- }
- if ($PUSH_INSTALLATION_KEY) {
- $data = $data->merge([
- 'Push Installation Key' => [
- 'key' => data_get($PUSH_INSTALLATION_KEY, 'key'),
- 'value' => data_get($PUSH_INSTALLATION_KEY, 'value'),
- 'isPassword' => true,
- ],
- ]);
- }
-
- $fields->put('Vaultwarden', $data);
- break;
- case $image->contains('gitlab/gitlab'):
- $password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_GITLAB')->first();
- $data = collect([]);
- if ($password) {
- $data = $data->merge([
- 'Root Password' => [
- 'key' => data_get($password, 'key'),
- 'value' => data_get($password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $data = $data->merge([
- 'Root User' => [
- 'key' => 'GITLAB_ROOT_USER',
- 'value' => 'root',
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
-
- $fields->put('GitLab', $data->toArray());
- break;
- case $image->contains('code-server'):
- $data = collect([]);
- $password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_64_PASSWORDCODESERVER')->first();
- if ($password) {
- $data = $data->merge([
- 'Password' => [
- 'key' => data_get($password, 'key'),
- 'value' => data_get($password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $sudoPassword = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_SUDOCODESERVER')->first();
- if ($sudoPassword) {
- $data = $data->merge([
- 'Sudo Password' => [
- 'key' => data_get($sudoPassword, 'key'),
- 'value' => data_get($sudoPassword, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- $fields->put('Code Server', $data->toArray());
- break;
- case $image->contains('elestio/strapi'):
- $data = collect([]);
- $license = $this->environment_variables()->where('key', 'STRAPI_LICENSE')->first();
- if ($license) {
- $data = $data->merge([
- 'License' => [
- 'key' => data_get($license, 'key'),
- 'value' => data_get($license, 'value'),
- ],
- ]);
- }
- $nodeEnv = $this->environment_variables()->where('key', 'NODE_ENV')->first();
- if ($nodeEnv) {
- $data = $data->merge([
- 'Node Environment' => [
- 'key' => data_get($nodeEnv, 'key'),
- 'value' => data_get($nodeEnv, 'value'),
- ],
- ]);
- }
-
- $fields->put('Strapi', $data->toArray());
- break;
- default:
- $data = collect([]);
- $admin_user = $this->environment_variables()->where('key', 'SERVICE_USER_ADMIN')->first();
- // Chaskiq
- $admin_email = $this->environment_variables()->where('key', 'ADMIN_EMAIL')->first();
-
- $admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_ADMIN')->first();
- if ($admin_user) {
- $data = $data->merge([
- 'User' => [
- 'key' => data_get($admin_user, 'key'),
- 'value' => data_get($admin_user, 'value', 'admin'),
- 'readonly' => true,
- 'rules' => 'required',
- ],
- ]);
- }
- if ($admin_password) {
- $data = $data->merge([
- 'Password' => [
- 'key' => data_get($admin_password, 'key'),
- 'value' => data_get($admin_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- if ($admin_email) {
- $data = $data->merge([
- 'Email' => [
- 'key' => data_get($admin_email, 'key'),
- 'value' => data_get($admin_email, 'value'),
- 'rules' => 'required|email',
- ],
- ]);
- }
- $fields->put('Admin', $data->toArray());
- break;
- }
- }
- $databases = $this->databases()->get();
-
- foreach ($databases as $database) {
- $image = str($database->image)->before(':');
- if ($image->isEmpty()) {
- continue;
- }
- switch ($image) {
- case $image->contains('postgres'):
- $userVariables = ['SERVICE_USER_POSTGRES', 'SERVICE_USER_POSTGRESQL'];
- $passwordVariables = ['SERVICE_PASSWORD_POSTGRES', 'SERVICE_PASSWORD_POSTGRESQL'];
- $dbNameVariables = ['POSTGRESQL_DATABASE', 'POSTGRES_DB'];
- $postgres_user = $this->environment_variables()->whereIn('key', $userVariables)->first();
- $postgres_password = $this->environment_variables()->whereIn('key', $passwordVariables)->first();
- $postgres_db_name = $this->environment_variables()->whereIn('key', $dbNameVariables)->first();
- $data = collect([]);
- if ($postgres_user) {
- $data = $data->merge([
- 'User' => [
- 'key' => data_get($postgres_user, 'key'),
- 'value' => data_get($postgres_user, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- if ($postgres_password) {
- $data = $data->merge([
- 'Password' => [
- 'key' => data_get($postgres_password, 'key'),
- 'value' => data_get($postgres_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- if ($postgres_db_name) {
- $data = $data->merge([
- 'Database Name' => [
- 'key' => data_get($postgres_db_name, 'key'),
- 'value' => data_get($postgres_db_name, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- $fields->put('PostgreSQL', $data->toArray());
- break;
- case $image->contains('mysql'):
- $userVariables = ['SERVICE_USER_MYSQL', 'SERVICE_USER_WORDPRESS', 'MYSQL_USER'];
- $passwordVariables = ['SERVICE_PASSWORD_MYSQL', 'SERVICE_PASSWORD_WORDPRESS', 'MYSQL_PASSWORD', 'SERVICE_PASSWORD_64_MYSQL'];
- $rootPasswordVariables = ['SERVICE_PASSWORD_MYSQLROOT', 'SERVICE_PASSWORD_ROOT', 'SERVICE_PASSWORD_64_MYSQLROOT'];
- $dbNameVariables = ['MYSQL_DATABASE'];
- $mysql_user = $this->environment_variables()->whereIn('key', $userVariables)->first();
- $mysql_password = $this->environment_variables()->whereIn('key', $passwordVariables)->first();
- $mysql_root_password = $this->environment_variables()->whereIn('key', $rootPasswordVariables)->first();
- $mysql_db_name = $this->environment_variables()->whereIn('key', $dbNameVariables)->first();
- $data = collect([]);
- if ($mysql_user) {
- $data = $data->merge([
- 'User' => [
- 'key' => data_get($mysql_user, 'key'),
- 'value' => data_get($mysql_user, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- if ($mysql_password) {
- $data = $data->merge([
- 'Password' => [
- 'key' => data_get($mysql_password, 'key'),
- 'value' => data_get($mysql_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- if ($mysql_root_password) {
- $data = $data->merge([
- 'Root Password' => [
- 'key' => data_get($mysql_root_password, 'key'),
- 'value' => data_get($mysql_root_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- if ($mysql_db_name) {
- $data = $data->merge([
- 'Database Name' => [
- 'key' => data_get($mysql_db_name, 'key'),
- 'value' => data_get($mysql_db_name, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- $fields->put('MySQL', $data->toArray());
- break;
- case $image->contains('mariadb'):
- $userVariables = ['SERVICE_USER_MARIADB', 'SERVICE_USER_WORDPRESS', 'SERVICE_USER_MYSQL', 'MYSQL_USER'];
- $passwordVariables = ['SERVICE_PASSWORD_MARIADB', 'SERVICE_PASSWORD_WORDPRESS', '_APP_DB_PASS', 'MYSQL_PASSWORD'];
- $rootPasswordVariables = ['SERVICE_PASSWORD_MARIADBROOT', 'SERVICE_PASSWORD_ROOT', '_APP_DB_ROOT_PASS', 'MYSQL_ROOT_PASSWORD'];
- $dbNameVariables = ['SERVICE_DATABASE_MARIADB', 'SERVICE_DATABASE_WORDPRESS', '_APP_DB_SCHEMA', 'MYSQL_DATABASE'];
-
- $mariadb_user = $this->environment_variables()->whereIn('key', $userVariables)->first();
- $mariadb_password = $this->environment_variables()->whereIn('key', $passwordVariables)->first();
- $mariadb_root_password = $this->environment_variables()->whereIn('key', $rootPasswordVariables)->first();
- $mariadb_db_name = $this->environment_variables()->whereIn('key', $dbNameVariables)->first();
- $data = collect([]);
-
- if ($mariadb_user) {
- $data = $data->merge([
- 'User' => [
- 'key' => data_get($mariadb_user, 'key'),
- 'value' => data_get($mariadb_user, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- if ($mariadb_password) {
- $data = $data->merge([
- 'Password' => [
- 'key' => data_get($mariadb_password, 'key'),
- 'value' => data_get($mariadb_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- if ($mariadb_root_password) {
- $data = $data->merge([
- 'Root Password' => [
- 'key' => data_get($mariadb_root_password, 'key'),
- 'value' => data_get($mariadb_root_password, 'value'),
- 'rules' => 'required',
- 'isPassword' => true,
- ],
- ]);
- }
- if ($mariadb_db_name) {
- $data = $data->merge([
- 'Database Name' => [
- 'key' => data_get($mariadb_db_name, 'key'),
- 'value' => data_get($mariadb_db_name, 'value'),
- 'rules' => 'required',
- ],
- ]);
- }
- $fields->put('MariaDB', $data->toArray());
- break;
- }
- }
- $fields = collect($fields)->map(function ($extraFields) {
- if (is_array($extraFields)) {
- $extraFields = collect($extraFields)->map(function ($field) {
- if (filled($field['value']) && str($field['value'])->startsWith('$SERVICE_')) {
- $searchValue = str($field['value'])->after('$')->value;
- $newValue = $this->environment_variables()->where('key', $searchValue)->first();
- if ($newValue) {
- $field['value'] = $newValue->value;
- }
- }
-
- return $field;
- });
- }
-
- return $extraFields;
- });
-
- return $fields;
- }
-
- public function saveExtraFields($fields)
- {
- foreach ($fields as $field) {
- $key = data_get($field, 'key');
- $value = data_get($field, 'value');
- $found = $this->environment_variables()->where('key', $key)->first();
- if ($found) {
- $found->value = $value;
- $found->save();
- } else {
- $this->environment_variables()->create([
- 'key' => $key,
- 'value' => $value,
- 'is_build_time' => false,
- 'resourceable_id' => $this->id,
- 'resourceable_type' => $this->getMorphClass(),
- 'is_preview' => false,
- ]);
- }
- }
- }
-
- public function link()
- {
- if (data_get($this, 'environment.project.uuid')) {
- return route('project.service.configuration', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'service_uuid' => data_get($this, 'uuid'),
- ]);
- }
-
- return null;
- }
-
- public function taskLink($task_uuid)
- {
- if (data_get($this, 'environment.project.uuid')) {
- $route = route('project.service.scheduled-tasks', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'service_uuid' => data_get($this, 'uuid'),
- 'task_uuid' => $task_uuid,
- ]);
- $settings = InstanceSettings::get();
- if (data_get($settings, 'fqdn')) {
- $url = Url::fromString($route);
- $url = $url->withPort(null);
- $fqdn = data_get($settings, 'fqdn');
- $fqdn = str_replace(['http://', 'https://'], '', $fqdn);
- $url = $url->withHost($fqdn);
-
- return $url->__toString();
- }
-
- return $route;
- }
-
- return null;
- }
-
- public function documentation()
- {
- $services = get_service_templates();
- $service = data_get($services, str($this->name)->beforeLast('-')->value, []);
-
- return data_get($service, 'documentation', config('constants.urls.docs'));
- }
-
- public function applications()
- {
- return $this->hasMany(ServiceApplication::class);
- }
-
- public function databases()
- {
- return $this->hasMany(ServiceDatabase::class);
- }
-
- public function destination()
- {
- return $this->morphTo();
- }
-
- public function environment()
- {
- return $this->belongsTo(Environment::class);
- }
-
- public function server()
- {
- return $this->belongsTo(Server::class);
- }
-
- public function byUuid(string $uuid)
- {
- $app = $this->applications()->whereUuid($uuid)->first();
- if ($app) {
- return $app;
- }
- $db = $this->databases()->whereUuid($uuid)->first();
- if ($db) {
- return $db;
- }
-
- return null;
- }
-
- public function byName(string $name)
- {
- $app = $this->applications()->whereName($name)->first();
- if ($app) {
- return $app;
- }
- $db = $this->databases()->whereName($name)->first();
- if ($db) {
- return $db;
- }
-
- return null;
- }
-
- public function scheduled_tasks(): HasMany
- {
- return $this->hasMany(ScheduledTask::class)->orderBy('name', 'asc');
- }
-
- public function environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
- }
-
- public function environment_variables_preview()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->where('is_preview', true)
- ->orderByRaw("LOWER(key) LIKE LOWER('SERVICE%') DESC, LOWER(key) ASC");
- }
-
- public function workdir()
- {
- return service_configuration_dir()."/{$this->uuid}";
- }
-
- public function saveComposeConfigs()
- {
- $workdir = $this->workdir();
-
- instant_remote_process([
- "mkdir -p $workdir",
- "cd $workdir",
- ], $this->server);
-
- $filename = new Cuid2.'-docker-compose.yml';
- Storage::disk('local')->put("tmp/{$filename}", $this->docker_compose);
- $path = Storage::path("tmp/{$filename}");
- instant_scp($path, "{$workdir}/docker-compose.yml", $this->server);
- Storage::disk('local')->delete("tmp/{$filename}");
-
- $commands[] = "cd $workdir";
- $commands[] = 'rm -f .env || true';
-
- $envs_from_coolify = $this->environment_variables()->get();
- $sorted = $envs_from_coolify->sortBy(function ($env) {
- if (str($env->key)->startsWith('SERVICE_')) {
- return 1;
- }
- if (str($env->value)->startsWith('$SERVICE_') || str($env->value)->startsWith('${SERVICE_')) {
- return 2;
- }
-
- return 3;
- });
- foreach ($sorted as $env) {
- if (version_compare($env->version, '4.0.0-beta.347', '<=')) {
- $commands[] = "echo '{$env->key}={$env->real_value}' >> .env";
- } else {
- $real_value = $env->real_value;
- if ($env->version === '4.0.0-beta.239') {
- $real_value = $env->real_value;
- } else {
- if ($env->is_literal || $env->is_multiline) {
- $real_value = '\''.$real_value.'\'';
- } else {
- $real_value = escapeEnvVariables($env->real_value);
- }
- }
- $commands[] = "echo \"{$env->key}={$real_value}\" >> .env";
- }
- }
- if ($sorted->count() === 0) {
- $commands[] = 'touch .env';
- }
- instant_remote_process($commands, $this->server);
- }
-
- public function parse(bool $isNew = false): Collection
- {
- if ((int) $this->compose_parsing_version >= 3) {
- return newParser($this);
- } elseif ($this->docker_compose_raw) {
- return parseDockerComposeFile($this, $isNew);
- } else {
- return collect([]);
- }
- }
-
- public function networks()
- {
- return getTopLevelNetworks($this);
- }
-
- protected function isDeployable(): Attribute
- {
- return Attribute::make(
- get: function () {
- $envs = $this->environment_variables()->where('is_required', true)->get();
- foreach ($envs as $env) {
- if ($env->is_really_required) {
- return false;
- }
- }
-
- return true;
- }
- );
- }
-}
diff --git a/app/Models/ServiceApplication.php b/app/Models/ServiceApplication.php
deleted file mode 100644
index 5cafc90422..0000000000
--- a/app/Models/ServiceApplication.php
+++ /dev/null
@@ -1,130 +0,0 @@
-update(['fqdn' => null]);
- $service->persistentStorages()->delete();
- $service->fileStorages()->delete();
- });
- static::saving(function ($service) {
- if ($service->isDirty('status')) {
- $service->forceFill(['last_online_at' => now()]);
- }
- });
- }
-
- public function restart()
- {
- $container_id = $this->name.'-'.$this->service->uuid;
- instant_remote_process(["docker restart {$container_id}"], $this->service->server);
- }
-
- public static function ownedByCurrentTeamAPI(int $teamId)
- {
- return ServiceApplication::whereRelation('service.environment.project.team', 'id', $teamId)->orderBy('name');
- }
-
- public static function ownedByCurrentTeam()
- {
- return ServiceApplication::whereRelation('service.environment.project.team', 'id', currentTeam()->id)->orderBy('name');
- }
-
- public function isRunning()
- {
- return str($this->status)->contains('running');
- }
-
- public function isExited()
- {
- return str($this->status)->contains('exited');
- }
-
- public function isLogDrainEnabled()
- {
- return data_get($this, 'is_log_drain_enabled', false);
- }
-
- public function isStripprefixEnabled()
- {
- return data_get($this, 'is_stripprefix_enabled', true);
- }
-
- public function isGzipEnabled()
- {
- return data_get($this, 'is_gzip_enabled', true);
- }
-
- public function type()
- {
- return 'service';
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function workdir()
- {
- return service_configuration_dir()."/{$this->service->uuid}";
- }
-
- public function serviceType()
- {
- $found = str(collect(SPECIFIC_SERVICES)->filter(function ($service) {
- return str($this->image)->before(':')->value() === $service;
- })->first());
- if ($found->isNotEmpty()) {
- return $found;
- }
-
- return null;
- }
-
- public function service()
- {
- return $this->belongsTo(Service::class);
- }
-
- public function persistentStorages()
- {
- return $this->morphMany(LocalPersistentVolume::class, 'resource');
- }
-
- public function fileStorages()
- {
- return $this->morphMany(LocalFileVolume::class, 'resource');
- }
-
- public function fqdns(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->fqdn)
- ? []
- : explode(',', $this->fqdn),
- );
- }
-
- public function getFilesFromServer(bool $isInit = false)
- {
- getFilesystemVolumesFromServer($this, $isInit);
- }
-
- public function isBackupSolutionAvailable()
- {
- return false;
- }
-}
diff --git a/app/Models/ServiceDatabase.php b/app/Models/ServiceDatabase.php
deleted file mode 100644
index c2a0df8cdf..0000000000
--- a/app/Models/ServiceDatabase.php
+++ /dev/null
@@ -1,146 +0,0 @@
-persistentStorages()->delete();
- $service->fileStorages()->delete();
- });
- static::saving(function ($service) {
- if ($service->isDirty('status')) {
- $service->forceFill(['last_online_at' => now()]);
- }
- });
- }
-
- public static function ownedByCurrentTeamAPI(int $teamId)
- {
- return ServiceDatabase::whereRelation('service.environment.project.team', 'id', $teamId)->orderBy('name');
- }
-
- public static function ownedByCurrentTeam()
- {
- return ServiceDatabase::whereRelation('service.environment.project.team', 'id', currentTeam()->id)->orderBy('name');
- }
-
- public function restart()
- {
- $container_id = $this->name.'-'.$this->service->uuid;
- remote_process(["docker restart {$container_id}"], $this->service->server);
- }
-
- public function isRunning()
- {
- return str($this->status)->contains('running');
- }
-
- public function isExited()
- {
- return str($this->status)->contains('exited');
- }
-
- public function isLogDrainEnabled()
- {
- return data_get($this, 'is_log_drain_enabled', false);
- }
-
- public function isStripprefixEnabled()
- {
- return data_get($this, 'is_stripprefix_enabled', true);
- }
-
- public function isGzipEnabled()
- {
- return data_get($this, 'is_gzip_enabled', true);
- }
-
- public function type()
- {
- return 'service';
- }
-
- public function serviceType()
- {
- return null;
- }
-
- public function databaseType()
- {
- $image = str($this->image)->before(':');
- if ($image->contains('supabase/postgres')) {
- $finalImage = 'supabase/postgres';
- } elseif ($image->contains('postgres') || $image->contains('postgis')) {
- $finalImage = 'postgresql';
- } else {
- $finalImage = $image;
- }
-
- return "standalone-$finalImage";
- }
-
- public function getServiceDatabaseUrl()
- {
- $port = $this->public_port;
- $realIp = $this->service->server->ip;
- if ($this->service->server->isLocalhost() || isDev()) {
- $realIp = base_ip();
- }
-
- return "{$realIp}:{$port}";
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function workdir()
- {
- return service_configuration_dir()."/{$this->service->uuid}";
- }
-
- public function service()
- {
- return $this->belongsTo(Service::class);
- }
-
- public function persistentStorages()
- {
- return $this->morphMany(LocalPersistentVolume::class, 'resource');
- }
-
- public function fileStorages()
- {
- return $this->morphMany(LocalFileVolume::class, 'resource');
- }
-
- public function getFilesFromServer(bool $isInit = false)
- {
- getFilesystemVolumesFromServer($this, $isInit);
- }
-
- public function scheduledBackups()
- {
- return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
- }
-
- public function isBackupSolutionAvailable()
- {
- return str($this->databaseType())->contains('mysql') ||
- str($this->databaseType())->contains('postgres') ||
- str($this->databaseType())->contains('postgis') ||
- str($this->databaseType())->contains('mariadb') ||
- str($this->databaseType())->contains('mongodb');
- }
-}
diff --git a/app/Models/SharedEnvironmentVariable.php b/app/Models/SharedEnvironmentVariable.php
deleted file mode 100644
index aab8b87350..0000000000
--- a/app/Models/SharedEnvironmentVariable.php
+++ /dev/null
@@ -1,15 +0,0 @@
- 'string',
- 'value' => 'encrypted',
- ];
-}
diff --git a/app/Models/SlackNotificationSettings.php b/app/Models/SlackNotificationSettings.php
deleted file mode 100644
index 48153f2ea8..0000000000
--- a/app/Models/SlackNotificationSettings.php
+++ /dev/null
@@ -1,59 +0,0 @@
- 'boolean',
- 'slack_webhook_url' => 'encrypted',
-
- 'deployment_success_slack_notifications' => 'boolean',
- 'deployment_failure_slack_notifications' => 'boolean',
- 'status_change_slack_notifications' => 'boolean',
- 'backup_success_slack_notifications' => 'boolean',
- 'backup_failure_slack_notifications' => 'boolean',
- 'scheduled_task_success_slack_notifications' => 'boolean',
- 'scheduled_task_failure_slack_notifications' => 'boolean',
- 'docker_cleanup_slack_notifications' => 'boolean',
- 'server_disk_usage_slack_notifications' => 'boolean',
- 'server_reachable_slack_notifications' => 'boolean',
- 'server_unreachable_slack_notifications' => 'boolean',
- ];
-
- public function team()
- {
- return $this->belongsTo(Team::class);
- }
-
- public function isEnabled()
- {
- return $this->slack_enabled;
- }
-}
diff --git a/app/Models/StandaloneClickhouse.php b/app/Models/StandaloneClickhouse.php
deleted file mode 100644
index 60198115da..0000000000
--- a/app/Models/StandaloneClickhouse.php
+++ /dev/null
@@ -1,322 +0,0 @@
- 'encrypted',
- ];
-
- protected static function booted()
- {
- static::created(function ($database) {
- LocalPersistentVolume::create([
- 'name' => 'clickhouse-data-'.$database->uuid,
- 'mount_path' => '/bitnami/clickhouse',
- 'host_path' => null,
- 'resource_id' => $database->id,
- 'resource_type' => $database->getMorphClass(),
- 'is_readonly' => true,
- ]);
- });
- static::forceDeleting(function ($database) {
- $database->persistentStorages()->delete();
- $database->scheduledBackups()->delete();
- $database->environment_variables()->delete();
- $database->tags()->detach();
- });
- static::saving(function ($database) {
- if ($database->isDirty('status')) {
- $database->forceFill(['last_online_at' => now()]);
- }
- });
- }
-
- protected function serverStatus(): Attribute
- {
- return Attribute::make(
- get: function () {
- return $this->destination->server->isFunctional();
- }
- );
- }
-
- public function isConfigurationChanged(bool $save = false)
- {
- $newConfigHash = $this->image.$this->ports_mappings;
- $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort());
- $newConfigHash = md5($newConfigHash);
- $oldConfigHash = data_get($this, 'config_hash');
- if ($oldConfigHash === null) {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- if ($oldConfigHash === $newConfigHash) {
- return false;
- } else {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- }
-
- public function isRunning()
- {
- return (bool) str($this->status)->contains('running');
- }
-
- public function isExited()
- {
- return (bool) str($this->status)->startsWith('exited');
- }
-
- public function workdir()
- {
- return database_configuration_dir()."/{$this->uuid}";
- }
-
- public function delete_configurations()
- {
- $server = data_get($this, 'destination.server');
- $workdir = $this->workdir();
- if (str($workdir)->endsWith($this->uuid)) {
- instant_remote_process(['rm -rf '.$this->workdir()], $server, false);
- }
- }
-
- public function delete_volumes(Collection $persistentStorages)
- {
- if ($persistentStorages->count() === 0) {
- return;
- }
- $server = data_get($this, 'destination.server');
- foreach ($persistentStorages as $storage) {
- instant_remote_process(["docker volume rm -f $storage->name"], $server, false);
- }
- }
-
- public function realStatus()
- {
- return $this->getRawOriginal('status');
- }
-
- public function status(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- get: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- );
- }
-
- public function tags()
- {
- return $this->morphToMany(Tag::class, 'taggable');
- }
-
- public function project()
- {
- return data_get($this, 'environment.project');
- }
-
- public function link()
- {
- if (data_get($this, 'environment.project.uuid')) {
- return route('project.database.configuration', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'database_uuid' => data_get($this, 'uuid'),
- ]);
- }
-
- return null;
- }
-
- public function isLogDrainEnabled()
- {
- return data_get($this, 'is_log_drain_enabled', false);
- }
-
- public function portsMappings(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => $value === '' ? null : $value,
- );
- }
-
- public function portsMappingsArray(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->ports_mappings)
- ? []
- : explode(',', $this->ports_mappings),
-
- );
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function databaseType(): Attribute
- {
- return new Attribute(
- get: fn () => $this->type(),
- );
- }
-
- public function type(): string
- {
- return 'standalone-clickhouse';
- }
-
- protected function internalDbUrl(): Attribute
- {
- return new Attribute(
- get: fn () => "clickhouse://{$this->clickhouse_admin_user}:{$this->clickhouse_admin_password}@{$this->uuid}:9000/{$this->clickhouse_db}",
- );
- }
-
- protected function externalDbUrl(): Attribute
- {
- return new Attribute(
- get: function () {
- if ($this->is_public && $this->public_port) {
- return "clickhouse://{$this->clickhouse_admin_user}:{$this->clickhouse_admin_password}@{$this->destination->server->getIp}:{$this->public_port}/{$this->clickhouse_db}";
- }
-
- return null;
- }
- );
- }
-
- public function environment()
- {
- return $this->belongsTo(Environment::class);
- }
-
- public function fileStorages()
- {
- return $this->morphMany(LocalFileVolume::class, 'resource');
- }
-
- public function destination()
- {
- return $this->morphTo();
- }
-
- public function environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
- }
-
- public function runtime_environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable');
- }
-
- public function persistentStorages()
- {
- return $this->morphMany(LocalPersistentVolume::class, 'resource');
- }
-
- public function scheduledBackups()
- {
- return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
- }
-
- public function getCpuMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['percent']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function getMemoryMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['used']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function isBackupSolutionAvailable()
- {
- return false;
- }
-}
diff --git a/app/Models/StandaloneDocker.php b/app/Models/StandaloneDocker.php
deleted file mode 100644
index 9db6a2d290..0000000000
--- a/app/Models/StandaloneDocker.php
+++ /dev/null
@@ -1,92 +0,0 @@
-server;
- instant_remote_process([
- "docker network inspect $newStandaloneDocker->network >/dev/null 2>&1 || docker network create --driver overlay --attachable $newStandaloneDocker->network >/dev/null",
- ], $server, false);
- $connectProxyToDockerNetworks = connectProxyToNetworks($server);
- instant_remote_process($connectProxyToDockerNetworks, $server, false);
- });
- }
-
- public function applications()
- {
- return $this->morphMany(Application::class, 'destination');
- }
-
- public function postgresqls()
- {
- return $this->morphMany(StandalonePostgresql::class, 'destination');
- }
-
- public function redis()
- {
- return $this->morphMany(StandaloneRedis::class, 'destination');
- }
-
- public function mongodbs()
- {
- return $this->morphMany(StandaloneMongodb::class, 'destination');
- }
-
- public function mysqls()
- {
- return $this->morphMany(StandaloneMysql::class, 'destination');
- }
-
- public function mariadbs()
- {
- return $this->morphMany(StandaloneMariadb::class, 'destination');
- }
-
- public function keydbs()
- {
- return $this->morphMany(StandaloneKeydb::class, 'destination');
- }
-
- public function dragonflies()
- {
- return $this->morphMany(StandaloneDragonfly::class, 'destination');
- }
-
- public function clickhouses()
- {
- return $this->morphMany(StandaloneClickhouse::class, 'destination');
- }
-
- public function server()
- {
- return $this->belongsTo(Server::class);
- }
-
- public function services()
- {
- return $this->morphMany(Service::class, 'destination');
- }
-
- public function databases()
- {
- $postgresqls = $this->postgresqls;
- $redis = $this->redis;
- $mongodbs = $this->mongodbs;
- $mysqls = $this->mysqls;
- $mariadbs = $this->mariadbs;
-
- return $postgresqls->concat($redis)->concat($mongodbs)->concat($mysqls)->concat($mariadbs);
- }
-
- public function attachedTo()
- {
- return $this->applications?->count() > 0 || $this->databases()->count() > 0;
- }
-}
diff --git a/app/Models/StandaloneDragonfly.php b/app/Models/StandaloneDragonfly.php
deleted file mode 100644
index 3c1127d8de..0000000000
--- a/app/Models/StandaloneDragonfly.php
+++ /dev/null
@@ -1,322 +0,0 @@
- 'encrypted',
- ];
-
- protected static function booted()
- {
- static::created(function ($database) {
- LocalPersistentVolume::create([
- 'name' => 'dragonfly-data-'.$database->uuid,
- 'mount_path' => '/data',
- 'host_path' => null,
- 'resource_id' => $database->id,
- 'resource_type' => $database->getMorphClass(),
- 'is_readonly' => true,
- ]);
- });
- static::forceDeleting(function ($database) {
- $database->persistentStorages()->delete();
- $database->scheduledBackups()->delete();
- $database->environment_variables()->delete();
- $database->tags()->detach();
- });
- static::saving(function ($database) {
- if ($database->isDirty('status')) {
- $database->forceFill(['last_online_at' => now()]);
- }
- });
- }
-
- protected function serverStatus(): Attribute
- {
- return Attribute::make(
- get: function () {
- return $this->destination->server->isFunctional();
- }
- );
- }
-
- public function isConfigurationChanged(bool $save = false)
- {
- $newConfigHash = $this->image.$this->ports_mappings;
- $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort());
- $newConfigHash = md5($newConfigHash);
- $oldConfigHash = data_get($this, 'config_hash');
- if ($oldConfigHash === null) {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- if ($oldConfigHash === $newConfigHash) {
- return false;
- } else {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- }
-
- public function isRunning()
- {
- return (bool) str($this->status)->contains('running');
- }
-
- public function isExited()
- {
- return (bool) str($this->status)->startsWith('exited');
- }
-
- public function workdir()
- {
- return database_configuration_dir()."/{$this->uuid}";
- }
-
- public function delete_configurations()
- {
- $server = data_get($this, 'destination.server');
- $workdir = $this->workdir();
- if (str($workdir)->endsWith($this->uuid)) {
- instant_remote_process(['rm -rf '.$this->workdir()], $server, false);
- }
- }
-
- public function delete_volumes(Collection $persistentStorages)
- {
- if ($persistentStorages->count() === 0) {
- return;
- }
- $server = data_get($this, 'destination.server');
- foreach ($persistentStorages as $storage) {
- instant_remote_process(["docker volume rm -f $storage->name"], $server, false);
- }
- }
-
- public function realStatus()
- {
- return $this->getRawOriginal('status');
- }
-
- public function status(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- get: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- );
- }
-
- public function tags()
- {
- return $this->morphToMany(Tag::class, 'taggable');
- }
-
- public function project()
- {
- return data_get($this, 'environment.project');
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function link()
- {
- if (data_get($this, 'environment.project.uuid')) {
- return route('project.database.configuration', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'database_uuid' => data_get($this, 'uuid'),
- ]);
- }
-
- return null;
- }
-
- public function isLogDrainEnabled()
- {
- return data_get($this, 'is_log_drain_enabled', false);
- }
-
- public function portsMappings(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => $value === '' ? null : $value,
- );
- }
-
- public function portsMappingsArray(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->ports_mappings)
- ? []
- : explode(',', $this->ports_mappings),
-
- );
- }
-
- public function databaseType(): Attribute
- {
- return new Attribute(
- get: fn () => $this->type(),
- );
- }
-
- public function type(): string
- {
- return 'standalone-dragonfly';
- }
-
- protected function internalDbUrl(): Attribute
- {
- return new Attribute(
- get: fn () => "redis://:{$this->dragonfly_password}@{$this->uuid}:6379/0",
- );
- }
-
- protected function externalDbUrl(): Attribute
- {
- return new Attribute(
- get: function () {
- if ($this->is_public && $this->public_port) {
- return "redis://:{$this->dragonfly_password}@{$this->destination->server->getIp}:{$this->public_port}/0";
- }
-
- return null;
- }
- );
- }
-
- public function environment()
- {
- return $this->belongsTo(Environment::class);
- }
-
- public function fileStorages()
- {
- return $this->morphMany(LocalFileVolume::class, 'resource');
- }
-
- public function destination()
- {
- return $this->morphTo();
- }
-
- public function runtime_environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable');
- }
-
- public function persistentStorages()
- {
- return $this->morphMany(LocalPersistentVolume::class, 'resource');
- }
-
- public function scheduledBackups()
- {
- return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
- }
-
- public function getCpuMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['percent']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function getMemoryMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['used']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function isBackupSolutionAvailable()
- {
- return false;
- }
-
- public function environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
- }
-}
diff --git a/app/Models/StandaloneKeydb.php b/app/Models/StandaloneKeydb.php
deleted file mode 100644
index ebf1c22e95..0000000000
--- a/app/Models/StandaloneKeydb.php
+++ /dev/null
@@ -1,322 +0,0 @@
- 'encrypted',
- ];
-
- protected static function booted()
- {
- static::created(function ($database) {
- LocalPersistentVolume::create([
- 'name' => 'keydb-data-'.$database->uuid,
- 'mount_path' => '/data',
- 'host_path' => null,
- 'resource_id' => $database->id,
- 'resource_type' => $database->getMorphClass(),
- 'is_readonly' => true,
- ]);
- });
- static::forceDeleting(function ($database) {
- $database->persistentStorages()->delete();
- $database->scheduledBackups()->delete();
- $database->environment_variables()->delete();
- $database->tags()->detach();
- });
- static::saving(function ($database) {
- if ($database->isDirty('status')) {
- $database->forceFill(['last_online_at' => now()]);
- }
- });
- }
-
- protected function serverStatus(): Attribute
- {
- return Attribute::make(
- get: function () {
- return $this->destination->server->isFunctional();
- }
- );
- }
-
- public function isConfigurationChanged(bool $save = false)
- {
- $newConfigHash = $this->image.$this->ports_mappings.$this->keydb_conf;
- $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort());
- $newConfigHash = md5($newConfigHash);
- $oldConfigHash = data_get($this, 'config_hash');
- if ($oldConfigHash === null) {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- if ($oldConfigHash === $newConfigHash) {
- return false;
- } else {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- }
-
- public function isRunning()
- {
- return (bool) str($this->status)->contains('running');
- }
-
- public function isExited()
- {
- return (bool) str($this->status)->startsWith('exited');
- }
-
- public function workdir()
- {
- return database_configuration_dir()."/{$this->uuid}";
- }
-
- public function delete_configurations()
- {
- $server = data_get($this, 'destination.server');
- $workdir = $this->workdir();
- if (str($workdir)->endsWith($this->uuid)) {
- instant_remote_process(['rm -rf '.$this->workdir()], $server, false);
- }
- }
-
- public function delete_volumes(Collection $persistentStorages)
- {
- if ($persistentStorages->count() === 0) {
- return;
- }
- $server = data_get($this, 'destination.server');
- foreach ($persistentStorages as $storage) {
- instant_remote_process(["docker volume rm -f $storage->name"], $server, false);
- }
- }
-
- public function realStatus()
- {
- return $this->getRawOriginal('status');
- }
-
- public function status(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- get: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- );
- }
-
- public function tags()
- {
- return $this->morphToMany(Tag::class, 'taggable');
- }
-
- public function project()
- {
- return data_get($this, 'environment.project');
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function link()
- {
- if (data_get($this, 'environment.project.uuid')) {
- return route('project.database.configuration', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'database_uuid' => data_get($this, 'uuid'),
- ]);
- }
-
- return null;
- }
-
- public function isLogDrainEnabled()
- {
- return data_get($this, 'is_log_drain_enabled', false);
- }
-
- public function portsMappings(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => $value === '' ? null : $value,
- );
- }
-
- public function portsMappingsArray(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->ports_mappings)
- ? []
- : explode(',', $this->ports_mappings),
-
- );
- }
-
- public function databaseType(): Attribute
- {
- return new Attribute(
- get: fn () => $this->type(),
- );
- }
-
- public function type(): string
- {
- return 'standalone-keydb';
- }
-
- protected function internalDbUrl(): Attribute
- {
- return new Attribute(
- get: fn () => "redis://:{$this->keydb_password}@{$this->uuid}:6379/0",
- );
- }
-
- protected function externalDbUrl(): Attribute
- {
- return new Attribute(
- get: function () {
- if ($this->is_public && $this->public_port) {
- return "redis://:{$this->keydb_password}@{$this->destination->server->getIp}:{$this->public_port}/0";
- }
-
- return null;
- }
- );
- }
-
- public function environment()
- {
- return $this->belongsTo(Environment::class);
- }
-
- public function fileStorages()
- {
- return $this->morphMany(LocalFileVolume::class, 'resource');
- }
-
- public function destination()
- {
- return $this->morphTo();
- }
-
- public function runtime_environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable');
- }
-
- public function persistentStorages()
- {
- return $this->morphMany(LocalPersistentVolume::class, 'resource');
- }
-
- public function scheduledBackups()
- {
- return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
- }
-
- public function getCpuMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['percent']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function getMemoryMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['used']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function isBackupSolutionAvailable()
- {
- return false;
- }
-
- public function environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
- }
-}
diff --git a/app/Models/StandaloneMariadb.php b/app/Models/StandaloneMariadb.php
deleted file mode 100644
index 004ead4d95..0000000000
--- a/app/Models/StandaloneMariadb.php
+++ /dev/null
@@ -1,322 +0,0 @@
- 'encrypted',
- ];
-
- protected static function booted()
- {
- static::created(function ($database) {
- LocalPersistentVolume::create([
- 'name' => 'mariadb-data-'.$database->uuid,
- 'mount_path' => '/var/lib/mysql',
- 'host_path' => null,
- 'resource_id' => $database->id,
- 'resource_type' => $database->getMorphClass(),
- 'is_readonly' => true,
- ]);
- });
- static::forceDeleting(function ($database) {
- $database->persistentStorages()->delete();
- $database->scheduledBackups()->delete();
- $database->environment_variables()->delete();
- $database->tags()->detach();
- });
- static::saving(function ($database) {
- if ($database->isDirty('status')) {
- $database->forceFill(['last_online_at' => now()]);
- }
- });
- }
-
- protected function serverStatus(): Attribute
- {
- return Attribute::make(
- get: function () {
- return $this->destination->server->isFunctional();
- }
- );
- }
-
- public function isConfigurationChanged(bool $save = false)
- {
- $newConfigHash = $this->image.$this->ports_mappings.$this->mariadb_conf;
- $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort());
- $newConfigHash = md5($newConfigHash);
- $oldConfigHash = data_get($this, 'config_hash');
- if ($oldConfigHash === null) {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- if ($oldConfigHash === $newConfigHash) {
- return false;
- } else {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- }
-
- public function isRunning()
- {
- return (bool) str($this->status)->contains('running');
- }
-
- public function isExited()
- {
- return (bool) str($this->status)->startsWith('exited');
- }
-
- public function workdir()
- {
- return database_configuration_dir()."/{$this->uuid}";
- }
-
- public function delete_configurations()
- {
- $server = data_get($this, 'destination.server');
- $workdir = $this->workdir();
- if (str($workdir)->endsWith($this->uuid)) {
- instant_remote_process(['rm -rf '.$this->workdir()], $server, false);
- }
- }
-
- public function delete_volumes(Collection $persistentStorages)
- {
- if ($persistentStorages->count() === 0) {
- return;
- }
- $server = data_get($this, 'destination.server');
- foreach ($persistentStorages as $storage) {
- instant_remote_process(["docker volume rm -f $storage->name"], $server, false);
- }
- }
-
- public function realStatus()
- {
- return $this->getRawOriginal('status');
- }
-
- public function status(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- get: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- );
- }
-
- public function tags()
- {
- return $this->morphToMany(Tag::class, 'taggable');
- }
-
- public function project()
- {
- return data_get($this, 'environment.project');
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function link()
- {
- if (data_get($this, 'environment.project.uuid')) {
- return route('project.database.configuration', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'database_uuid' => data_get($this, 'uuid'),
- ]);
- }
-
- return null;
- }
-
- public function isLogDrainEnabled()
- {
- return data_get($this, 'is_log_drain_enabled', false);
- }
-
- public function databaseType(): Attribute
- {
- return new Attribute(
- get: fn () => $this->type(),
- );
- }
-
- public function type(): string
- {
- return 'standalone-mariadb';
- }
-
- public function portsMappings(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => $value === '' ? null : $value,
- );
- }
-
- public function portsMappingsArray(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->ports_mappings)
- ? []
- : explode(',', $this->ports_mappings),
-
- );
- }
-
- protected function internalDbUrl(): Attribute
- {
- return new Attribute(
- get: fn () => "mysql://{$this->mariadb_user}:{$this->mariadb_password}@{$this->uuid}:3306/{$this->mariadb_database}",
- );
- }
-
- protected function externalDbUrl(): Attribute
- {
- return new Attribute(
- get: function () {
- if ($this->is_public && $this->public_port) {
- return "mysql://{$this->mariadb_user}:{$this->mariadb_password}@{$this->destination->server->getIp}:{$this->public_port}/{$this->mariadb_database}";
- }
-
- return null;
- }
- );
- }
-
- public function environment()
- {
- return $this->belongsTo(Environment::class);
- }
-
- public function fileStorages()
- {
- return $this->morphMany(LocalFileVolume::class, 'resource');
- }
-
- public function destination()
- {
- return $this->morphTo();
- }
-
- public function environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
- }
-
- public function runtime_environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable');
- }
-
- public function persistentStorages()
- {
- return $this->morphMany(LocalPersistentVolume::class, 'resource');
- }
-
- public function scheduledBackups()
- {
- return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
- }
-
- public function getCpuMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['percent']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function getMemoryMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['used']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function isBackupSolutionAvailable()
- {
- return true;
- }
-}
diff --git a/app/Models/StandaloneMongodb.php b/app/Models/StandaloneMongodb.php
deleted file mode 100644
index aba0f6123e..0000000000
--- a/app/Models/StandaloneMongodb.php
+++ /dev/null
@@ -1,342 +0,0 @@
- 'mongodb-configdb-'.$database->uuid,
- 'mount_path' => '/data/configdb',
- 'host_path' => null,
- 'resource_id' => $database->id,
- 'resource_type' => $database->getMorphClass(),
- 'is_readonly' => true,
- ]);
- LocalPersistentVolume::create([
- 'name' => 'mongodb-db-'.$database->uuid,
- 'mount_path' => '/data/db',
- 'host_path' => null,
- 'resource_id' => $database->id,
- 'resource_type' => $database->getMorphClass(),
- 'is_readonly' => true,
- ]);
- });
- static::forceDeleting(function ($database) {
- $database->persistentStorages()->delete();
- $database->scheduledBackups()->delete();
- $database->environment_variables()->delete();
- $database->tags()->detach();
- });
- static::saving(function ($database) {
- if ($database->isDirty('status')) {
- $database->forceFill(['last_online_at' => now()]);
- }
- });
- }
-
- protected function serverStatus(): Attribute
- {
- return Attribute::make(
- get: function () {
- return $this->destination->server->isFunctional();
- }
- );
- }
-
- public function isConfigurationChanged(bool $save = false)
- {
- $newConfigHash = $this->image.$this->ports_mappings.$this->mongo_conf;
- $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort());
- $newConfigHash = md5($newConfigHash);
- $oldConfigHash = data_get($this, 'config_hash');
- if ($oldConfigHash === null) {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- if ($oldConfigHash === $newConfigHash) {
- return false;
- } else {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- }
-
- public function isRunning()
- {
- return (bool) str($this->status)->contains('running');
- }
-
- public function isExited()
- {
- return (bool) str($this->status)->startsWith('exited');
- }
-
- public function workdir()
- {
- return database_configuration_dir()."/{$this->uuid}";
- }
-
- public function delete_configurations()
- {
- $server = data_get($this, 'destination.server');
- $workdir = $this->workdir();
- if (str($workdir)->endsWith($this->uuid)) {
- instant_remote_process(['rm -rf '.$this->workdir()], $server, false);
- }
- }
-
- public function delete_volumes(Collection $persistentStorages)
- {
- if ($persistentStorages->count() === 0) {
- return;
- }
- $server = data_get($this, 'destination.server');
- foreach ($persistentStorages as $storage) {
- instant_remote_process(["docker volume rm -f $storage->name"], $server, false);
- }
- }
-
- public function realStatus()
- {
- return $this->getRawOriginal('status');
- }
-
- public function status(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- get: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- );
- }
-
- public function tags()
- {
- return $this->morphToMany(Tag::class, 'taggable');
- }
-
- public function project()
- {
- return data_get($this, 'environment.project');
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function isLogDrainEnabled()
- {
- return data_get($this, 'is_log_drain_enabled', false);
- }
-
- public function link()
- {
- if (data_get($this, 'environment.project.uuid')) {
- return route('project.database.configuration', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'database_uuid' => data_get($this, 'uuid'),
- ]);
- }
-
- return null;
- }
-
- public function mongoInitdbRootPassword(): Attribute
- {
- return Attribute::make(
- get: function ($value) {
- try {
- return decrypt($value);
- } catch (\Throwable $th) {
- $this->mongo_initdb_root_password = encrypt($value);
- $this->save();
-
- return $value;
- }
- }
- );
- }
-
- public function portsMappings(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => $value === '' ? null : $value,
- );
- }
-
- public function portsMappingsArray(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->ports_mappings)
- ? []
- : explode(',', $this->ports_mappings),
-
- );
- }
-
- public function databaseType(): Attribute
- {
- return new Attribute(
- get: fn () => $this->type(),
- );
- }
-
- public function type(): string
- {
- return 'standalone-mongodb';
- }
-
- protected function internalDbUrl(): Attribute
- {
- return new Attribute(
- get: fn () => "mongodb://{$this->mongo_initdb_root_username}:{$this->mongo_initdb_root_password}@{$this->uuid}:27017/?directConnection=true",
- );
- }
-
- protected function externalDbUrl(): Attribute
- {
- return new Attribute(
- get: function () {
- if ($this->is_public && $this->public_port) {
- return "mongodb://{$this->mongo_initdb_root_username}:{$this->mongo_initdb_root_password}@{$this->destination->server->getIp}:{$this->public_port}/?directConnection=true";
- }
-
- return null;
- }
- );
- }
-
- public function environment()
- {
- return $this->belongsTo(Environment::class);
- }
-
- public function fileStorages()
- {
- return $this->morphMany(LocalFileVolume::class, 'resource');
- }
-
- public function destination()
- {
- return $this->morphTo();
- }
-
- public function runtime_environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable');
- }
-
- public function persistentStorages()
- {
- return $this->morphMany(LocalPersistentVolume::class, 'resource');
- }
-
- public function scheduledBackups()
- {
- return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
- }
-
- public function getCpuMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['percent']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function getMemoryMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['used']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function isBackupSolutionAvailable()
- {
- return true;
- }
-
- public function environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
- }
-}
diff --git a/app/Models/StandaloneMysql.php b/app/Models/StandaloneMysql.php
deleted file mode 100644
index 9ae0fdcaeb..0000000000
--- a/app/Models/StandaloneMysql.php
+++ /dev/null
@@ -1,323 +0,0 @@
- 'encrypted',
- 'mysql_root_password' => 'encrypted',
- ];
-
- protected static function booted()
- {
- static::created(function ($database) {
- LocalPersistentVolume::create([
- 'name' => 'mysql-data-'.$database->uuid,
- 'mount_path' => '/var/lib/mysql',
- 'host_path' => null,
- 'resource_id' => $database->id,
- 'resource_type' => $database->getMorphClass(),
- 'is_readonly' => true,
- ]);
- });
- static::forceDeleting(function ($database) {
- $database->persistentStorages()->delete();
- $database->scheduledBackups()->delete();
- $database->environment_variables()->delete();
- $database->tags()->detach();
- });
- static::saving(function ($database) {
- if ($database->isDirty('status')) {
- $database->forceFill(['last_online_at' => now()]);
- }
- });
- }
-
- protected function serverStatus(): Attribute
- {
- return Attribute::make(
- get: function () {
- return $this->destination->server->isFunctional();
- }
- );
- }
-
- public function isConfigurationChanged(bool $save = false)
- {
- $newConfigHash = $this->image.$this->ports_mappings.$this->mysql_conf;
- $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort());
- $newConfigHash = md5($newConfigHash);
- $oldConfigHash = data_get($this, 'config_hash');
- if ($oldConfigHash === null) {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- if ($oldConfigHash === $newConfigHash) {
- return false;
- } else {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- }
-
- public function isRunning()
- {
- return (bool) str($this->status)->contains('running');
- }
-
- public function isExited()
- {
- return (bool) str($this->status)->startsWith('exited');
- }
-
- public function workdir()
- {
- return database_configuration_dir()."/{$this->uuid}";
- }
-
- public function delete_configurations()
- {
- $server = data_get($this, 'destination.server');
- $workdir = $this->workdir();
- if (str($workdir)->endsWith($this->uuid)) {
- instant_remote_process(['rm -rf '.$this->workdir()], $server, false);
- }
- }
-
- public function delete_volumes(Collection $persistentStorages)
- {
- if ($persistentStorages->count() === 0) {
- return;
- }
- $server = data_get($this, 'destination.server');
- foreach ($persistentStorages as $storage) {
- instant_remote_process(["docker volume rm -f $storage->name"], $server, false);
- }
- }
-
- public function realStatus()
- {
- return $this->getRawOriginal('status');
- }
-
- public function status(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- get: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- );
- }
-
- public function tags()
- {
- return $this->morphToMany(Tag::class, 'taggable');
- }
-
- public function project()
- {
- return data_get($this, 'environment.project');
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function link()
- {
- if (data_get($this, 'environment.project.uuid')) {
- return route('project.database.configuration', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'database_uuid' => data_get($this, 'uuid'),
- ]);
- }
-
- return null;
- }
-
- public function databaseType(): Attribute
- {
- return new Attribute(
- get: fn () => $this->type(),
- );
- }
-
- public function type(): string
- {
- return 'standalone-mysql';
- }
-
- public function isLogDrainEnabled()
- {
- return data_get($this, 'is_log_drain_enabled', false);
- }
-
- public function portsMappings(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => $value === '' ? null : $value,
- );
- }
-
- public function portsMappingsArray(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->ports_mappings)
- ? []
- : explode(',', $this->ports_mappings),
-
- );
- }
-
- protected function internalDbUrl(): Attribute
- {
- return new Attribute(
- get: fn () => "mysql://{$this->mysql_user}:{$this->mysql_password}@{$this->uuid}:3306/{$this->mysql_database}",
- );
- }
-
- protected function externalDbUrl(): Attribute
- {
- return new Attribute(
- get: function () {
- if ($this->is_public && $this->public_port) {
- return "mysql://{$this->mysql_user}:{$this->mysql_password}@{$this->destination->server->getIp}:{$this->public_port}/{$this->mysql_database}";
- }
-
- return null;
- }
- );
- }
-
- public function environment()
- {
- return $this->belongsTo(Environment::class);
- }
-
- public function fileStorages()
- {
- return $this->morphMany(LocalFileVolume::class, 'resource');
- }
-
- public function destination()
- {
- return $this->morphTo();
- }
-
- public function runtime_environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable');
- }
-
- public function persistentStorages()
- {
- return $this->morphMany(LocalPersistentVolume::class, 'resource');
- }
-
- public function scheduledBackups()
- {
- return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
- }
-
- public function getCpuMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['percent']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function getMemoryMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['used']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function isBackupSolutionAvailable()
- {
- return true;
- }
-
- public function environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
- }
-}
diff --git a/app/Models/StandalonePostgresql.php b/app/Models/StandalonePostgresql.php
deleted file mode 100644
index dd92ae7c91..0000000000
--- a/app/Models/StandalonePostgresql.php
+++ /dev/null
@@ -1,323 +0,0 @@
- 'array',
- 'postgres_password' => 'encrypted',
- ];
-
- protected static function booted()
- {
- static::created(function ($database) {
- LocalPersistentVolume::create([
- 'name' => 'postgres-data-'.$database->uuid,
- 'mount_path' => '/var/lib/postgresql/data',
- 'host_path' => null,
- 'resource_id' => $database->id,
- 'resource_type' => $database->getMorphClass(),
- 'is_readonly' => true,
- ]);
- });
- static::forceDeleting(function ($database) {
- $database->persistentStorages()->delete();
- $database->scheduledBackups()->delete();
- $database->environment_variables()->delete();
- $database->tags()->detach();
- });
- static::saving(function ($database) {
- if ($database->isDirty('status')) {
- $database->forceFill(['last_online_at' => now()]);
- }
- });
- }
-
- public function workdir()
- {
- return database_configuration_dir()."/{$this->uuid}";
- }
-
- protected function serverStatus(): Attribute
- {
- return Attribute::make(
- get: function () {
- return $this->destination->server->isFunctional();
- }
- );
- }
-
- public function delete_configurations()
- {
- $server = data_get($this, 'destination.server');
- $workdir = $this->workdir();
- if (str($workdir)->endsWith($this->uuid)) {
- instant_remote_process(['rm -rf '.$this->workdir()], $server, false);
- }
- }
-
- public function delete_volumes(Collection $persistentStorages)
- {
- if ($persistentStorages->count() === 0) {
- return;
- }
- $server = data_get($this, 'destination.server');
- foreach ($persistentStorages as $storage) {
- instant_remote_process(["docker volume rm -f $storage->name"], $server, false);
- }
- }
-
- public function isConfigurationChanged(bool $save = false)
- {
- $newConfigHash = $this->image.$this->ports_mappings.$this->postgres_initdb_args.$this->postgres_host_auth_method;
- $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort());
- $newConfigHash = md5($newConfigHash);
- $oldConfigHash = data_get($this, 'config_hash');
- if ($oldConfigHash === null) {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- if ($oldConfigHash === $newConfigHash) {
- return false;
- } else {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- }
-
- public function isRunning()
- {
- return (bool) str($this->status)->contains('running');
- }
-
- public function isExited()
- {
- return (bool) str($this->status)->startsWith('exited');
- }
-
- public function realStatus()
- {
- return $this->getRawOriginal('status');
- }
-
- public function status(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- get: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- );
- }
-
- public function tags()
- {
- return $this->morphToMany(Tag::class, 'taggable');
- }
-
- public function project()
- {
- return data_get($this, 'environment.project');
- }
-
- public function link()
- {
- if (data_get($this, 'environment.project.uuid')) {
- return route('project.database.configuration', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'database_uuid' => data_get($this, 'uuid'),
- ]);
- }
-
- return null;
- }
-
- public function isLogDrainEnabled()
- {
- return data_get($this, 'is_log_drain_enabled', false);
- }
-
- public function portsMappings(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => $value === '' ? null : $value,
- );
- }
-
- public function portsMappingsArray(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->ports_mappings)
- ? []
- : explode(',', $this->ports_mappings),
-
- );
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function databaseType(): Attribute
- {
- return new Attribute(
- get: fn () => $this->type(),
- );
- }
-
- public function type(): string
- {
- return 'standalone-postgresql';
- }
-
- protected function internalDbUrl(): Attribute
- {
- return new Attribute(
- get: fn () => "postgres://{$this->postgres_user}:{$this->postgres_password}@{$this->uuid}:5432/{$this->postgres_db}",
- );
- }
-
- protected function externalDbUrl(): Attribute
- {
- return new Attribute(
- get: function () {
- if ($this->is_public && $this->public_port) {
- return "postgres://{$this->postgres_user}:{$this->postgres_password}@{$this->destination->server->getIp}:{$this->public_port}/{$this->postgres_db}";
- }
-
- return null;
- }
- );
- }
-
- public function environment()
- {
- return $this->belongsTo(Environment::class);
- }
-
- public function fileStorages()
- {
- return $this->morphMany(LocalFileVolume::class, 'resource');
- }
-
- public function destination()
- {
- return $this->morphTo();
- }
-
- public function runtime_environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable');
- }
-
- public function persistentStorages()
- {
- return $this->morphMany(LocalPersistentVolume::class, 'resource');
- }
-
- public function scheduledBackups()
- {
- return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
- }
-
- public function isBackupSolutionAvailable()
- {
- return true;
- }
-
- public function getCpuMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['percent']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function getMemoryMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['used']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
- }
-}
diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php
deleted file mode 100644
index 6037364fe7..0000000000
--- a/app/Models/StandaloneRedis.php
+++ /dev/null
@@ -1,373 +0,0 @@
- 'redis-data-'.$database->uuid,
- 'mount_path' => '/data',
- 'host_path' => null,
- 'resource_id' => $database->id,
- 'resource_type' => $database->getMorphClass(),
- 'is_readonly' => true,
- ]);
- });
- static::forceDeleting(function ($database) {
- $database->persistentStorages()->delete();
- $database->scheduledBackups()->delete();
- $database->environment_variables()->delete();
- $database->tags()->detach();
- });
- static::saving(function ($database) {
- if ($database->isDirty('status')) {
- $database->forceFill(['last_online_at' => now()]);
- }
- });
-
- static::retrieved(function ($database) {
- if (! $database->redis_username) {
- $database->redis_username = 'default';
- }
- });
- }
-
- protected function serverStatus(): Attribute
- {
- return Attribute::make(
- get: function () {
- return $this->destination->server->isFunctional();
- }
- );
- }
-
- public function isConfigurationChanged(bool $save = false)
- {
- $newConfigHash = $this->image.$this->ports_mappings.$this->redis_conf;
- $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort());
- $newConfigHash = md5($newConfigHash);
- $oldConfigHash = data_get($this, 'config_hash');
- if ($oldConfigHash === null) {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- if ($oldConfigHash === $newConfigHash) {
- return false;
- } else {
- if ($save) {
- $this->config_hash = $newConfigHash;
- $this->save();
- }
-
- return true;
- }
- }
-
- public function isRunning()
- {
- return (bool) str($this->status)->contains('running');
- }
-
- public function isExited()
- {
- return (bool) str($this->status)->startsWith('exited');
- }
-
- public function workdir()
- {
- return database_configuration_dir()."/{$this->uuid}";
- }
-
- public function delete_configurations()
- {
- $server = data_get($this, 'destination.server');
- $workdir = $this->workdir();
- if (str($workdir)->endsWith($this->uuid)) {
- instant_remote_process(['rm -rf '.$this->workdir()], $server, false);
- }
- }
-
- public function delete_volumes(Collection $persistentStorages)
- {
- if ($persistentStorages->count() === 0) {
- return;
- }
- $server = data_get($this, 'destination.server');
- foreach ($persistentStorages as $storage) {
- instant_remote_process(["docker volume rm -f $storage->name"], $server, false);
- }
- }
-
- public function realStatus()
- {
- return $this->getRawOriginal('status');
- }
-
- public function status(): Attribute
- {
- return Attribute::make(
- set: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- get: function ($value) {
- if (str($value)->contains('(')) {
- $status = str($value)->before('(')->trim()->value();
- $health = str($value)->after('(')->before(')')->trim()->value() ?? 'unhealthy';
- } elseif (str($value)->contains(':')) {
- $status = str($value)->before(':')->trim()->value();
- $health = str($value)->after(':')->trim()->value() ?? 'unhealthy';
- } else {
- $status = $value;
- $health = 'unhealthy';
- }
-
- return "$status:$health";
- },
- );
- }
-
- public function tags()
- {
- return $this->morphToMany(Tag::class, 'taggable');
- }
-
- public function project()
- {
- return data_get($this, 'environment.project');
- }
-
- public function team()
- {
- return data_get($this, 'environment.project.team');
- }
-
- public function link()
- {
- if (data_get($this, 'environment.project.uuid')) {
- return route('project.database.configuration', [
- 'project_uuid' => data_get($this, 'environment.project.uuid'),
- 'environment_uuid' => data_get($this, 'environment.uuid'),
- 'database_uuid' => data_get($this, 'uuid'),
- ]);
- }
-
- return null;
- }
-
- public function isLogDrainEnabled()
- {
- return data_get($this, 'is_log_drain_enabled', false);
- }
-
- public function portsMappings(): Attribute
- {
- return Attribute::make(
- set: fn ($value) => $value === '' ? null : $value,
- );
- }
-
- public function portsMappingsArray(): Attribute
- {
- return Attribute::make(
- get: fn () => is_null($this->ports_mappings)
- ? []
- : explode(',', $this->ports_mappings),
-
- );
- }
-
- public function type(): string
- {
- return 'standalone-redis';
- }
-
- public function databaseType(): Attribute
- {
- return new Attribute(
- get: fn () => $this->type(),
- );
- }
-
- protected function internalDbUrl(): Attribute
- {
- return new Attribute(
- get: function () {
- $redis_version = $this->getRedisVersion();
- $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : '';
-
- return "redis://{$username_part}{$this->redis_password}@{$this->uuid}:6379/0";
- }
- );
- }
-
- protected function externalDbUrl(): Attribute
- {
- return new Attribute(
- get: function () {
- if ($this->is_public && $this->public_port) {
- $redis_version = $this->getRedisVersion();
- $username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : '';
-
- return "redis://{$username_part}{$this->redis_password}@{$this->destination->server->getIp}:{$this->public_port}/0";
- }
-
- return null;
- }
- );
- }
-
- public function getRedisVersion()
- {
- $image_parts = explode(':', $this->image);
-
- return $image_parts[1] ?? '0.0';
- }
-
- public function environment()
- {
- return $this->belongsTo(Environment::class);
- }
-
- public function fileStorages()
- {
- return $this->morphMany(LocalFileVolume::class, 'resource');
- }
-
- public function destination()
- {
- return $this->morphTo();
- }
-
- public function runtime_environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable');
- }
-
- public function persistentStorages()
- {
- return $this->morphMany(LocalPersistentVolume::class, 'resource');
- }
-
- public function scheduledBackups()
- {
- return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
- }
-
- public function getCpuMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['percent']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function getMemoryMetrics(int $mins = 5)
- {
- $server = $this->destination->server;
- $container_name = $this->uuid;
- $from = now()->subMinutes($mins)->toIso8601ZuluString();
- $metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
- if (str($metrics)->contains('error')) {
- $error = json_decode($metrics, true);
- $error = data_get($error, 'error', 'Something is not okay, are you okay?');
- if ($error === 'Unauthorized') {
- $error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
- }
- throw new \Exception($error);
- }
- $metrics = json_decode($metrics, true);
- $parsedCollection = collect($metrics)->map(function ($metric) {
- return [(int) $metric['time'], (float) $metric['used']];
- });
-
- return $parsedCollection->toArray();
- }
-
- public function isBackupSolutionAvailable()
- {
- return false;
- }
-
- public function redisPassword(): Attribute
- {
- return new Attribute(
- get: function () {
- $password = $this->runtime_environment_variables()->where('key', 'REDIS_PASSWORD')->first();
- if (! $password) {
- return null;
- }
-
- return $password->value;
- },
-
- );
- }
-
- public function redisUsername(): Attribute
- {
- return new Attribute(
- get: function () {
- $username = $this->runtime_environment_variables()->where('key', 'REDIS_USERNAME')->first();
- if (! $username) {
- $this->runtime_environment_variables()->create([
- 'key' => 'REDIS_USERNAME',
- 'value' => 'default',
- ]);
-
- return 'default';
- }
-
- return $username->value;
- }
- );
- }
-
- public function environment_variables()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
- }
-}
diff --git a/app/Models/Subscription.php b/app/Models/Subscription.php
deleted file mode 100644
index 1bd84a6647..0000000000
--- a/app/Models/Subscription.php
+++ /dev/null
@@ -1,48 +0,0 @@
-belongsTo(Team::class);
- }
-
- public function type()
- {
- if (isStripe()) {
- if (! $this->stripe_plan_id) {
- return 'zero';
- }
- $subscription = Subscription::where('id', $this->id)->first();
- if (! $subscription) {
- return null;
- }
- $subscriptionPlanId = data_get($subscription, 'stripe_plan_id');
- if (! $subscriptionPlanId) {
- return null;
- }
- $subscriptionInvoicePaid = data_get($subscription, 'stripe_invoice_paid');
- if (! $subscriptionInvoicePaid) {
- return null;
- }
- $subscriptionConfigs = collect(config('subscription'));
- $stripePlanId = null;
- $subscriptionConfigs->map(function ($value, $key) use ($subscriptionPlanId, &$stripePlanId) {
- if ($value === $subscriptionPlanId) {
- $stripePlanId = $key;
- }
- })->first();
- if ($stripePlanId) {
- return str($stripePlanId)->after('stripe_price_id_')->before('_')->lower();
- }
- }
-
- return 'zero';
- }
-}
diff --git a/app/Models/SwarmDocker.php b/app/Models/SwarmDocker.php
deleted file mode 100644
index e0fe349c71..0000000000
--- a/app/Models/SwarmDocker.php
+++ /dev/null
@@ -1,82 +0,0 @@
-morphMany(Application::class, 'destination');
- }
-
- public function postgresqls()
- {
- return $this->morphMany(StandalonePostgresql::class, 'destination');
- }
-
- public function redis()
- {
- return $this->morphMany(StandaloneRedis::class, 'destination');
- }
-
- public function keydbs()
- {
- return $this->morphMany(StandaloneKeydb::class, 'destination');
- }
-
- public function dragonflies()
- {
- return $this->morphMany(StandaloneDragonfly::class, 'destination');
- }
-
- public function clickhouses()
- {
- return $this->morphMany(StandaloneClickhouse::class, 'destination');
- }
-
- public function mongodbs()
- {
- return $this->morphMany(StandaloneMongodb::class, 'destination');
- }
-
- public function mysqls()
- {
- return $this->morphMany(StandaloneMysql::class, 'destination');
- }
-
- public function mariadbs()
- {
- return $this->morphMany(StandaloneMariadb::class, 'destination');
- }
-
- public function server()
- {
- return $this->belongsTo(Server::class);
- }
-
- public function services()
- {
- return $this->morphMany(Service::class, 'destination');
- }
-
- public function databases()
- {
- $postgresqls = $this->postgresqls;
- $redis = $this->redis;
- $mongodbs = $this->mongodbs;
- $mysqls = $this->mysqls;
- $mariadbs = $this->mariadbs;
- $keydbs = $this->keydbs;
- $dragonflies = $this->dragonflies;
- $clickhouses = $this->clickhouses;
-
- return $postgresqls->concat($redis)->concat($mongodbs)->concat($mysqls)->concat($mariadbs)->concat($keydbs)->concat($dragonflies)->concat($clickhouses);
- }
-
- public function attachedTo()
- {
- return $this->applications?->count() > 0 || $this->databases()->count() > 0;
- }
-}
diff --git a/app/Models/Tag.php b/app/Models/Tag.php
deleted file mode 100644
index a64c994a3a..0000000000
--- a/app/Models/Tag.php
+++ /dev/null
@@ -1,33 +0,0 @@
- strtolower($value),
- set: fn ($value) => strtolower($value)
- );
- }
-
- public static function ownedByCurrentTeam()
- {
- return Tag::whereTeamId(currentTeam()->id)->orderBy('name');
- }
-
- public function applications()
- {
- return $this->morphedByMany(Application::class, 'taggable');
- }
-
- public function services()
- {
- return $this->morphedByMany(Service::class, 'taggable');
- }
-}
diff --git a/app/Models/Team.php b/app/Models/Team.php
deleted file mode 100644
index 6796b22ad7..0000000000
--- a/app/Models/Team.php
+++ /dev/null
@@ -1,306 +0,0 @@
- ['type' => 'integer', 'description' => 'The unique identifier of the team.'],
- 'name' => ['type' => 'string', 'description' => 'The name of the team.'],
- 'description' => ['type' => 'string', 'description' => 'The description of the team.'],
- 'personal_team' => ['type' => 'boolean', 'description' => 'Whether the team is personal or not.'],
- 'created_at' => ['type' => 'string', 'description' => 'The date and time the team was created.'],
- 'updated_at' => ['type' => 'string', 'description' => 'The date and time the team was last updated.'],
- 'show_boarding' => ['type' => 'boolean', 'description' => 'Whether to show the boarding screen or not.'],
- 'custom_server_limit' => ['type' => 'string', 'description' => 'The custom server limit.'],
- '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, SendsPushover, SendsSlack
-{
- use HasNotificationSettings, Notifiable;
-
- protected $guarded = [];
-
- protected $casts = [
- 'personal_team' => 'boolean',
- ];
-
- protected static function booted()
- {
- static::created(function ($team) {
- $team->emailNotificationSettings()->create();
- $team->discordNotificationSettings()->create();
- $team->slackNotificationSettings()->create();
- $team->telegramNotificationSettings()->create();
- $team->pushoverNotificationSettings()->create();
- });
-
- static::saving(function ($team) {
- if (auth()->user()?->isMember()) {
- throw new \Exception('You are not allowed to update this team.');
- }
- });
-
- static::deleting(function ($team) {
- $keys = $team->privateKeys;
- foreach ($keys as $key) {
- $key->delete();
- }
- $sources = $team->sources();
- foreach ($sources as $source) {
- $source->delete();
- }
- $tags = Tag::whereTeamId($team->id)->get();
- foreach ($tags as $tag) {
- $tag->delete();
- }
- $shared_variables = $team->environment_variables();
- foreach ($shared_variables as $shared_variable) {
- $shared_variable->delete();
- }
- $s3s = $team->s3s;
- foreach ($s3s as $s3) {
- $s3->delete();
- }
- });
- }
-
- public static function serverLimitReached()
- {
- $serverLimit = Team::serverLimit();
- $team = currentTeam();
- $servers = $team->servers->count();
-
- return $servers >= $serverLimit;
- }
-
- public function subscriptionPastOverDue()
- {
- if (isCloud()) {
- return $this->subscription?->stripe_past_due;
- }
-
- return false;
- }
-
- public function serverOverflow()
- {
- if ($this->serverLimit() < $this->servers->count()) {
- return true;
- }
-
- return false;
- }
-
- public static function serverLimit()
- {
- if (currentTeam()->id === 0 && isDev()) {
- return 9999999;
- }
- $team = Team::find(currentTeam()->id);
- if (! $team) {
- return 0;
- }
-
- return data_get($team, 'limits', 0);
- }
-
- public function limits(): Attribute
- {
- return Attribute::make(
- get: function () {
- if (config('constants.coolify.self_hosted') || $this->id === 0) {
- return 999999999999;
- }
-
- return $this->custom_server_limit ?? 2;
- }
- );
- }
-
- public function routeNotificationForDiscord()
- {
- return data_get($this, 'discord_webhook_url', null);
- }
-
- public function routeNotificationForTelegram()
- {
- return [
- 'token' => data_get($this, 'telegram_token', null),
- 'chat_id' => data_get($this, 'telegram_chat_id', null),
- ];
- }
-
- public function routeNotificationForSlack()
- {
- return data_get($this, 'slack_webhook_url', null);
- }
-
- public function routeNotificationForPushover()
- {
- return [
- 'user' => data_get($this, 'pushover_user_key', null),
- 'token' => data_get($this, 'pushover_api_token', null),
- ];
- }
-
- public function getRecipients($notification)
- {
- $recipients = data_get($notification, 'emails', null);
- if (is_null($recipients)) {
- return $this->members()->pluck('email')->toArray();
- }
-
- return explode(',', $recipients);
- }
-
- public function isAnyNotificationEnabled()
- {
- if (isCloud()) {
- return true;
- }
-
- return $this->getNotificationSettings('email')?->isEnabled() ||
- $this->getNotificationSettings('discord')?->isEnabled() ||
- $this->getNotificationSettings('slack')?->isEnabled() ||
- $this->getNotificationSettings('telegram')?->isEnabled() ||
- $this->getNotificationSettings('pushover')?->isEnabled();
- }
-
- public function subscriptionEnded()
- {
- $this->subscription->update([
- 'stripe_subscription_id' => null,
- 'stripe_plan_id' => null,
- 'stripe_cancel_at_period_end' => false,
- 'stripe_invoice_paid' => false,
- 'stripe_trial_already_ended' => false,
- 'stripe_past_due' => false,
- ]);
- foreach ($this->servers as $server) {
- $server->settings()->update([
- 'is_usable' => false,
- 'is_reachable' => false,
- ]);
- ServerReachabilityChanged::dispatch($server);
- }
- }
-
- public function environment_variables()
- {
- return $this->hasMany(SharedEnvironmentVariable::class)->whereNull('project_id')->whereNull('environment_id');
- }
-
- public function members()
- {
- return $this->belongsToMany(User::class, 'team_user', 'team_id', 'user_id')->withPivot('role');
- }
-
- public function subscription()
- {
- return $this->hasOne(Subscription::class);
- }
-
- public function applications()
- {
- return $this->hasManyThrough(Application::class, Project::class);
- }
-
- public function invitations()
- {
- return $this->hasMany(TeamInvitation::class);
- }
-
- public function isEmpty()
- {
- if ($this->projects()->count() === 0 && $this->servers()->count() === 0 && $this->privateKeys()->count() === 0 && $this->sources()->count() === 0) {
- return true;
- }
-
- return false;
- }
-
- public function projects()
- {
- return $this->hasMany(Project::class);
- }
-
- public function servers()
- {
- return $this->hasMany(Server::class);
- }
-
- public function privateKeys()
- {
- return $this->hasMany(PrivateKey::class);
- }
-
- public function sources()
- {
- $sources = collect([]);
- $github_apps = GithubApp::where(function ($query) {
- $query->where(function ($q) {
- $q->where('team_id', $this->id)
- ->orWhere('is_system_wide', true);
- })->where('is_public', false);
- })->get();
-
- $gitlab_apps = GitlabApp::where(function ($query) {
- $query->where(function ($q) {
- $q->where('team_id', $this->id)
- ->orWhere('is_system_wide', true);
- })->where('is_public', false);
- })->get();
-
- return $sources->merge($github_apps)->merge($gitlab_apps);
- }
-
- public function s3s()
- {
- return $this->hasMany(S3Storage::class)->where('is_usable', true);
- }
-
- public function emailNotificationSettings()
- {
- return $this->hasOne(EmailNotificationSettings::class);
- }
-
- public function discordNotificationSettings()
- {
- return $this->hasOne(DiscordNotificationSettings::class);
- }
-
- public function telegramNotificationSettings()
- {
- return $this->hasOne(TelegramNotificationSettings::class);
- }
-
- public function slackNotificationSettings()
- {
- return $this->hasOne(SlackNotificationSettings::class);
- }
-
- public function pushoverNotificationSettings()
- {
- return $this->hasOne(PushoverNotificationSettings::class);
- }
-}
diff --git a/app/Models/TeamInvitation.php b/app/Models/TeamInvitation.php
deleted file mode 100644
index bc1a90d586..0000000000
--- a/app/Models/TeamInvitation.php
+++ /dev/null
@@ -1,40 +0,0 @@
-belongsTo(Team::class);
- }
-
- public static function ownedByCurrentTeam()
- {
- return TeamInvitation::whereTeamId(currentTeam()->id);
- }
-
- public function isValid()
- {
- $createdAt = $this->created_at;
- $diff = $createdAt->diffInDays(now());
- if ($diff <= config('constants.invitation.link.expiration_days')) {
- return true;
- } else {
- $this->delete();
-
- return false;
- }
- }
-}
diff --git a/app/Models/TelegramNotificationSettings.php b/app/Models/TelegramNotificationSettings.php
deleted file mode 100644
index 78bd841bd4..0000000000
--- a/app/Models/TelegramNotificationSettings.php
+++ /dev/null
@@ -1,85 +0,0 @@
- 'boolean',
- 'telegram_token' => 'encrypted',
- 'telegram_chat_id' => 'encrypted',
-
- 'deployment_success_telegram_notifications' => 'boolean',
- 'deployment_failure_telegram_notifications' => 'boolean',
- 'status_change_telegram_notifications' => 'boolean',
- 'backup_success_telegram_notifications' => 'boolean',
- 'backup_failure_telegram_notifications' => 'boolean',
- 'scheduled_task_success_telegram_notifications' => 'boolean',
- 'scheduled_task_failure_telegram_notifications' => 'boolean',
- 'docker_cleanup_telegram_notifications' => 'boolean',
- 'server_disk_usage_telegram_notifications' => 'boolean',
- 'server_reachable_telegram_notifications' => 'boolean',
- 'server_unreachable_telegram_notifications' => 'boolean',
-
- 'telegram_notifications_deployment_success_thread_id' => 'encrypted',
- 'telegram_notifications_deployment_failure_thread_id' => 'encrypted',
- 'telegram_notifications_status_change_thread_id' => 'encrypted',
- 'telegram_notifications_backup_success_thread_id' => 'encrypted',
- 'telegram_notifications_backup_failure_thread_id' => 'encrypted',
- 'telegram_notifications_scheduled_task_success_thread_id' => 'encrypted',
- 'telegram_notifications_scheduled_task_failure_thread_id' => 'encrypted',
- 'telegram_notifications_docker_cleanup_thread_id' => 'encrypted',
- 'telegram_notifications_server_disk_usage_thread_id' => 'encrypted',
- 'telegram_notifications_server_reachable_thread_id' => 'encrypted',
- 'telegram_notifications_server_unreachable_thread_id' => 'encrypted',
- ];
-
- public function team()
- {
- return $this->belongsTo(Team::class);
- }
-
- public function isEnabled()
- {
- return $this->telegram_enabled;
- }
-}
diff --git a/app/Models/User.php b/app/Models/User.php
deleted file mode 100644
index 7c23631c36..0000000000
--- a/app/Models/User.php
+++ /dev/null
@@ -1,224 +0,0 @@
- ['type' => 'integer', 'description' => 'The user identifier in the database.'],
- 'name' => ['type' => 'string', 'description' => 'The user name.'],
- 'email' => ['type' => 'string', 'description' => 'The user email.'],
- 'email_verified_at' => ['type' => 'string', 'description' => 'The date when the user email was verified.'],
- 'created_at' => ['type' => 'string', 'description' => 'The date when the user was created.'],
- 'updated_at' => ['type' => 'string', 'description' => 'The date when the user was updated.'],
- 'two_factor_confirmed_at' => ['type' => 'string', 'description' => 'The date when the user two factor was confirmed.'],
- 'force_password_reset' => ['type' => 'boolean', 'description' => 'The flag to force the user to reset the password.'],
- 'marketing_emails' => ['type' => 'boolean', 'description' => 'The flag to receive marketing emails.'],
- ],
-)]
-class User extends Authenticatable implements SendsEmail
-{
- use HasApiTokens, HasFactory, Notifiable, TwoFactorAuthenticatable;
-
- protected $guarded = [];
-
- protected $hidden = [
- 'password',
- 'remember_token',
- 'two_factor_recovery_codes',
- 'two_factor_secret',
- ];
-
- protected $casts = [
- 'email_verified_at' => 'datetime',
- 'force_password_reset' => 'boolean',
- 'show_boarding' => 'boolean',
- ];
-
- protected static function boot()
- {
- parent::boot();
- static::created(function (User $user) {
- $team = [
- 'name' => $user->name."'s Team",
- 'personal_team' => true,
- 'show_boarding' => true,
- ];
- if ($user->id === 0) {
- $team['id'] = 0;
- $team['name'] = 'Root Team';
- }
- $new_team = Team::create($team);
- $user->teams()->attach($new_team, ['role' => 'owner']);
- });
- }
-
- public function recreate_personal_team()
- {
- $team = [
- 'name' => $this->name."'s Team",
- 'personal_team' => true,
- 'show_boarding' => true,
- ];
- if ($this->id === 0) {
- $team['id'] = 0;
- $team['name'] = 'Root Team';
- }
- $new_team = Team::create($team);
- $this->teams()->attach($new_team, ['role' => 'owner']);
-
- return $new_team;
- }
-
- public function createToken(string $name, array $abilities = ['*'], ?DateTimeInterface $expiresAt = null)
- {
- $plainTextToken = sprintf(
- '%s%s%s',
- config('sanctum.token_prefix', ''),
- $tokenEntropy = Str::random(40),
- hash('crc32b', $tokenEntropy)
- );
-
- $token = $this->tokens()->create([
- 'name' => $name,
- 'token' => hash('sha256', $plainTextToken),
- 'abilities' => $abilities,
- 'expires_at' => $expiresAt,
- 'team_id' => session('currentTeam')->id,
- ]);
-
- return new NewAccessToken($token, $token->getKey().'|'.$plainTextToken);
- }
-
- public function teams()
- {
- return $this->belongsToMany(Team::class)->withPivot('role');
- }
-
- public function getRecipients($notification)
- {
- return $this->email;
- }
-
- public function sendVerificationEmail()
- {
- $mail = new MailMessage;
- $url = Url::temporarySignedRoute(
- 'verify.verify',
- Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
- [
- 'id' => $this->getKey(),
- 'hash' => sha1($this->getEmailForVerification()),
- ]
- );
- $mail->view('emails.email-verification', [
- 'url' => $url,
- ]);
- $mail->subject('Coolify: Verify your email.');
- send_user_an_email($mail, $this->email);
- }
-
- public function sendPasswordResetNotification($token): void
- {
- $this?->notify(new TransactionalEmailsResetPassword($token));
- }
-
- public function isAdmin()
- {
- return $this->role() === 'admin' || $this->role() === 'owner';
- }
-
- public function isOwner()
- {
- return $this->role() === 'owner';
- }
-
- public function isMember()
- {
- return $this->role() === 'member';
- }
-
- public function isAdminFromSession()
- {
- if (Auth::id() === 0) {
- return true;
- }
- $teams = $this->teams()->get();
-
- $is_part_of_root_team = $teams->where('id', 0)->first();
- $is_admin_of_root_team = $is_part_of_root_team &&
- ($is_part_of_root_team->pivot->role === 'admin' || $is_part_of_root_team->pivot->role === 'owner');
-
- if ($is_part_of_root_team && $is_admin_of_root_team) {
- return true;
- }
- $team = $teams->where('id', session('currentTeam')->id)->first();
- $role = data_get($team, 'pivot.role');
-
- return $role === 'admin' || $role === 'owner';
- }
-
- public function isInstanceAdmin()
- {
- $found_root_team = Auth::user()->teams->filter(function ($team) {
- if ($team->id == 0) {
- if (! Auth::user()->isAdmin()) {
- return false;
- }
-
- return true;
- }
-
- return false;
- });
-
- return $found_root_team->count() > 0;
- }
-
- public function currentTeam()
- {
- return Cache::remember('team:'.Auth::id(), 3600, function () {
- if (is_null(data_get(session('currentTeam'), 'id')) && Auth::user()->teams->count() > 0) {
- return Auth::user()->teams[0];
- }
-
- return Team::find(session('currentTeam')->id);
- });
- }
-
- public function otherTeams()
- {
- return Auth::user()->teams->filter(function ($team) {
- return $team->id != currentTeam()->id;
- });
- }
-
- public function role()
- {
- if (data_get($this, 'pivot')) {
- return $this->pivot->role;
- }
- $user = Auth::user()->teams->where('id', currentTeam()->id)->first();
-
- return data_get($user, 'pivot.role');
- }
-}
diff --git a/app/Models/Webhook.php b/app/Models/Webhook.php
deleted file mode 100644
index 8e2b629558..0000000000
--- a/app/Models/Webhook.php
+++ /dev/null
@@ -1,15 +0,0 @@
- 'string',
- 'payload' => 'encrypted',
- ];
-}
diff --git a/app/Notifications/Application/DeploymentFailed.php b/app/Notifications/Application/DeploymentFailed.php
deleted file mode 100644
index dec361e782..0000000000
--- a/app/Notifications/Application/DeploymentFailed.php
+++ /dev/null
@@ -1,188 +0,0 @@
-onQueue('high');
- $this->application = $application;
- $this->deployment_uuid = $deployment_uuid;
- $this->preview = $preview;
- $this->application_name = data_get($application, 'name');
- $this->project_uuid = data_get($application, 'environment.project.uuid');
- $this->environment_uuid = data_get($application, 'environment.uuid');
- $this->environment_name = data_get($application, 'environment.name');
- $this->fqdn = data_get($application, 'fqdn');
- if (str($this->fqdn)->explode(',')->count() > 1) {
- $this->fqdn = str($this->fqdn)->explode(',')->first();
- }
- $this->deployment_url = base_url()."/project/{$this->project_uuid}/environment/{$this->environment_uuid}/application/{$this->application->uuid}/deployment/{$this->deployment_uuid}";
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('deployment_failure');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $pull_request_id = data_get($this->preview, 'pull_request_id', 0);
- $fqdn = $this->fqdn;
- if ($pull_request_id === 0) {
- $mail->subject('Coolify: Deployment failed of '.$this->application_name.'.');
- } else {
- $fqdn = $this->preview->fqdn;
- $mail->subject('Coolify: Deployment failed of pull request #'.$this->preview->pull_request_id.' of '.$this->application_name.'.');
- }
- $mail->view('emails.application-deployment-failed', [
- 'name' => $this->application_name,
- 'fqdn' => $fqdn,
- 'deployment_url' => $this->deployment_url,
- 'pull_request_id' => data_get($this->preview, 'pull_request_id', 0),
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- if ($this->preview) {
- $message = new DiscordMessage(
- title: ':cross_mark: Deployment failed',
- description: 'Pull request: '.$this->preview->pull_request_id,
- color: DiscordMessage::errorColor(),
- isCritical: true,
- );
-
- $message->addField('Project', data_get($this->application, 'environment.project.name'), true);
- $message->addField('Environment', $this->environment_name, true);
- $message->addField('Name', $this->application_name, true);
-
- $message->addField('Deployment Logs', '[Link]('.$this->deployment_url.')');
- if ($this->fqdn) {
- $message->addField('Domain', $this->fqdn, true);
- }
- } else {
- if ($this->fqdn) {
- $description = '[Open application]('.$this->fqdn.')';
- } else {
- $description = '';
- }
- $message = new DiscordMessage(
- title: ':cross_mark: Deployment failed',
- description: $description,
- color: DiscordMessage::errorColor(),
- isCritical: true,
- );
-
- $message->addField('Project', data_get($this->application, 'environment.project.name'), true);
- $message->addField('Environment', $this->environment_name, true);
- $message->addField('Name', $this->application_name, true);
-
- $message->addField('Deployment Logs', '[Link]('.$this->deployment_url.')');
- }
-
- return $message;
- }
-
- public function toTelegram(): array
- {
- if ($this->preview) {
- $message = 'Coolify: Pull request #'.$this->preview->pull_request_id.' of '.$this->application_name.' ('.$this->preview->fqdn.') deployment failed: ';
- } else {
- $message = 'Coolify: Deployment failed of '.$this->application_name.' ('.$this->fqdn.'): ';
- }
- $buttons[] = [
- 'text' => 'Deployment logs',
- 'url' => $this->deployment_url,
- ];
-
- return [
- 'message' => $message,
- 'buttons' => [
- ...$buttons,
- ],
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- if ($this->preview) {
- $title = "Pull request #{$this->preview->pull_request_id} deployment failed";
- $message = "Pull request deployment failed for {$this->application_name}";
- } else {
- $title = 'Deployment failed';
- $message = "Deployment failed for {$this->application_name}";
- }
-
- $buttons[] = [
- 'text' => 'Deployment logs',
- 'url' => $this->deployment_url,
- ];
-
- return new PushoverMessage(
- title: $title,
- level: 'error',
- message: $message,
- buttons: [
- ...$buttons,
- ],
- );
- }
-
- public function toSlack(): SlackMessage
- {
- if ($this->preview) {
- $title = "Pull request #{$this->preview->pull_request_id} deployment failed";
- $description = "Pull request deployment failed for {$this->application_name}";
- if ($this->preview->fqdn) {
- $description .= "\nPreview URL: {$this->preview->fqdn}";
- }
- } else {
- $title = 'Deployment failed';
- $description = "Deployment failed for {$this->application_name}";
- if ($this->fqdn) {
- $description .= "\nApplication URL: {$this->fqdn}";
- }
- }
-
- $description .= "\n\n*Project:* ".data_get($this->application, 'environment.project.name');
- $description .= "\n*Environment:* {$this->environment_name}";
- $description .= "\n*<{$this->deployment_url}|Deployment Logs>*";
-
- return new SlackMessage(
- title: $title,
- description: $description,
- color: SlackMessage::errorColor()
- );
- }
-}
diff --git a/app/Notifications/Application/DeploymentSuccess.php b/app/Notifications/Application/DeploymentSuccess.php
deleted file mode 100644
index 9b59d9162a..0000000000
--- a/app/Notifications/Application/DeploymentSuccess.php
+++ /dev/null
@@ -1,208 +0,0 @@
-onQueue('high');
- $this->application = $application;
- $this->deployment_uuid = $deployment_uuid;
- $this->preview = $preview;
- $this->application_name = data_get($application, 'name');
- $this->project_uuid = data_get($application, 'environment.project.uuid');
- $this->environment_uuid = data_get($application, 'environment.uuid');
- $this->environment_name = data_get($application, 'environment.name');
- $this->fqdn = data_get($application, 'fqdn');
- if (str($this->fqdn)->explode(',')->count() > 1) {
- $this->fqdn = str($this->fqdn)->explode(',')->first();
- }
- $this->deployment_url = base_url()."/project/{$this->project_uuid}/environment/{$this->environment_uuid}/application/{$this->application->uuid}/deployment/{$this->deployment_uuid}";
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('deployment_success');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $pull_request_id = data_get($this->preview, 'pull_request_id', 0);
- $fqdn = $this->fqdn;
- if ($pull_request_id === 0) {
- $mail->subject("Coolify: New version is deployed of {$this->application_name}");
- } else {
- $fqdn = $this->preview->fqdn;
- $mail->subject("Coolify: Pull request #{$pull_request_id} of {$this->application_name} deployed successfully");
- }
- $mail->view('emails.application-deployment-success', [
- 'name' => $this->application_name,
- 'fqdn' => $fqdn,
- 'deployment_url' => $this->deployment_url,
- 'pull_request_id' => $pull_request_id,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- if ($this->preview) {
- $message = new DiscordMessage(
- title: ':white_check_mark: Preview deployment successful',
- description: 'Pull request: '.$this->preview->pull_request_id,
- color: DiscordMessage::successColor(),
- );
-
- if ($this->preview->fqdn) {
- $message->addField('Application', '[Link]('.$this->preview->fqdn.')');
- }
-
- $message->addField('Project', data_get($this->application, 'environment.project.name'), true);
- $message->addField('Environment', $this->environment_name, true);
- $message->addField('Name', $this->application_name, true);
- $message->addField('Deployment logs', '[Link]('.$this->deployment_url.')');
- } else {
- if ($this->fqdn) {
- $description = '[Open application]('.$this->fqdn.')';
- } else {
- $description = '';
- }
- $message = new DiscordMessage(
- title: ':white_check_mark: New version successfully deployed',
- description: $description,
- color: DiscordMessage::successColor(),
- );
- $message->addField('Project', data_get($this->application, 'environment.project.name'), true);
- $message->addField('Environment', $this->environment_name, true);
- $message->addField('Name', $this->application_name, true);
-
- $message->addField('Deployment logs', '[Link]('.$this->deployment_url.')');
- }
-
- return $message;
- }
-
- public function toTelegram(): array
- {
- if ($this->preview) {
- $message = 'Coolify: New PR'.$this->preview->pull_request_id.' version successfully deployed of '.$this->application_name.'';
- if ($this->preview->fqdn) {
- $buttons[] = [
- 'text' => 'Open Application',
- 'url' => $this->preview->fqdn,
- ];
- }
- } else {
- $message = '✅ New version successfully deployed of '.$this->application_name.'';
- if ($this->fqdn) {
- $buttons[] = [
- 'text' => 'Open Application',
- 'url' => $this->fqdn,
- ];
- }
- }
- $buttons[] = [
- 'text' => 'Deployment logs',
- 'url' => $this->deployment_url,
- ];
-
- return [
- 'message' => $message,
- 'buttons' => [
- ...$buttons,
- ],
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- if ($this->preview) {
- $title = "Pull request #{$this->preview->pull_request_id} successfully deployed";
- $message = 'New PR'.$this->preview->pull_request_id.' version successfully deployed of '.$this->application_name.'';
- if ($this->preview->fqdn) {
- $buttons[] = [
- 'text' => 'Open Application',
- 'url' => $this->preview->fqdn,
- ];
- }
- } else {
- $title = 'New version successfully deployed';
- $message = 'New version successfully deployed of '.$this->application_name.'';
- if ($this->fqdn) {
- $buttons[] = [
- 'text' => 'Open Application',
- 'url' => $this->fqdn,
- ];
- }
- }
- $buttons[] = [
- 'text' => 'Deployment logs',
- 'url' => $this->deployment_url,
- ];
-
- return new PushoverMessage(
- title: $title,
- level: 'success',
- message: $message,
- buttons: [
- ...$buttons,
- ],
- );
- }
-
- public function toSlack(): SlackMessage
- {
- if ($this->preview) {
- $title = "Pull request #{$this->preview->pull_request_id} successfully deployed";
- $description = "New version successfully deployed for {$this->application_name}";
- if ($this->preview->fqdn) {
- $description .= "\nPreview URL: {$this->preview->fqdn}";
- }
- } else {
- $title = 'New version successfully deployed';
- $description = "New version successfully deployed for {$this->application_name}";
- if ($this->fqdn) {
- $description .= "\nApplication URL: {$this->fqdn}";
- }
- }
-
- $description .= "\n\n*Project:* ".data_get($this->application, 'environment.project.name');
- $description .= "\n*Environment:* {$this->environment_name}";
- $description .= "\n*<{$this->deployment_url}|Deployment Logs>*";
-
- return new SlackMessage(
- title: $title,
- description: $description,
- color: SlackMessage::successColor()
- );
- }
-}
diff --git a/app/Notifications/Application/StatusChanged.php b/app/Notifications/Application/StatusChanged.php
deleted file mode 100644
index fab5487ef4..0000000000
--- a/app/Notifications/Application/StatusChanged.php
+++ /dev/null
@@ -1,116 +0,0 @@
-onQueue('high');
- $this->resource_name = data_get($resource, 'name');
- $this->project_uuid = data_get($resource, 'environment.project.uuid');
- $this->environment_uuid = data_get($resource, 'environment.uuid');
- $this->environment_name = data_get($resource, 'environment.name');
- $this->fqdn = data_get($resource, 'fqdn', null);
- if (str($this->fqdn)->explode(',')->count() > 1) {
- $this->fqdn = str($this->fqdn)->explode(',')->first();
- }
- $this->resource_url = base_url()."/project/{$this->project_uuid}/environment/{$this->environment_uuid}/application/{$this->resource->uuid}";
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('status_change');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $fqdn = $this->fqdn;
- $mail->subject("Coolify: {$this->resource_name} has been stopped");
- $mail->view('emails.application-status-changes', [
- 'name' => $this->resource_name,
- 'fqdn' => $fqdn,
- 'resource_url' => $this->resource_url,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- return new DiscordMessage(
- title: ':cross_mark: Application stopped',
- description: '[Open Application in Coolify]('.$this->resource_url.')',
- color: DiscordMessage::errorColor(),
- isCritical: true,
- );
- }
-
- public function toTelegram(): array
- {
- $message = 'Coolify: '.$this->resource_name.' has been stopped.';
-
- return [
- 'message' => $message,
- 'buttons' => [
- [
- 'text' => 'Open Application in Coolify',
- 'url' => $this->resource_url,
- ],
- ],
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- $message = $this->resource_name.' has been stopped.';
-
- return new PushoverMessage(
- title: 'Application stopped',
- level: 'error',
- message: $message,
- buttons: [
- [
- 'text' => 'Open Application in Coolify',
- 'url' => $this->resource_url,
- ],
- ],
- );
- }
-
- public function toSlack(): SlackMessage
- {
- $title = 'Application stopped';
- $description = "{$this->resource_name} has been stopped";
-
- $description .= "\n\n*Project:* ".data_get($this->resource, 'environment.project.name');
- $description .= "\n*Environment:* {$this->environment_name}";
- $description .= "\n*Application URL:* {$this->resource_url}";
-
- return new SlackMessage(
- title: $title,
- description: $description,
- color: SlackMessage::errorColor()
- );
- }
-}
diff --git a/app/Notifications/Channels/DiscordChannel.php b/app/Notifications/Channels/DiscordChannel.php
deleted file mode 100644
index 362006d8ec..0000000000
--- a/app/Notifications/Channels/DiscordChannel.php
+++ /dev/null
@@ -1,25 +0,0 @@
-toDiscord();
-
- $discordSettings = $notifiable->discordNotificationSettings;
-
- if (! $discordSettings || ! $discordSettings->isEnabled() || ! $discordSettings->discord_webhook_url) {
- return;
- }
-
- SendMessageToDiscordJob::dispatch($message, $discordSettings->discord_webhook_url);
- }
-}
diff --git a/app/Notifications/Channels/EmailChannel.php b/app/Notifications/Channels/EmailChannel.php
deleted file mode 100644
index 215fae4ea8..0000000000
--- a/app/Notifications/Channels/EmailChannel.php
+++ /dev/null
@@ -1,90 +0,0 @@
-bootConfigs($notifiable);
- $recipients = $notifiable->getRecipients($notification);
- if (count($recipients) === 0) {
- throw new Exception('No email recipients found');
- }
-
- $mailMessage = $notification->toMail($notifiable);
- Mail::send(
- [],
- [],
- fn (Message $message) => $message
- ->to($recipients)
- ->subject($mailMessage->subject)
- ->html((string) $mailMessage->render())
- );
- } catch (Exception $e) {
- $error = $e->getMessage();
- if ($error === 'No email settings found.') {
- throw $e;
- }
- $message = "EmailChannel error: {$e->getMessage()}. Failed to send email to:";
- if (isset($recipients)) {
- $message .= implode(', ', $recipients);
- }
- if (isset($mailMessage)) {
- $message .= " with subject: {$mailMessage->subject}";
- }
- send_internal_notification($message);
- throw $e;
- }
- }
-
- private function bootConfigs($notifiable): void
- {
- $emailSettings = $notifiable->emailNotificationSettings;
-
- if ($emailSettings->use_instance_email_settings) {
- $type = set_transanctional_email_settings();
- if (blank($type)) {
- throw new Exception('No email settings found.');
- }
-
- return;
- }
-
- config()->set('mail.from.address', $emailSettings->smtp_from_address ?? 'test@example.com');
- config()->set('mail.from.name', $emailSettings->smtp_from_name ?? 'Test');
-
- if ($emailSettings->resend_enabled) {
- config()->set('mail.default', 'resend');
- config()->set('resend.api_key', $emailSettings->resend_api_key);
- }
-
- if ($emailSettings->smtp_enabled) {
- $encryption = match (strtolower($emailSettings->smtp_encryption)) {
- 'starttls' => null,
- 'tls' => 'tls',
- 'none' => null,
- default => null,
- };
-
- config()->set('mail.default', 'smtp');
- config()->set('mail.mailers.smtp', [
- 'transport' => 'smtp',
- 'host' => $emailSettings->smtp_host,
- 'port' => $emailSettings->smtp_port,
- 'encryption' => $encryption,
- 'username' => $emailSettings->smtp_username,
- 'password' => $emailSettings->smtp_password,
- 'timeout' => $emailSettings->smtp_timeout,
- 'local_domain' => null,
- 'auto_tls' => $emailSettings->smtp_encryption === 'none' ? '0' : '', // If encryption is "none", it will not try to upgrade to TLS via StartTLS to make sure it is unencrypted.
- ]);
- }
- }
-}
diff --git a/app/Notifications/Channels/PushoverChannel.php b/app/Notifications/Channels/PushoverChannel.php
deleted file mode 100644
index 3d3728d01f..0000000000
--- a/app/Notifications/Channels/PushoverChannel.php
+++ /dev/null
@@ -1,21 +0,0 @@
-toPushover();
- $pushoverSettings = $notifiable->pushoverNotificationSettings;
-
- if (! $pushoverSettings || ! $pushoverSettings->isEnabled() || ! $pushoverSettings->pushover_user_key || ! $pushoverSettings->pushover_api_token) {
- return;
- }
-
- SendMessageToPushoverJob::dispatch($message, $pushoverSettings->pushover_api_token, $pushoverSettings->pushover_user_key);
- }
-}
diff --git a/app/Notifications/Channels/SendsDiscord.php b/app/Notifications/Channels/SendsDiscord.php
deleted file mode 100644
index fdaa9fc60e..0000000000
--- a/app/Notifications/Channels/SendsDiscord.php
+++ /dev/null
@@ -1,8 +0,0 @@
-toSlack();
- $slackSettings = $notifiable->slackNotificationSettings;
-
- if (! $slackSettings || ! $slackSettings->isEnabled() || ! $slackSettings->slack_webhook_url) {
- return;
- }
-
- SendMessageToSlackJob::dispatch($message, $slackSettings->slack_webhook_url);
- }
-}
diff --git a/app/Notifications/Channels/TelegramChannel.php b/app/Notifications/Channels/TelegramChannel.php
deleted file mode 100644
index ea4ab71715..0000000000
--- a/app/Notifications/Channels/TelegramChannel.php
+++ /dev/null
@@ -1,47 +0,0 @@
-toTelegram($notifiable);
- $settings = $notifiable->telegramNotificationSettings;
-
- $message = data_get($data, 'message');
- $buttons = data_get($data, 'buttons', []);
- $telegramToken = $settings->telegram_token;
- $chatId = $settings->telegram_chat_id;
-
- $threadId = match (get_class($notification)) {
- \App\Notifications\Application\DeploymentSuccess::class => $settings->telegram_notifications_deployment_success_thread_id,
- \App\Notifications\Application\DeploymentFailed::class => $settings->telegram_notifications_deployment_failure_thread_id,
- \App\Notifications\Application\StatusChanged::class,
- \App\Notifications\Container\ContainerRestarted::class,
- \App\Notifications\Container\ContainerStopped::class => $settings->telegram_notifications_status_change_thread_id,
-
- \App\Notifications\Database\BackupSuccess::class => $settings->telegram_notifications_backup_success_thread_id,
- \App\Notifications\Database\BackupFailed::class => $settings->telegram_notifications_backup_failure_thread_id,
-
- \App\Notifications\ScheduledTask\TaskSuccess::class => $settings->telegram_notifications_scheduled_task_success_thread_id,
- \App\Notifications\ScheduledTask\TaskFailed::class => $settings->telegram_notifications_scheduled_task_failure_thread_id,
-
- \App\Notifications\Server\DockerCleanupSuccess::class => $settings->telegram_notifications_docker_cleanup_success_thread_id,
- \App\Notifications\Server\DockerCleanupFailed::class => $settings->telegram_notifications_docker_cleanup_failure_thread_id,
- \App\Notifications\Server\HighDiskUsage::class => $settings->telegram_notifications_server_disk_usage_thread_id,
- \App\Notifications\Server\Unreachable::class => $settings->telegram_notifications_server_unreachable_thread_id,
- \App\Notifications\Server\Reachable::class => $settings->telegram_notifications_server_reachable_thread_id,
-
- default => null,
- };
-
- if (! $telegramToken || ! $chatId || ! $message) {
- return;
- }
-
- SendMessageToTelegramJob::dispatch($message, $buttons, $telegramToken, $chatId, $threadId);
- }
-}
diff --git a/app/Notifications/Channels/TransactionalEmailChannel.php b/app/Notifications/Channels/TransactionalEmailChannel.php
deleted file mode 100644
index 114d1f6eda..0000000000
--- a/app/Notifications/Channels/TransactionalEmailChannel.php
+++ /dev/null
@@ -1,42 +0,0 @@
-email;
- if (! $email) {
- return;
- }
- $this->bootConfigs();
- $mailMessage = $notification->toMail($notifiable);
- Mail::send(
- [],
- [],
- fn (Message $message) => $message
- ->to($email)
- ->subject($mailMessage->subject)
- ->html((string) $mailMessage->render())
- );
- }
-
- private function bootConfigs(): void
- {
- $type = set_transanctional_email_settings();
- if (blank($type)) {
- throw new Exception('No email settings found.');
- }
- }
-}
diff --git a/app/Notifications/Container/ContainerRestarted.php b/app/Notifications/Container/ContainerRestarted.php
deleted file mode 100644
index f6ae694819..0000000000
--- a/app/Notifications/Container/ContainerRestarted.php
+++ /dev/null
@@ -1,105 +0,0 @@
-onQueue('high');
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('status_change');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}");
- $mail->view('emails.container-restarted', [
- 'containerName' => $this->name,
- 'serverName' => $this->server->name,
- 'url' => $this->url,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- $message = new DiscordMessage(
- title: ':warning: Resource restarted',
- description: "{$this->name} has been restarted automatically on {$this->server->name}.",
- color: DiscordMessage::infoColor(),
- );
-
- if ($this->url) {
- $message->addField('Resource', '[Link]('.$this->url.')');
- }
-
- return $message;
- }
-
- public function toTelegram(): array
- {
- $message = "Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}";
- $payload = [
- 'message' => $message,
- ];
- if ($this->url) {
- $payload['buttons'] = [
- [
- [
- 'text' => 'Check Proxy in Coolify',
- 'url' => $this->url,
- ],
- ],
- ];
- }
-
- return $payload;
- }
-
- public function toPushover(): PushoverMessage
- {
- $buttons = [];
- if ($this->url) {
- $buttons[] = [
- 'text' => 'Check Proxy in Coolify',
- 'url' => $this->url,
- ];
- }
-
- return new PushoverMessage(
- title: 'Resource restarted',
- level: 'warning',
- message: "A resource ({$this->name}) has been restarted automatically on {$this->server->name}",
- buttons: $buttons,
- );
- }
-
- public function toSlack(): SlackMessage
- {
- $title = 'Resource restarted';
- $description = "A resource ({$this->name}) has been restarted automatically on {$this->server->name}";
-
- if ($this->url) {
- $description .= "\n*Resource URL:* {$this->url}";
- }
-
- return new SlackMessage(
- title: $title,
- description: $description,
- color: SlackMessage::warningColor()
- );
- }
-}
diff --git a/app/Notifications/Container/ContainerStopped.php b/app/Notifications/Container/ContainerStopped.php
deleted file mode 100644
index fc9410a851..0000000000
--- a/app/Notifications/Container/ContainerStopped.php
+++ /dev/null
@@ -1,105 +0,0 @@
-onQueue('high');
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('status_change');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: A resource has been stopped unexpectedly on {$this->server->name}");
- $mail->view('emails.container-stopped', [
- 'containerName' => $this->name,
- 'serverName' => $this->server->name,
- 'url' => $this->url,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- $message = new DiscordMessage(
- title: ':cross_mark: Resource stopped',
- description: "{$this->name} has been stopped unexpectedly on {$this->server->name}.",
- color: DiscordMessage::errorColor(),
- );
-
- if ($this->url) {
- $message->addField('Resource', '[Link]('.$this->url.')');
- }
-
- return $message;
- }
-
- public function toTelegram(): array
- {
- $message = "Coolify: A resource ($this->name) has been stopped unexpectedly on {$this->server->name}";
- $payload = [
- 'message' => $message,
- ];
- if ($this->url) {
- $payload['buttons'] = [
- [
- [
- 'text' => 'Open Application in Coolify',
- 'url' => $this->url,
- ],
- ],
- ];
- }
-
- return $payload;
- }
-
- public function toPushover(): PushoverMessage
- {
- $buttons = [];
- if ($this->url) {
- $buttons[] = [
- 'text' => 'Open Application in Coolify',
- 'url' => $this->url,
- ];
- }
-
- return new PushoverMessage(
- title: 'Resource stopped',
- level: 'error',
- message: "A resource ({$this->name}) has been stopped unexpectedly on {$this->server->name}",
- buttons: $buttons,
- );
- }
-
- public function toSlack(): SlackMessage
- {
- $title = 'Resource stopped';
- $description = "A resource ({$this->name}) has been stopped unexpectedly on {$this->server->name}";
-
- if ($this->url) {
- $description .= "\n*Resource URL:* {$this->url}";
- }
-
- return new SlackMessage(
- title: $title,
- description: $description,
- color: SlackMessage::errorColor()
- );
- }
-}
diff --git a/app/Notifications/CustomEmailNotification.php b/app/Notifications/CustomEmailNotification.php
deleted file mode 100644
index c3c89b30f4..0000000000
--- a/app/Notifications/CustomEmailNotification.php
+++ /dev/null
@@ -1,18 +0,0 @@
-onQueue('high');
- $this->name = $database->name;
- $this->frequency = $backup->frequency;
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('backup_failure');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: [ACTION REQUIRED] Database Backup FAILED for {$this->database->name}");
- $mail->view('emails.backup-failed', [
- 'name' => $this->name,
- 'database_name' => $this->database_name,
- 'frequency' => $this->frequency,
- 'output' => $this->output,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- $message = new DiscordMessage(
- title: ':cross_mark: Database backup failed',
- description: "Database backup for {$this->name} (db:{$this->database_name}) has FAILED.",
- color: DiscordMessage::errorColor(),
- isCritical: true,
- );
-
- $message->addField('Frequency', $this->frequency, true);
- $message->addField('Output', $this->output);
-
- return $message;
- }
-
- public function toTelegram(): array
- {
- $message = "Coolify: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was FAILED.\n\nReason:\n{$this->output}";
-
- return [
- 'message' => $message,
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- return new PushoverMessage(
- title: 'Database backup failed',
- level: 'error',
- message: "Database backup for {$this->name} (db:{$this->database_name}) was FAILEDFrequency: {$this->frequency} .Reason: {$this->output}",
- );
- }
-
- public function toSlack(): SlackMessage
- {
- $title = 'Database backup failed';
- $description = "Database backup for {$this->name} (db:{$this->database_name}) has FAILED.";
-
- $description .= "\n\n*Frequency:* {$this->frequency}";
- $description .= "\n\n*Error Output:* {$this->output}";
-
- return new SlackMessage(
- title: $title,
- description: $description,
- color: SlackMessage::errorColor()
- );
- }
-}
diff --git a/app/Notifications/Database/BackupSuccess.php b/app/Notifications/Database/BackupSuccess.php
deleted file mode 100644
index 78bcfafe35..0000000000
--- a/app/Notifications/Database/BackupSuccess.php
+++ /dev/null
@@ -1,88 +0,0 @@
-onQueue('high');
-
- $this->name = $database->name;
- $this->frequency = $backup->frequency;
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('backup_success');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: Backup successfully done for {$this->database->name}");
- $mail->view('emails.backup-success', [
- 'name' => $this->name,
- 'database_name' => $this->database_name,
- 'frequency' => $this->frequency,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- $message = new DiscordMessage(
- title: ':white_check_mark: Database backup successful',
- description: "Database backup for {$this->name} (db:{$this->database_name}) was successful.",
- color: DiscordMessage::successColor(),
- );
-
- $message->addField('Frequency', $this->frequency, true);
-
- return $message;
- }
-
- public function toTelegram(): array
- {
- $message = "Coolify: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was successful.";
-
- return [
- 'message' => $message,
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- return new PushoverMessage(
- title: 'Database backup successful',
- level: 'success',
- message: "Database backup for {$this->name} (db:{$this->database_name}) was successful.Frequency: {$this->frequency}.",
- );
- }
-
- public function toSlack(): SlackMessage
- {
- $title = 'Database backup successful';
- $description = "Database backup for {$this->name} (db:{$this->database_name}) was successful.";
-
- $description .= "\n\n*Frequency:* {$this->frequency}";
-
- return new SlackMessage(
- title: $title,
- description: $description,
- color: SlackMessage::successColor()
- );
- }
-}
diff --git a/app/Notifications/Dto/DiscordMessage.php b/app/Notifications/Dto/DiscordMessage.php
deleted file mode 100644
index 278bfd1b69..0000000000
--- a/app/Notifications/Dto/DiscordMessage.php
+++ /dev/null
@@ -1,83 +0,0 @@
-fields[] = [
- 'name' => $name,
- 'value' => $value,
- 'inline' => $inline,
- ];
-
- return $this;
- }
-
- public function toPayload(): array
- {
- $footerText = 'Coolify v'.config('constants.coolify.version');
- if (isCloud()) {
- $footerText = 'Coolify Cloud';
- }
- $payload = [
- 'embeds' => [
- [
- 'title' => $this->title,
- 'description' => $this->description,
- 'color' => $this->color,
- 'fields' => $this->addTimestampToFields($this->fields),
- 'footer' => [
- 'text' => $footerText,
- ],
- ],
- ],
- ];
- if ($this->isCritical) {
- $payload['content'] = '@here';
- }
-
- return $payload;
- }
-
- private function addTimestampToFields(array $fields): array
- {
- $fields[] = [
- 'name' => 'Time',
- 'value' => 'timestamp.':R>',
- 'inline' => true,
- ];
-
- return $fields;
- }
-}
diff --git a/app/Notifications/Dto/PushoverMessage.php b/app/Notifications/Dto/PushoverMessage.php
deleted file mode 100644
index abf6f1b7ac..0000000000
--- a/app/Notifications/Dto/PushoverMessage.php
+++ /dev/null
@@ -1,50 +0,0 @@
-level) {
- 'info' => 'ℹ️',
- 'error' => '❌',
- 'success' => '✅ ',
- 'warning' => '⚠️',
- };
- }
-
- public function toPayload(string $token, string $user): array
- {
- $levelIcon = $this->getLevelIcon();
- $payload = [
- 'token' => $token,
- 'user' => $user,
- 'title' => "{$levelIcon} {$this->title}",
- 'message' => $this->message,
- 'html' => 1,
- ];
-
- foreach ($this->buttons as $button) {
- $buttonUrl = data_get($button, 'url');
- $text = data_get($button, 'text', 'Click here');
- if ($buttonUrl && str_contains($buttonUrl, 'http://localhost')) {
- $buttonUrl = str_replace('http://localhost', config('app.url'), $buttonUrl);
- }
- $payload['message'] .= " ".$text.' ';
- }
-
- Log::info('Pushover message', $payload);
-
- return $payload;
- }
-}
diff --git a/app/Notifications/Dto/SlackMessage.php b/app/Notifications/Dto/SlackMessage.php
deleted file mode 100644
index 879bf65472..0000000000
--- a/app/Notifications/Dto/SlackMessage.php
+++ /dev/null
@@ -1,32 +0,0 @@
-onQueue('high');
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('general');
- }
-
- public function toDiscord(): DiscordMessage
- {
- return new DiscordMessage(
- title: 'Coolify: General Notification',
- description: $this->message,
- color: DiscordMessage::infoColor(),
- );
- }
-
- public function toTelegram(): array
- {
- return [
- 'message' => $this->message,
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- return new PushoverMessage(
- title: 'General Notification',
- level: 'info',
- message: $this->message,
- );
- }
-
- public function toSlack(): SlackMessage
- {
- return new SlackMessage(
- title: 'Coolify: General Notification',
- description: $this->message,
- color: SlackMessage::infoColor(),
- );
- }
-}
diff --git a/app/Notifications/ScheduledTask/TaskFailed.php b/app/Notifications/ScheduledTask/TaskFailed.php
deleted file mode 100644
index eb4fc7e79f..0000000000
--- a/app/Notifications/ScheduledTask/TaskFailed.php
+++ /dev/null
@@ -1,117 +0,0 @@
-onQueue('high');
- if ($task->application) {
- $this->url = $task->application->taskLink($task->uuid);
- } elseif ($task->service) {
- $this->url = $task->service->taskLink($task->uuid);
- }
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('scheduled_task_failure');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: [ACTION REQUIRED] Scheduled task ({$this->task->name}) failed.");
- $mail->view('emails.scheduled-task-failed', [
- 'task' => $this->task,
- 'url' => $this->url,
- 'output' => $this->output,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- $message = new DiscordMessage(
- title: ':cross_mark: Scheduled task failed',
- description: "Scheduled task ({$this->task->name}) failed.",
- color: DiscordMessage::errorColor(),
- );
-
- if ($this->url) {
- $message->addField('Scheduled task', '[Link]('.$this->url.')');
- }
-
- return $message;
- }
-
- public function toTelegram(): array
- {
- $message = "Coolify: Scheduled task ({$this->task->name}) failed with output: {$this->output}";
- if ($this->url) {
- $buttons[] = [
- 'text' => 'Open task in Coolify',
- 'url' => (string) $this->url,
- ];
- }
-
- return [
- 'message' => $message,
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- $message = "Scheduled task ({$this->task->name}) failed ";
-
- if ($this->output) {
- $message .= "Error Output: {$this->output}";
- }
-
- $buttons = [];
- if ($this->url) {
- $buttons[] = [
- 'text' => 'Open task in Coolify',
- 'url' => (string) $this->url,
- ];
- }
-
- return new PushoverMessage(
- title: 'Scheduled task failed',
- level: 'error',
- message: $message,
- buttons: $buttons,
- );
- }
-
- public function toSlack(): SlackMessage
- {
- $title = 'Scheduled task failed';
- $description = "Scheduled task ({$this->task->name}) failed.";
-
- if ($this->output) {
- $description .= "\n\n*Error Output:* {$this->output}";
- }
-
- if ($this->url) {
- $description .= "\n\n*Task URL:* {$this->url}";
- }
-
- return new SlackMessage(
- title: $title,
- description: $description,
- color: SlackMessage::errorColor()
- );
- }
-}
diff --git a/app/Notifications/ScheduledTask/TaskSuccess.php b/app/Notifications/ScheduledTask/TaskSuccess.php
deleted file mode 100644
index c45784db24..0000000000
--- a/app/Notifications/ScheduledTask/TaskSuccess.php
+++ /dev/null
@@ -1,108 +0,0 @@
-onQueue('high');
- if ($task->application) {
- $this->url = $task->application->taskLink($task->uuid);
- } elseif ($task->service) {
- $this->url = $task->service->taskLink($task->uuid);
- }
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('scheduled_task_success');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: Scheduled task ({$this->task->name}) succeeded.");
- $mail->view('emails.scheduled-task-success', [
- 'task' => $this->task,
- 'url' => $this->url,
- 'output' => $this->output,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- $message = new DiscordMessage(
- title: ':white_check_mark: Scheduled task succeeded',
- description: "Scheduled task ({$this->task->name}) succeeded.",
- color: DiscordMessage::successColor(),
- );
-
- if ($this->url) {
- $message->addField('Scheduled task', '[Link]('.$this->url.')');
- }
-
- return $message;
- }
-
- public function toTelegram(): array
- {
- $message = "Coolify: Scheduled task ({$this->task->name}) succeeded.";
- if ($this->url) {
- $buttons[] = [
- 'text' => 'Open task in Coolify',
- 'url' => (string) $this->url,
- ];
- }
-
- return [
- 'message' => $message,
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- $message = "Coolify: Scheduled task ({$this->task->name}) succeeded.";
- $buttons = [];
- if ($this->url) {
- $buttons[] = [
- 'text' => 'Open task in Coolify',
- 'url' => (string) $this->url,
- ];
- }
-
- return new PushoverMessage(
- title: 'Scheduled task succeeded',
- level: 'success',
- message: $message,
- buttons: $buttons,
- );
- }
-
- public function toSlack(): SlackMessage
- {
- $title = 'Scheduled task succeeded';
- $description = "Scheduled task ({$this->task->name}) succeeded.";
-
- if ($this->url) {
- $description .= "\n\n*Task URL:* {$this->url}";
- }
-
- return new SlackMessage(
- title: $title,
- description: $description,
- color: SlackMessage::successColor()
- );
- }
-}
diff --git a/app/Notifications/Server/DockerCleanupFailed.php b/app/Notifications/Server/DockerCleanupFailed.php
deleted file mode 100644
index 0291eed19d..0000000000
--- a/app/Notifications/Server/DockerCleanupFailed.php
+++ /dev/null
@@ -1,69 +0,0 @@
-onQueue('high');
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('docker_cleanup_failure');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: [ACTION REQUIRED] Docker cleanup job failed on {$this->server->name}");
- $mail->view('emails.docker-cleanup-failed', [
- 'name' => $this->server->name,
- 'text' => $this->message,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- return new DiscordMessage(
- title: ':cross_mark: Coolify: [ACTION REQUIRED] Docker cleanup job failed on '.$this->server->name,
- description: $this->message,
- color: DiscordMessage::errorColor(),
- );
- }
-
- public function toTelegram(): array
- {
- return [
- 'message' => "Coolify: [ACTION REQUIRED] Docker cleanup job failed on {$this->server->name}!\n\n{$this->message}",
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- return new PushoverMessage(
- title: 'Docker cleanup job failed',
- level: 'error',
- message: "[ACTION REQUIRED] Docker cleanup job failed on {$this->server->name}!\n\n{$this->message}",
- );
- }
-
- public function toSlack(): SlackMessage
- {
- return new SlackMessage(
- title: 'Coolify: [ACTION REQUIRED] Docker cleanup job failed',
- description: "Docker cleanup job failed on '{$this->server->name}'!\n\n{$this->message}",
- color: SlackMessage::errorColor()
- );
- }
-}
diff --git a/app/Notifications/Server/DockerCleanupSuccess.php b/app/Notifications/Server/DockerCleanupSuccess.php
deleted file mode 100644
index 1a652d1890..0000000000
--- a/app/Notifications/Server/DockerCleanupSuccess.php
+++ /dev/null
@@ -1,69 +0,0 @@
-onQueue('high');
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('docker_cleanup_success');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: Docker cleanup job succeeded on {$this->server->name}");
- $mail->view('emails.docker-cleanup-success', [
- 'name' => $this->server->name,
- 'text' => $this->message,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- return new DiscordMessage(
- title: ':white_check_mark: Coolify: Docker cleanup job succeeded on '.$this->server->name,
- description: $this->message,
- color: DiscordMessage::successColor(),
- );
- }
-
- public function toTelegram(): array
- {
- return [
- 'message' => "Coolify: Docker cleanup job succeeded on {$this->server->name}!\n\n{$this->message}",
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- return new PushoverMessage(
- title: 'Docker cleanup job succeeded',
- level: 'success',
- message: "Docker cleanup job succeeded on {$this->server->name}!\n\n{$this->message}",
- );
- }
-
- public function toSlack(): SlackMessage
- {
- return new SlackMessage(
- title: 'Coolify: Docker cleanup job succeeded',
- description: "Docker cleanup job succeeded on '{$this->server->name}'!\n\n{$this->message}",
- color: SlackMessage::successColor()
- );
- }
-}
diff --git a/app/Notifications/Server/ForceDisabled.php b/app/Notifications/Server/ForceDisabled.php
deleted file mode 100644
index 7a1f7bcbf7..0000000000
--- a/app/Notifications/Server/ForceDisabled.php
+++ /dev/null
@@ -1,77 +0,0 @@
-onQueue('high');
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('server_force_disabled');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: Server ({$this->server->name}) disabled because it is not paid!");
- $mail->view('emails.server-force-disabled', [
- 'name' => $this->server->name,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- $message = new DiscordMessage(
- title: ':cross_mark: Server disabled',
- description: "Server ({$this->server->name}) disabled because it is not paid!",
- color: DiscordMessage::errorColor(),
- );
-
- $message->addField('Please update your subscription to enable the server again!', '[Link](https://app.coolify.io/subscriptions)');
-
- return $message;
- }
-
- public function toTelegram(): array
- {
- return [
- 'message' => "Coolify: Server ({$this->server->name}) disabled because it is not paid!\n All automations and integrations are stopped.\nPlease update your subscription to enable the server again [here](https://app.coolify.io/subscriptions).",
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- return new PushoverMessage(
- title: 'Server disabled',
- level: 'error',
- message: "Server ({$this->server->name}) disabled because it is not paid!\n All automations and integrations are stopped. Please update your subscription to enable the server again [here](https://app.coolify.io/subscriptions).",
- );
- }
-
- public function toSlack(): SlackMessage
- {
- $title = 'Server disabled';
- $description = "Server ({$this->server->name}) disabled because it is not paid!\n";
- $description .= "All automations and integrations are stopped.\n\n";
- $description .= 'Please update your subscription to enable the server again: https://app.coolify.io/subscriptions';
-
- return new SlackMessage(
- title: $title,
- description: $description,
- color: SlackMessage::errorColor()
- );
- }
-}
diff --git a/app/Notifications/Server/ForceEnabled.php b/app/Notifications/Server/ForceEnabled.php
deleted file mode 100644
index 36dad3c60f..0000000000
--- a/app/Notifications/Server/ForceEnabled.php
+++ /dev/null
@@ -1,68 +0,0 @@
-onQueue('high');
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('server_force_enabled');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: Server ({$this->server->name}) enabled again!");
- $mail->view('emails.server-force-enabled', [
- 'name' => $this->server->name,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- return new DiscordMessage(
- title: ':white_check_mark: Server enabled',
- description: "Server '{$this->server->name}' enabled again!",
- color: DiscordMessage::successColor(),
- );
- }
-
- public function toTelegram(): array
- {
- return [
- 'message' => "Coolify: Server ({$this->server->name}) enabled again!",
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- return new PushoverMessage(
- title: 'Server enabled',
- level: 'success',
- message: "Server ({$this->server->name}) enabled again!",
- );
- }
-
- public function toSlack(): SlackMessage
- {
- return new SlackMessage(
- title: 'Server enabled',
- description: "Server '{$this->server->name}' enabled again!",
- color: SlackMessage::successColor()
- );
- }
-}
diff --git a/app/Notifications/Server/HighDiskUsage.php b/app/Notifications/Server/HighDiskUsage.php
deleted file mode 100644
index 983e6d81e7..0000000000
--- a/app/Notifications/Server/HighDiskUsage.php
+++ /dev/null
@@ -1,91 +0,0 @@
-onQueue('high');
- }
-
- public function via(object $notifiable): array
- {
- return $notifiable->getEnabledChannels('server_disk_usage');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: Server ({$this->server->name}) high disk usage detected!");
- $mail->view('emails.high-disk-usage', [
- 'name' => $this->server->name,
- 'disk_usage' => $this->disk_usage,
- 'threshold' => $this->server_disk_usage_notification_threshold,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- $message = new DiscordMessage(
- title: ':cross_mark: High disk usage detected',
- description: "Server '{$this->server->name}' high disk usage detected!",
- color: DiscordMessage::errorColor(),
- isCritical: true,
- );
-
- $message->addField('Disk usage', "{$this->disk_usage}%", true);
- $message->addField('Threshold', "{$this->server_disk_usage_notification_threshold}%", true);
- $message->addField('What to do?', '[Link](https://coolify.io/docs/knowledge-base/server/automated-cleanup)', true);
- $message->addField('Change Settings', '[Threshold]('.base_url().'/server/'.$this->server->uuid.'#advanced) | [Notification]('.base_url().'/notifications/discord)');
-
- return $message;
- }
-
- public function toTelegram(): array
- {
- return [
- 'message' => "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->server_disk_usage_notification_threshold}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup.",
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- return new PushoverMessage(
- title: 'High disk usage detected',
- level: 'warning',
- message: "Server '{$this->server->name}' high disk usage detected!Disk usage: {$this->disk_usage}%.Threshold: {$this->server_disk_usage_notification_threshold}%. Please cleanup your disk to prevent data-loss.",
- buttons: [
- 'Change settings' => base_url().'/server/'.$this->server->uuid.'#advanced',
- 'Tips for cleanup' => 'https://coolify.io/docs/knowledge-base/server/automated-cleanup',
- ],
- );
- }
-
- public function toSlack(): SlackMessage
- {
- $description = "Server '{$this->server->name}' high disk usage detected!\n";
- $description .= "Disk usage: {$this->disk_usage}%\n";
- $description .= "Threshold: {$this->server_disk_usage_notification_threshold}%\n\n";
- $description .= "Please cleanup your disk to prevent data-loss.\n";
- $description .= "Tips for cleanup: https://coolify.io/docs/knowledge-base/server/automated-cleanup\n";
- $description .= "Change settings:\n";
- $description .= '- Threshold: '.base_url().'/server/'.$this->server->uuid."#advanced\n";
- $description .= '- Notifications: '.base_url().'/notifications/slack';
-
- return new SlackMessage(
- title: 'High disk usage detected',
- description: $description,
- color: SlackMessage::errorColor()
- );
- }
-}
diff --git a/app/Notifications/Server/Reachable.php b/app/Notifications/Server/Reachable.php
deleted file mode 100644
index e03aef6b79..0000000000
--- a/app/Notifications/Server/Reachable.php
+++ /dev/null
@@ -1,77 +0,0 @@
-onQueue('high');
- $this->isRateLimited = isEmailRateLimited(
- limiterKey: 'server-reachable:'.$this->server->id,
- );
- }
-
- public function via(object $notifiable): array
- {
- if ($this->isRateLimited) {
- return [];
- }
-
- return $notifiable->getEnabledChannels('server_reachable');
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: Server ({$this->server->name}) revived.");
- $mail->view('emails.server-revived', [
- 'name' => $this->server->name,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- return new DiscordMessage(
- title: ":white_check_mark: Server '{$this->server->name}' revived",
- description: 'All automations & integrations are turned on again!',
- color: DiscordMessage::successColor(),
- );
- }
-
- public function toPushover(): PushoverMessage
- {
- return new PushoverMessage(
- title: 'Server revived',
- message: "Server '{$this->server->name}' revived. All automations & integrations are turned on again!",
- level: 'success',
- );
- }
-
- public function toTelegram(): array
- {
- return [
- 'message' => "Coolify: Server '{$this->server->name}' revived. All automations & integrations are turned on again!",
- ];
- }
-
- public function toSlack(): SlackMessage
- {
- return new SlackMessage(
- title: 'Server revived',
- description: "Server '{$this->server->name}' revived.\nAll automations & integrations are turned on again!",
- color: SlackMessage::successColor()
- );
- }
-}
diff --git a/app/Notifications/Server/Unreachable.php b/app/Notifications/Server/Unreachable.php
deleted file mode 100644
index fe90cc6105..0000000000
--- a/app/Notifications/Server/Unreachable.php
+++ /dev/null
@@ -1,85 +0,0 @@
-onQueue('high');
- $this->isRateLimited = isEmailRateLimited(
- limiterKey: 'server-unreachable:'.$this->server->id,
- );
- }
-
- public function via(object $notifiable): array
- {
- if ($this->isRateLimited) {
- return [];
- }
-
- return $notifiable->getEnabledChannels('server_unreachable');
- }
-
- public function toMail(): ?MailMessage
- {
- $mail = new MailMessage;
- $mail->subject("Coolify: Your server ({$this->server->name}) is unreachable.");
- $mail->view('emails.server-lost-connection', [
- 'name' => $this->server->name,
- ]);
-
- return $mail;
- }
-
- public function toDiscord(): ?DiscordMessage
- {
- $message = new DiscordMessage(
- title: ':cross_mark: Server unreachable',
- description: "Your server '{$this->server->name}' is unreachable.",
- color: DiscordMessage::errorColor(),
- );
-
- $message->addField('IMPORTANT', 'We automatically try to revive your server and turn on all automations & integrations.');
-
- return $message;
- }
-
- public function toTelegram(): ?array
- {
- return [
- 'message' => "Coolify: Your server '{$this->server->name}' is unreachable. All automations & integrations are turned off! Please check your server! IMPORTANT: We automatically try to revive your server and turn on all automations & integrations.",
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- return new PushoverMessage(
- title: 'Server unreachable',
- level: 'error',
- message: "Your server '{$this->server->name}' is unreachable. All automations & integrations are turned off!IMPORTANT: We automatically try to revive your server and turn on all automations & integrations.",
- );
- }
-
- public function toSlack(): SlackMessage
- {
- $description = "Your server '{$this->server->name}' is unreachable.\n";
- $description .= "All automations & integrations are turned off!\n\n";
- $description .= '*IMPORTANT:* We automatically try to revive your server and turn on all automations & integrations.';
-
- return new SlackMessage(
- title: 'Server unreachable',
- description: $description,
- color: SlackMessage::errorColor()
- );
- }
-}
diff --git a/app/Notifications/Test.php b/app/Notifications/Test.php
deleted file mode 100644
index ebb8735f53..0000000000
--- a/app/Notifications/Test.php
+++ /dev/null
@@ -1,112 +0,0 @@
-onQueue('high');
- }
-
- public function via(object $notifiable): array
- {
- if ($this->channel) {
- $channels = match ($this->channel) {
- 'email' => [EmailChannel::class],
- 'discord' => [DiscordChannel::class],
- 'telegram' => [TelegramChannel::class],
- 'slack' => [SlackChannel::class],
- 'pushover' => [PushoverChannel::class],
- default => [],
- };
- } else {
- $channels = $notifiable->getEnabledChannels('test');
- }
-
- return $channels;
- }
-
- public function middleware(object $notifiable, string $channel)
- {
- return match ($channel) {
- EmailChannel::class => [new RateLimited('email')],
- default => [],
- };
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject('Coolify: Test Email');
- $mail->view('emails.test');
-
- return $mail;
- }
-
- public function toDiscord(): DiscordMessage
- {
- $message = new DiscordMessage(
- title: ':white_check_mark: Test Success',
- description: 'This is a test Discord notification from Coolify. :cross_mark: :warning: :information_source:',
- color: DiscordMessage::successColor(),
- );
-
- $message->addField(name: 'Dashboard', value: '[Link]('.base_url().')', inline: true);
-
- return $message;
- }
-
- public function toTelegram(): array
- {
- return [
- 'message' => 'Coolify: This is a test Telegram notification from Coolify.',
- 'buttons' => [
- [
- 'text' => 'Go to your dashboard',
- 'url' => base_url(),
- ],
- ],
- ];
- }
-
- public function toPushover(): PushoverMessage
- {
- return new PushoverMessage(
- title: 'Test Pushover Notification',
- message: 'This is a test Pushover notification from Coolify.',
- buttons: [
- [
- 'text' => 'Go to your dashboard',
- 'url' => base_url(),
- ],
- ],
- );
- }
-
- public function toSlack(): SlackMessage
- {
- return new SlackMessage(
- title: 'Test Slack Notification',
- description: 'This is a test Slack notification from Coolify.'
- );
- }
-}
diff --git a/app/Notifications/TransactionalEmails/InvitationLink.php b/app/Notifications/TransactionalEmails/InvitationLink.php
deleted file mode 100644
index 30ace99dcb..0000000000
--- a/app/Notifications/TransactionalEmails/InvitationLink.php
+++ /dev/null
@@ -1,39 +0,0 @@
-onQueue('high');
- }
-
- public function toMail(): MailMessage
- {
- $invitation = TeamInvitation::whereEmail($this->user->email)->first();
- $invitation_team = Team::find($invitation->team->id);
-
- $mail = new MailMessage;
- $mail->subject('Coolify: Invitation for '.$invitation_team->name);
- $mail->view('emails.invitation-link', [
- 'team' => $invitation_team->name,
- 'email' => $this->user->email,
- 'invitation_link' => $invitation->link,
- ]);
-
- return $mail;
- }
-}
diff --git a/app/Notifications/TransactionalEmails/ResetPassword.php b/app/Notifications/TransactionalEmails/ResetPassword.php
deleted file mode 100644
index 4593ddb0d2..0000000000
--- a/app/Notifications/TransactionalEmails/ResetPassword.php
+++ /dev/null
@@ -1,75 +0,0 @@
-settings = instanceSettings();
- $this->token = $token;
- }
-
- public static function createUrlUsing($callback)
- {
- static::$createUrlCallback = $callback;
- }
-
- public static function toMailUsing($callback)
- {
- static::$toMailCallback = $callback;
- }
-
- public function via($notifiable)
- {
- $type = set_transanctional_email_settings();
- if (blank($type)) {
- throw new Exception('No email settings found.');
- }
-
- return ['mail'];
- }
-
- public function toMail($notifiable)
- {
- if (static::$toMailCallback) {
- return call_user_func(static::$toMailCallback, $notifiable, $this->token);
- }
-
- return $this->buildMailMessage($this->resetUrl($notifiable));
- }
-
- protected function buildMailMessage($url)
- {
- $mail = new MailMessage;
- $mail->subject('Coolify: Reset Password');
- $mail->view('emails.reset-password', ['url' => $url, 'count' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')]);
-
- return $mail;
- }
-
- protected function resetUrl($notifiable)
- {
- if (static::$createUrlCallback) {
- return call_user_func(static::$createUrlCallback, $notifiable, $this->token);
- }
-
- return url(route('password.reset', [
- 'token' => $this->token,
- 'email' => $notifiable->getEmailForPasswordReset(),
- ], false));
- }
-}
diff --git a/app/Notifications/TransactionalEmails/Test.php b/app/Notifications/TransactionalEmails/Test.php
deleted file mode 100644
index eeb32a2545..0000000000
--- a/app/Notifications/TransactionalEmails/Test.php
+++ /dev/null
@@ -1,29 +0,0 @@
-onQueue('high');
- }
-
- public function via(): array
- {
- return [EmailChannel::class];
- }
-
- public function toMail(): MailMessage
- {
- $mail = new MailMessage;
- $mail->subject('Coolify: Test Email');
- $mail->view('emails.test');
-
- return $mail;
- }
-}
diff --git a/app/Policies/ApplicationPolicy.php b/app/Policies/ApplicationPolicy.php
deleted file mode 100644
index 05fc289b8b..0000000000
--- a/app/Policies/ApplicationPolicy.php
+++ /dev/null
@@ -1,69 +0,0 @@
-isAdmin()) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Determine whether the user can restore the model.
- */
- public function restore(User $user, Application $application): bool
- {
- return true;
- }
-
- /**
- * Determine whether the user can permanently delete the model.
- */
- public function forceDelete(User $user, Application $application): bool
- {
- return true;
- }
-}
diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php
deleted file mode 100644
index ad59b7140d..0000000000
--- a/app/Policies/ServerPolicy.php
+++ /dev/null
@@ -1,65 +0,0 @@
-teams()->get()->firstWhere('id', $server->team_id) !== null;
- }
-
- /**
- * Determine whether the user can create models.
- */
- public function create(User $user): bool
- {
- return true;
- }
-
- /**
- * Determine whether the user can update the model.
- */
- public function update(User $user, Server $server): bool
- {
- return $user->teams()->get()->firstWhere('id', $server->team_id) !== null;
- }
-
- /**
- * Determine whether the user can delete the model.
- */
- public function delete(User $user, Server $server): bool
- {
- return $user->teams()->get()->firstWhere('id', $server->team_id) !== null;
- }
-
- /**
- * Determine whether the user can restore the model.
- */
- public function restore(User $user, Server $server): bool
- {
- return false;
- }
-
- /**
- * Determine whether the user can permanently delete the model.
- */
- public function forceDelete(User $user, Server $server): bool
- {
- return false;
- }
-}
diff --git a/app/Policies/ServicePolicy.php b/app/Policies/ServicePolicy.php
deleted file mode 100644
index 51a6d81168..0000000000
--- a/app/Policies/ServicePolicy.php
+++ /dev/null
@@ -1,82 +0,0 @@
-isAdmin()) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Determine whether the user can restore the model.
- */
- public function restore(User $user, Service $service): bool
- {
- return true;
- }
-
- /**
- * Determine whether the user can permanently delete the model.
- */
- public function forceDelete(User $user, Service $service): bool
- {
- if ($user->isAdmin()) {
- return true;
- }
-
- return false;
- }
-
- public function stop(User $user, Service $service): bool
- {
- if ($user->isAdmin()) {
- return true;
- }
-
- return false;
- }
-}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index 717daf2a2c..452e6b65b7 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -2,81 +2,23 @@
namespace App\Providers;
-use App\Models\PersonalAccessToken;
-use Illuminate\Database\Eloquent\Model;
-use Illuminate\Support\Facades\App;
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Http;
use Illuminate\Support\ServiceProvider;
-use Illuminate\Validation\Rules\Password;
-use Laravel\Sanctum\Sanctum;
-use Laravel\Telescope\TelescopeServiceProvider;
class AppServiceProvider extends ServiceProvider
{
+ /**
+ * Register any application services.
+ */
public function register(): void
{
- if (App::isLocal()) {
- $this->app->register(TelescopeServiceProvider::class);
- }
+ //
}
+ /**
+ * Bootstrap any application services.
+ */
public function boot(): void
{
- $this->configureCommands();
- $this->configureModels();
- $this->configurePasswords();
- $this->configureSanctumModel();
- $this->configureGitHubHttp();
-
- }
-
- private function configureCommands(): void
- {
- if (App::isProduction()) {
- DB::prohibitDestructiveCommands();
- }
- }
-
- private function configureModels(): void
- {
- // Disabled because it's causing issues with the application
- // Model::shouldBeStrict();
- }
-
- private function configurePasswords(): void
- {
- Password::defaults(function () {
- return App::isProduction()
- ? Password::min(8)
- ->mixedCase()
- ->letters()
- ->numbers()
- ->symbols()
- ->uncompromised()
- : Password::min(8)->letters();
- });
- }
-
- private function configureSanctumModel(): void
- {
- Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
- }
-
- private function configureGitHubHttp(): void
- {
- Http::macro('GitHub', function (string $api_url, ?string $github_access_token = null) {
- if ($github_access_token) {
- return Http::withHeaders([
- 'X-GitHub-Api-Version' => '2022-11-28',
- 'Accept' => 'application/vnd.github.v3+json',
- 'Authorization' => "Bearer $github_access_token",
- ])->baseUrl($api_url);
- } else {
- return Http::withHeaders([
- 'Accept' => 'application/vnd.github.v3+json',
- ])->baseUrl($api_url);
- }
- });
+ //
}
}
diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php
deleted file mode 100644
index dafcbee79f..0000000000
--- a/app/Providers/AuthServiceProvider.php
+++ /dev/null
@@ -1,26 +0,0 @@
-
- */
- protected $policies = [
- // 'App\Models\Model' => 'App\Policies\ModelPolicy',
- ];
-
- /**
- * Register any authentication / authorization services.
- */
- public function boot(): void
- {
- //
- }
-}
diff --git a/app/Providers/BroadcastServiceProvider.php b/app/Providers/BroadcastServiceProvider.php
deleted file mode 100644
index 2be04f5d9d..0000000000
--- a/app/Providers/BroadcastServiceProvider.php
+++ /dev/null
@@ -1,19 +0,0 @@
-visit('/login')
- ->type('email', 'test@example.com')
- ->type('password', 'password')
- ->press('Login');
- });
- }
-}
diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php
deleted file mode 100644
index d76ec30370..0000000000
--- a/app/Providers/EventServiceProvider.php
+++ /dev/null
@@ -1,47 +0,0 @@
- [
- MaintenanceModeEnabledNotification::class,
- ],
- MaintenanceModeDisabled::class => [
- MaintenanceModeDisabledNotification::class,
- ],
- SocialiteWasCalled::class => [
- AzureExtendSocialite::class.'@handle',
- AuthentikExtendSocialite::class.'@handle',
- GoogleExtendSocialite::class.'@handle',
- InfomaniakExtendSocialite::class.'@handle',
- ],
- ProxyStarted::class => [
- ProxyStartedNotification::class,
- ],
- ];
-
- public function boot(): void
- {
- //
- }
-
- public function shouldDiscoverEvents(): bool
- {
- return false;
- }
-}
diff --git a/app/Providers/FortifyServiceProvider.php b/app/Providers/FortifyServiceProvider.php
deleted file mode 100644
index ed27a158a1..0000000000
--- a/app/Providers/FortifyServiceProvider.php
+++ /dev/null
@@ -1,129 +0,0 @@
-app->instance(RegisterResponse::class, new class implements RegisterResponse
- {
- public function toResponse($request)
- {
- // First user (root) will be redirected to /settings instead of / on registration.
- if ($request->user()->currentTeam->id === 0) {
- return redirect()->route('settings.index');
- }
-
- return redirect(RouteServiceProvider::HOME);
- }
- });
- }
-
- /**
- * Bootstrap any application services.
- */
- public function boot(): void
- {
- Fortify::createUsersUsing(CreateNewUser::class);
- Fortify::registerView(function () {
- $isFirstUser = User::count() === 0;
-
- $settings = instanceSettings();
- if (! $settings->is_registration_enabled) {
- return redirect()->route('login');
- }
-
- return view('auth.register', [
- 'isFirstUser' => $isFirstUser,
- ]);
- });
-
- Fortify::loginView(function () {
- $settings = instanceSettings();
- $enabled_oauth_providers = OauthSetting::where('enabled', true)->get();
- $users = User::count();
- if ($users == 0) {
- // If there are no users, redirect to registration
- return redirect()->route('register');
- }
-
- return view('auth.login', [
- 'is_registration_enabled' => $settings->is_registration_enabled,
- 'enabled_oauth_providers' => $enabled_oauth_providers,
- ]);
- });
-
- Fortify::authenticateUsing(function (Request $request) {
- $email = strtolower($request->email);
- $user = User::where('email', $email)->with('teams')->first();
- if (
- $user &&
- Hash::check($request->password, $user->password)
- ) {
- $user->updated_at = now();
- $user->save();
- $user->currentTeam = $user->teams->firstWhere('personal_team', true);
- if (! $user->currentTeam) {
- $user->currentTeam = $user->recreate_personal_team();
- }
- session(['currentTeam' => $user->currentTeam]);
-
- return $user;
- }
- });
- Fortify::requestPasswordResetLinkView(function () {
- return view('auth.forgot-password');
- });
- Fortify::resetPasswordView(function ($request) {
- return view('auth.reset-password', ['request' => $request]);
- });
- Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
-
- Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
- Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
-
- Fortify::confirmPasswordView(function () {
- return view('auth.confirm-password');
- });
-
- Fortify::twoFactorChallengeView(function () {
- return view('auth.two-factor-challenge');
- });
-
- RateLimiter::for('force-password-reset', function (Request $request) {
- return Limit::perMinute(15)->by($request->user()->id);
- });
-
- RateLimiter::for('forgot-password', function (Request $request) {
- return Limit::perMinute(5)->by($request->ip());
- });
-
- RateLimiter::for('login', function (Request $request) {
- $email = (string) $request->email;
-
- return Limit::perMinute(5)->by($email.$request->ip());
- });
-
- RateLimiter::for('two-factor', function (Request $request) {
- return Limit::perMinute(5)->by($request->session()->get('login.id'));
- });
- }
-}
diff --git a/app/Providers/HorizonServiceProvider.php b/app/Providers/HorizonServiceProvider.php
deleted file mode 100644
index 0caa3a3a93..0000000000
--- a/app/Providers/HorizonServiceProvider.php
+++ /dev/null
@@ -1,63 +0,0 @@
-app->singleton(JobRepository::class, CustomJobRepository::class);
- $this->app->singleton(CustomJobRepositoryInterface::class, CustomJobRepository::class);
- }
-
- /**
- * Bootstrap services.
- */
- public function boot(): void
- {
- parent::boot();
- Event::listen(function (JobReserved $event) {
- $payload = $event->payload->decoded;
- $jobName = $payload['displayName'];
- if ($jobName === 'App\Jobs\ApplicationDeploymentJob') {
- $tags = $payload['tags'];
- $id = $payload['id'];
- $deploymentQueueId = collect($tags)->first(function ($tag) {
- return str_contains($tag, 'App\Models\ApplicationDeploymentQueue');
- });
- if (blank($deploymentQueueId)) {
- return;
- }
- $deploymentQueueId = explode(':', $deploymentQueueId)[1];
- $deploymentQueue = ApplicationDeploymentQueue::find($deploymentQueueId);
- $deploymentQueue->update([
- 'horizon_job_id' => $id,
- ]);
- }
- });
- }
-
- protected function gate(): void
- {
- Gate::define('viewHorizon', function ($user) {
- $root_user = User::find(0);
-
- return in_array($user->email, [
- $root_user->email,
- ]);
- });
- }
-}
diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php
deleted file mode 100644
index c859607464..0000000000
--- a/app/Providers/RouteServiceProvider.php
+++ /dev/null
@@ -1,58 +0,0 @@
-configureRateLimiting();
-
- $this->routes(function () {
- Route::middleware('api')
- ->prefix('api')
- ->group(base_path('routes/api.php'));
-
- Route::prefix('webhooks')
- ->group(base_path('routes/webhooks.php'));
-
- Route::middleware('web')
- ->group(base_path('routes/web.php'));
- });
- }
-
- /**
- * Configure the rate limiters for the application.
- */
- protected function configureRateLimiting(): void
- {
- RateLimiter::for('api', function (Request $request) {
- if ($request->path() === 'api/health') {
- return Limit::perMinute(1000)->by($request->user()?->id ?: $request->ip());
- }
-
- return Limit::perMinute(200)->by($request->user()?->id ?: $request->ip());
- });
- RateLimiter::for('5', function (Request $request) {
- return Limit::perMinute(5)->by($request->user()?->id ?: $request->ip());
- });
- }
-}
diff --git a/app/Providers/TelescopeServiceProvider.php b/app/Providers/TelescopeServiceProvider.php
deleted file mode 100644
index b7a3366314..0000000000
--- a/app/Providers/TelescopeServiceProvider.php
+++ /dev/null
@@ -1,67 +0,0 @@
-hideSensitiveRequestDetails();
-
- $isLocal = $this->app->environment('local');
-
- Telescope::filter(function (IncomingEntry $entry) use ($isLocal) {
- return $isLocal ||
- $entry->isReportableException() ||
- $entry->isFailedRequest() ||
- $entry->isFailedJob() ||
- $entry->isScheduledTask() ||
- $entry->hasMonitoredTag();
- });
- }
-
- /**
- * Prevent sensitive request details from being logged by Telescope.
- */
- protected function hideSensitiveRequestDetails(): void
- {
- if ($this->app->environment('local')) {
- return;
- }
-
- Telescope::hideRequestParameters(['_token']);
-
- Telescope::hideRequestHeaders([
- 'cookie',
- 'x-csrf-token',
- 'x-xsrf-token',
- ]);
- }
-
- /**
- * Register the Telescope gate.
- *
- * This gate determines who can access Telescope in non-local environments.
- */
- protected function gate(): void
- {
- Gate::define('viewTelescope', function ($user) {
- $root_user = User::find(0);
-
- return in_array($user->email, [
- $root_user->email,
- ]);
- });
- }
-}
diff --git a/app/Repositories/CustomJobRepository.php b/app/Repositories/CustomJobRepository.php
deleted file mode 100644
index 502dd252b7..0000000000
--- a/app/Repositories/CustomJobRepository.php
+++ /dev/null
@@ -1,51 +0,0 @@
-all();
- }
-
- public function getReservedJobs(): Collection
- {
- return $this->getJobsByStatus('reserved');
- }
-
- public function getJobsByStatus(string $status): Collection
- {
- $jobs = new Collection;
-
- $this->getRecent()->each(function ($job) use ($jobs, $status) {
- if ($job->status === $status) {
- $jobs->push($job);
- }
- });
-
- return $jobs;
- }
-
- public function countJobsByStatus(string $status): int
- {
- return $this->getJobsByStatus($status)->count();
- }
-
- public function getQueues(): array
- {
- $queues = $this->connection()->keys('queue:*');
- $queues = array_map(function ($queue) {
- return explode(':', $queue)[2];
- }, $queues);
-
- return $queues;
- }
-}
diff --git a/app/Services/ConfigurationGenerator.php b/app/Services/ConfigurationGenerator.php
deleted file mode 100644
index a7e4b31be7..0000000000
--- a/app/Services/ConfigurationGenerator.php
+++ /dev/null
@@ -1,194 +0,0 @@
-generateConfig();
- }
-
- protected function generateConfig(): void
- {
- if ($this->resource instanceof Application) {
- $this->config = [
- 'id' => $this->resource->id,
- 'name' => $this->resource->name,
- 'uuid' => $this->resource->uuid,
- 'description' => $this->resource->description,
- 'coolify_details' => [
- 'project_uuid' => $this->resource->project()->uuid,
- 'environment_uuid' => $this->resource->environment->uuid,
-
- 'destination_type' => $this->resource->destination_type,
- 'destination_id' => $this->resource->destination_id,
- 'source_type' => $this->resource->source_type,
- 'source_id' => $this->resource->source_id,
- 'private_key_id' => $this->resource->private_key_id,
- ],
-
- 'post_deployment_command' => $this->resource->post_deployment_command,
- 'post_deployment_command_container' => $this->resource->post_deployment_command_container,
- 'pre_deployment_command' => $this->resource->pre_deployment_command,
- 'pre_deployment_command_container' => $this->resource->pre_deployment_command_container,
- 'build' => [
- 'type' => $this->resource->build_pack,
- 'static_image' => $this->resource->static_image,
- 'base_directory' => $this->resource->base_directory,
- 'publish_directory' => $this->resource->publish_directory,
- 'dockerfile' => $this->resource->dockerfile,
- 'dockerfile_location' => $this->resource->dockerfile_location,
- 'dockerfile_target_build' => $this->resource->dockerfile_target_build,
- 'custom_docker_run_options' => $this->resource->custom_docker_options,
- 'compose_parsing_version' => $this->resource->compose_parsing_version,
- 'docker_compose' => $this->resource->docker_compose,
- 'docker_compose_location' => $this->resource->docker_compose_location,
- 'docker_compose_raw' => $this->resource->docker_compose_raw,
- 'docker_compose_domains' => $this->resource->docker_compose_domains,
- 'docker_compose_custom_start_command' => $this->resource->docker_compose_custom_start_command,
- 'docker_compose_custom_build_command' => $this->resource->docker_compose_custom_build_command,
- 'install_command' => $this->resource->install_command,
- 'build_command' => $this->resource->build_command,
- 'start_command' => $this->resource->start_command,
- 'watch_paths' => $this->resource->watch_paths,
- ],
- 'source' => [
- 'git_repository' => $this->resource->git_repository,
- 'git_branch' => $this->resource->git_branch,
- 'git_commit_sha' => $this->resource->git_commit_sha,
- 'repository_project_id' => $this->resource->repository_project_id,
- ],
- 'docker_registry_image' => $this->getDockerRegistryImage(),
- 'domains' => [
- 'fqdn' => $this->resource->fqdn,
- 'ports_exposes' => $this->resource->ports_exposes,
- 'ports_mappings' => $this->resource->ports_mappings,
- 'redirect' => $this->resource->redirect,
- 'custom_nginx_configuration' => $this->resource->custom_nginx_configuration,
- ],
- 'environment_variables' => [
- 'production' => $this->getEnvironmentVariables(),
- 'preview' => $this->getPreviewEnvironmentVariables(),
- ],
- 'settings' => $this->getApplicationSettings(),
- 'preview' => $this->getPreview(),
- 'limits' => $this->resource->getLimits(),
- 'health_check' => [
- 'health_check_path' => $this->resource->health_check_path,
- 'health_check_port' => $this->resource->health_check_port,
- 'health_check_host' => $this->resource->health_check_host,
- 'health_check_method' => $this->resource->health_check_method,
- 'health_check_return_code' => $this->resource->health_check_return_code,
- 'health_check_scheme' => $this->resource->health_check_scheme,
- 'health_check_response_text' => $this->resource->health_check_response_text,
- 'health_check_interval' => $this->resource->health_check_interval,
- 'health_check_timeout' => $this->resource->health_check_timeout,
- 'health_check_retries' => $this->resource->health_check_retries,
- 'health_check_start_period' => $this->resource->health_check_start_period,
- 'health_check_enabled' => $this->resource->health_check_enabled,
- ],
- 'webhooks_secrets' => [
- 'manual_webhook_secret_github' => $this->resource->manual_webhook_secret_github,
- 'manual_webhook_secret_gitlab' => $this->resource->manual_webhook_secret_gitlab,
- 'manual_webhook_secret_bitbucket' => $this->resource->manual_webhook_secret_bitbucket,
- 'manual_webhook_secret_gitea' => $this->resource->manual_webhook_secret_gitea,
- ],
- 'swarm' => [
- 'swarm_replicas' => $this->resource->swarm_replicas,
- 'swarm_placement_constraints' => $this->resource->swarm_placement_constraints,
- ],
- ];
- }
- }
-
- protected function getPreview(): array
- {
- return [
- 'preview_url_template' => $this->resource->preview_url_template,
- ];
- }
-
- protected function getDockerRegistryImage(): array
- {
- return [
- 'image' => $this->resource->docker_registry_image_name,
- 'tag' => $this->resource->docker_registry_image_tag,
- ];
- }
-
- protected function getEnvironmentVariables(): array
- {
- $variables = collect([]);
- foreach ($this->resource->environment_variables as $env) {
- $variables->push([
- 'key' => $env->key,
- 'value' => $env->value,
- 'is_build_time' => $env->is_build_time,
- 'is_preview' => $env->is_preview,
- 'is_multiline' => $env->is_multiline,
- ]);
- }
-
- return $variables->toArray();
- }
-
- protected function getPreviewEnvironmentVariables(): array
- {
- $variables = collect([]);
- foreach ($this->resource->environment_variables_preview as $env) {
- $variables->push([
- 'key' => $env->key,
- 'value' => $env->value,
- 'is_build_time' => $env->is_build_time,
- 'is_preview' => $env->is_preview,
- 'is_multiline' => $env->is_multiline,
- ]);
- }
-
- return $variables->toArray();
- }
-
- protected function getApplicationSettings(): array
- {
- $removedKeys = ['id', 'application_id', 'created_at', 'updated_at'];
- $settings = $this->resource->settings->attributesToArray();
- $settings = collect($settings)->filter(function ($value, $key) use ($removedKeys) {
- return ! in_array($key, $removedKeys);
- })->sortBy(function ($value, $key) {
- return $key;
- })->toArray();
-
- return $settings;
- }
-
- public function saveJson(string $path): void
- {
- file_put_contents($path, json_encode($this->config, JSON_PRETTY_PRINT));
- }
-
- public function saveYaml(string $path): void
- {
- file_put_contents($path, Yaml::dump($this->config, 6, 2));
- }
-
- public function toArray(): array
- {
- return $this->config;
- }
-
- public function toJson(): string
- {
- return json_encode($this->config, JSON_PRETTY_PRINT);
- }
-
- public function toYaml(): string
- {
- return Yaml::dump($this->config, 6, 2);
- }
-}
diff --git a/app/Services/DockerImageParser.php b/app/Services/DockerImageParser.php
deleted file mode 100644
index 1fd6625b32..0000000000
--- a/app/Services/DockerImageParser.php
+++ /dev/null
@@ -1,78 +0,0 @@
- strrpos($imageString, '/'))) {
- $mainPart = substr($imageString, 0, $lastColon);
- $this->tag = substr($imageString, $lastColon + 1);
- } else {
- $mainPart = $imageString;
- $this->tag = 'latest';
- }
-
- // Split the main part by / to handle registry and image name
- $pathParts = explode('/', $mainPart);
-
- // If we have more than one part and the first part contains a dot or colon
- // it's likely a registry URL
- if (count($pathParts) > 1 && (str_contains($pathParts[0], '.') || str_contains($pathParts[0], ':'))) {
- $this->registryUrl = array_shift($pathParts);
- $this->imageName = implode('/', $pathParts);
- } else {
- $this->imageName = $mainPart;
- }
-
- return $this;
- }
-
- public function getFullImageNameWithoutTag(): string
- {
- if ($this->registryUrl) {
- return $this->registryUrl.'/'.$this->imageName;
- }
-
- return $this->imageName;
- }
-
- public function getRegistryUrl(): string
- {
- return $this->registryUrl;
- }
-
- public function getImageName(): string
- {
- return $this->imageName;
- }
-
- public function getTag(): string
- {
- return $this->tag;
- }
-
- public function toString(): string
- {
- $parts = [];
- if ($this->registryUrl) {
- $parts[] = $this->registryUrl;
- }
- $parts[] = $this->imageName;
-
- return implode('/', $parts).':'.$this->tag;
- }
-}
diff --git a/app/Traits/ExecuteRemoteCommand.php b/app/Traits/ExecuteRemoteCommand.php
deleted file mode 100644
index f8ccee9db7..0000000000
--- a/app/Traits/ExecuteRemoteCommand.php
+++ /dev/null
@@ -1,96 +0,0 @@
-server instanceof Server === false) {
- throw new \RuntimeException('Server is not set or is not an instance of Server model');
- }
- $commandsText->each(function ($single_command) {
- $command = data_get($single_command, 'command') ?? $single_command[0] ?? null;
- if ($command === null) {
- throw new \RuntimeException('Command is not set');
- }
- $hidden = data_get($single_command, 'hidden', false);
- $customType = data_get($single_command, 'type');
- $ignore_errors = data_get($single_command, 'ignore_errors', false);
- $append = data_get($single_command, 'append', true);
- $this->save = data_get($single_command, 'save');
- if ($this->server->isNonRoot()) {
- if (str($command)->startsWith('docker exec')) {
- $command = str($command)->replace('docker exec', 'sudo docker exec');
- } else {
- $command = parseLineForSudo($command, $this->server);
- }
- }
- $remote_command = SshMultiplexingHelper::generateSshCommand($this->server, $command);
- $process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $hidden, $customType, $append) {
- $output = str($output)->trim();
- if ($output->startsWith('╔')) {
- $output = "\n".$output;
- }
- $new_log_entry = [
- 'command' => remove_iip($command),
- 'output' => remove_iip($output),
- 'type' => $customType ?? $type === 'err' ? 'stderr' : 'stdout',
- 'timestamp' => Carbon::now('UTC'),
- 'hidden' => $hidden,
- 'batch' => static::$batch_counter,
- ];
- if (! $this->application_deployment_queue->logs) {
- $new_log_entry['order'] = 1;
- } else {
- $previous_logs = json_decode($this->application_deployment_queue->logs, associative: true, flags: JSON_THROW_ON_ERROR);
- $new_log_entry['order'] = count($previous_logs) + 1;
- }
- $previous_logs[] = $new_log_entry;
- $this->application_deployment_queue->logs = json_encode($previous_logs, flags: JSON_THROW_ON_ERROR);
- $this->application_deployment_queue->save();
-
- if ($this->save) {
- if (data_get($this->saved_outputs, $this->save, null) === null) {
- data_set($this->saved_outputs, $this->save, str());
- }
- if ($append) {
- $this->saved_outputs[$this->save] .= str($output)->trim();
- $this->saved_outputs[$this->save] = str($this->saved_outputs[$this->save]);
- } else {
- $this->saved_outputs[$this->save] = str($output)->trim();
- }
- }
- });
- $this->application_deployment_queue->update([
- 'current_process_id' => $process->id(),
- ]);
-
- $process_result = $process->wait();
- if ($process_result->exitCode() !== 0) {
- if (! $ignore_errors) {
- $this->application_deployment_queue->status = ApplicationDeploymentStatus::FAILED->value;
- $this->application_deployment_queue->save();
- throw new \RuntimeException($process_result->errorOutput());
- }
- }
- });
- }
-}
diff --git a/app/Traits/HasConfiguration.php b/app/Traits/HasConfiguration.php
deleted file mode 100644
index e572c45ea2..0000000000
--- a/app/Traits/HasConfiguration.php
+++ /dev/null
@@ -1,42 +0,0 @@
-uuid}";
- if (! is_dir($configDir)) {
- mkdir($configDir, 0755, true);
- }
-
- $generator->saveJson($configDir.'/coolify.json');
- $generator->saveYaml($configDir.'/coolify.yaml');
-
- // Generate a README file with basic information
- file_put_contents(
- $configDir.'/README.md',
- generate_readme_file($this->name, now()->toIso8601String())
- );
- }
-
- public function getConfigurationAsJson(): string
- {
- return (new ConfigurationGenerator($this))->toJson();
- }
-
- public function getConfigurationAsYaml(): string
- {
- return (new ConfigurationGenerator($this))->toYaml();
- }
-
- public function getConfigurationAsArray(): array
- {
- return (new ConfigurationGenerator($this))->toArray();
- }
-}
diff --git a/app/Traits/HasNotificationSettings.php b/app/Traits/HasNotificationSettings.php
deleted file mode 100644
index bb088896a6..0000000000
--- a/app/Traits/HasNotificationSettings.php
+++ /dev/null
@@ -1,93 +0,0 @@
- $this->emailNotificationSettings,
- 'discord' => $this->discordNotificationSettings,
- 'telegram' => $this->telegramNotificationSettings,
- 'slack' => $this->slackNotificationSettings,
- 'pushover' => $this->pushoverNotificationSettings,
- default => null,
- };
- }
-
- /**
- * Check if a notification channel is enabled
- */
- public function isNotificationEnabled(string $channel): bool
- {
- $settings = $this->getNotificationSettings($channel);
-
- return $settings?->isEnabled() ?? false;
- }
-
- /**
- * Check if a specific notification type is enabled for a channel
- */
- public function isNotificationTypeEnabled(string $channel, string $event): bool
- {
- $settings = $this->getNotificationSettings($channel);
-
- if (! $settings || ! $this->isNotificationEnabled($channel)) {
- return false;
- }
-
- if (in_array($event, $this->alwaysSendEvents)) {
- return true;
- }
-
- $settingKey = "{$event}_{$channel}_notifications";
-
- return (bool) $settings->$settingKey;
- }
-
- /**
- * Get all enabled notification channels for an event
- */
- public function getEnabledChannels(string $event): array
- {
- $channels = [];
-
- $channelMap = [
- 'email' => EmailChannel::class,
- 'discord' => DiscordChannel::class,
- 'telegram' => TelegramChannel::class,
- 'slack' => SlackChannel::class,
- 'pushover' => PushoverChannel::class,
- ];
-
- if ($event === 'general') {
- unset($channelMap['email']);
- }
-
- foreach ($channelMap as $channel => $channelClass) {
- if ($this->isNotificationEnabled($channel) && $this->isNotificationTypeEnabled($channel, $event)) {
- $channels[] = $channelClass;
- }
- }
-
- return $channels;
- }
-}
diff --git a/app/Traits/SaveFromRedirect.php b/app/Traits/SaveFromRedirect.php
deleted file mode 100644
index 166c16a4bc..0000000000
--- a/app/Traits/SaveFromRedirect.php
+++ /dev/null
@@ -1,26 +0,0 @@
-forget('from');
- if (! $parameters || $parameters->count() === 0) {
- $parameters = $this->parameters;
- }
- $parameters = collect($parameters) ?? collect([]);
- $queries = collect($this->query) ?? collect([]);
- $parameters = $parameters->merge($queries);
- session(['from' => [
- 'back' => $this->currentRoute,
- 'route' => $route,
- 'parameters' => $parameters,
- ]]);
-
- return redirect()->route($route);
- }
-}
diff --git a/app/View/Components/Forms/Button.php b/app/View/Components/Forms/Button.php
deleted file mode 100644
index bf88d3f885..0000000000
--- a/app/View/Components/Forms/Button.php
+++ /dev/null
@@ -1,30 +0,0 @@
-noStyle) {
- $this->defaultClass = '';
- }
- }
-
- public function render(): View|Closure|string
- {
- return view('components.forms.button');
- }
-}
diff --git a/app/View/Components/Forms/Checkbox.php b/app/View/Components/Forms/Checkbox.php
deleted file mode 100644
index e46598e8e9..0000000000
--- a/app/View/Components/Forms/Checkbox.php
+++ /dev/null
@@ -1,38 +0,0 @@
-disabled) {
- $this->defaultClass .= ' opacity-40';
- }
- }
-
- /**
- * Get the view / contents that represent the component.
- */
- public function render(): View|Closure|string
- {
- return view('components.forms.checkbox');
- }
-}
diff --git a/app/View/Components/Forms/Datalist.php b/app/View/Components/Forms/Datalist.php
deleted file mode 100644
index 25643753d7..0000000000
--- a/app/View/Components/Forms/Datalist.php
+++ /dev/null
@@ -1,43 +0,0 @@
-id)) {
- $this->id = new Cuid2;
- }
- if (is_null($this->name)) {
- $this->name = $this->id;
- }
-
- $this->label = Str::title($this->label);
-
- return view('components.forms.datalist');
- }
-}
diff --git a/app/View/Components/Forms/Input.php b/app/View/Components/Forms/Input.php
deleted file mode 100644
index 7283ef20f8..0000000000
--- a/app/View/Components/Forms/Input.php
+++ /dev/null
@@ -1,45 +0,0 @@
-id)) {
- $this->id = new Cuid2;
- }
- if (is_null($this->name)) {
- $this->name = $this->id;
- }
- if ($this->type === 'password') {
- $this->defaultClass = $this->defaultClass.' pr-[2.8rem]';
- }
-
- // $this->label = Str::title($this->label);
- return view('components.forms.input');
- }
-}
diff --git a/app/View/Components/Forms/Select.php b/app/View/Components/Forms/Select.php
deleted file mode 100644
index dd5ba66b7d..0000000000
--- a/app/View/Components/Forms/Select.php
+++ /dev/null
@@ -1,43 +0,0 @@
-id)) {
- $this->id = new Cuid2;
- }
- if (is_null($this->name)) {
- $this->name = $this->id;
- }
-
- $this->label = Str::title($this->label);
-
- return view('components.forms.select');
- }
-}
diff --git a/app/View/Components/Forms/Textarea.php b/app/View/Components/Forms/Textarea.php
deleted file mode 100644
index 6081c2a8ae..0000000000
--- a/app/View/Components/Forms/Textarea.php
+++ /dev/null
@@ -1,55 +0,0 @@
-id)) {
- $this->id = new Cuid2;
- }
- if (is_null($this->name)) {
- $this->name = $this->id;
- }
-
- // $this->label = Str::title($this->label);
- return view('components.forms.textarea');
- }
-}
diff --git a/app/View/Components/Modal.php b/app/View/Components/Modal.php
deleted file mode 100644
index 7e254ebdcd..0000000000
--- a/app/View/Components/Modal.php
+++ /dev/null
@@ -1,34 +0,0 @@
-links = collect([]);
- $service->applications()->get()->map(function ($application) {
- $type = $application->serviceType();
- if ($type) {
- $links = generateServiceSpecificFqdns($application);
- $links = $links->map(function ($link) {
- return getFqdnWithoutPort($link);
- });
- $this->links = $this->links->merge($links);
- } else {
- if ($application->fqdn) {
- $fqdns = collect(str($application->fqdn)->explode(','));
- $fqdns->map(function ($fqdn) {
- $this->links->push(getFqdnWithoutPort($fqdn));
- });
- }
- if ($application->ports) {
- $portsCollection = collect(str($application->ports)->explode(','));
- $portsCollection->map(function ($port) {
- if (str($port)->contains(':')) {
- $hostPort = str($port)->before(':');
- } else {
- $hostPort = $port;
- }
- $this->links->push(base_url(withPort: false).":{$hostPort}");
- });
- }
- }
- });
- }
-
- /**
- * Get the view / contents that represent the component.
- */
- public function render(): View|Closure|string
- {
- return view('components.services.links');
- }
-}
diff --git a/app/View/Components/Status/Index.php b/app/View/Components/Status/Index.php
deleted file mode 100644
index ada9eb6823..0000000000
--- a/app/View/Components/Status/Index.php
+++ /dev/null
@@ -1,26 +0,0 @@
-complexStatus = $service->status;
- }
-
- /**
- * Get the view / contents that represent the component.
- */
- public function render(): View|Closure|string
- {
- return view('components.status.services');
- }
-}
diff --git a/app/View/Components/services/advanced.php b/app/View/Components/services/advanced.php
deleted file mode 100644
index 8104eaad49..0000000000
--- a/app/View/Components/services/advanced.php
+++ /dev/null
@@ -1,26 +0,0 @@
-make(Illuminate\Contracts\Console\Kernel::class);
-
-$status = $kernel->handle(
- $input = new Symfony\Component\Console\Input\ArgvInput,
- new Symfony\Component\Console\Output\ConsoleOutput
-);
-
-/*
-|--------------------------------------------------------------------------
-| Shutdown The Application
-|--------------------------------------------------------------------------
-|
-| Once Artisan has finished running, we will fire off the shutdown events
-| so that any final work may be done by the application before we shut
-| down the process. This is the last thing to happen to the request.
-|
-*/
-
-$kernel->terminate($input, $status);
+$status = $app->handleCommand(new ArgvInput);
exit($status);
diff --git a/bootstrap/app.php b/bootstrap/app.php
index 037e17df03..d6e5a1aeca 100644
--- a/bootstrap/app.php
+++ b/bootstrap/app.php
@@ -1,55 +1,16 @@
singleton(
- Illuminate\Contracts\Http\Kernel::class,
- App\Http\Kernel::class
-);
-
-$app->singleton(
- Illuminate\Contracts\Console\Kernel::class,
- App\Console\Kernel::class
-);
-
-$app->singleton(
- Illuminate\Contracts\Debug\ExceptionHandler::class,
- App\Exceptions\Handler::class
-);
-
-/*
-|--------------------------------------------------------------------------
-| Return The Application
-|--------------------------------------------------------------------------
-|
-| This script returns the application instance. The instance is given to
-| the calling script so we can separate the building of the instances
-| from the actual running of the application and sending responses.
-|
-*/
-
-return $app;
+return Application::configure(basePath: dirname(__DIR__))
+ ->withRouting(
+ web: __DIR__.'/../routes/web.php',
+ )
+ ->withMiddleware(function (Middleware $middleware) {
+ //
+ })
+ ->withExceptions(function (Exceptions $exceptions) {
+ //
+ })->create();
diff --git a/bootstrap/getHelperVersion.php b/bootstrap/getHelperVersion.php
deleted file mode 100644
index 766af8db29..0000000000
--- a/bootstrap/getHelperVersion.php
+++ /dev/null
@@ -1,10 +0,0 @@
-user()->currentAccessToken();
-
- return data_get($token, 'team_id');
-}
-function invalidTokenResponse()
-{
- return response()->json(['message' => 'Invalid token.', 'docs' => 'https://coolify.io/docs/api-reference/authorization'], 400);
-}
-
-function serializeApiResponse($data)
-{
- if ($data instanceof Collection) {
- return $data->map(function ($d) {
- $d = collect($d)->sortKeys();
- $created_at = data_get($d, 'created_at');
- $updated_at = data_get($d, 'updated_at');
- if ($created_at) {
- unset($d['created_at']);
- $d['created_at'] = $created_at;
- }
- if ($updated_at) {
- unset($d['updated_at']);
- $d['updated_at'] = $updated_at;
- }
- if (data_get($d, 'name')) {
- $d = $d->prepend($d['name'], 'name');
- }
- if (data_get($d, 'description')) {
- $d = $d->prepend($d['description'], 'description');
- }
- if (data_get($d, 'uuid')) {
- $d = $d->prepend($d['uuid'], 'uuid');
- }
-
- if (! is_null(data_get($d, 'id'))) {
- $d = $d->prepend($d['id'], 'id');
- }
-
- return $d;
- });
- } else {
- $d = collect($data)->sortKeys();
- $created_at = data_get($d, 'created_at');
- $updated_at = data_get($d, 'updated_at');
- if ($created_at) {
- unset($d['created_at']);
- $d['created_at'] = $created_at;
- }
- if ($updated_at) {
- unset($d['updated_at']);
- $d['updated_at'] = $updated_at;
- }
- if (data_get($d, 'name')) {
- $d = $d->prepend($d['name'], 'name');
- }
- if (data_get($d, 'description')) {
- $d = $d->prepend($d['description'], 'description');
- }
- if (data_get($d, 'uuid')) {
- $d = $d->prepend($d['uuid'], 'uuid');
- }
-
- if (! is_null(data_get($d, 'id'))) {
- $d = $d->prepend($d['id'], 'id');
- }
-
- return $d;
- }
-}
-
-function sharedDataApplications()
-{
- return [
- 'git_repository' => 'string',
- 'git_branch' => 'string',
- 'build_pack' => Rule::enum(BuildPackTypes::class),
- 'is_static' => 'boolean',
- 'static_image' => Rule::enum(StaticImageTypes::class),
- 'domains' => 'string',
- 'redirect' => Rule::enum(RedirectTypes::class),
- 'git_commit_sha' => 'string',
- 'docker_registry_image_name' => 'string|nullable',
- 'docker_registry_image_tag' => 'string|nullable',
- 'install_command' => 'string|nullable',
- 'build_command' => 'string|nullable',
- 'start_command' => 'string|nullable',
- 'ports_exposes' => 'string|regex:/^(\d+)(,\d+)*$/',
- 'ports_mappings' => 'string|regex:/^(\d+:\d+)(,\d+:\d+)*$/|nullable',
- 'base_directory' => 'string|nullable',
- 'publish_directory' => 'string|nullable',
- 'health_check_enabled' => 'boolean',
- 'health_check_path' => 'string',
- 'health_check_port' => 'string|nullable',
- 'health_check_host' => 'string',
- 'health_check_method' => 'string',
- 'health_check_return_code' => 'numeric',
- 'health_check_scheme' => 'string',
- 'health_check_response_text' => 'string|nullable',
- 'health_check_interval' => 'numeric',
- 'health_check_timeout' => 'numeric',
- 'health_check_retries' => 'numeric',
- 'health_check_start_period' => 'numeric',
- 'limits_memory' => 'string',
- 'limits_memory_swap' => 'string',
- 'limits_memory_swappiness' => 'numeric',
- 'limits_memory_reservation' => 'string',
- 'limits_cpus' => 'string',
- 'limits_cpuset' => 'string|nullable',
- 'limits_cpu_shares' => 'numeric',
- 'custom_labels' => 'string|nullable',
- 'custom_docker_run_options' => 'string|nullable',
- 'post_deployment_command' => 'string|nullable',
- 'post_deployment_command_container' => 'string',
- 'pre_deployment_command' => 'string|nullable',
- 'pre_deployment_command_container' => 'string',
- 'manual_webhook_secret_github' => 'string|nullable',
- 'manual_webhook_secret_gitlab' => 'string|nullable',
- 'manual_webhook_secret_bitbucket' => 'string|nullable',
- 'manual_webhook_secret_gitea' => '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',
- 'docker_compose_custom_build_command' => 'string|nullable',
- ];
-}
-
-function validateIncomingRequest(Request $request)
-{
- // check if request is json
- if (! $request->isJson()) {
- return response()->json([
- 'message' => 'Invalid request.',
- 'error' => 'Content-Type must be application/json.',
- ], 400);
- }
- // check if request is valid json
- if (! json_decode($request->getContent())) {
- return response()->json([
- 'message' => 'Invalid request.',
- 'error' => 'Invalid JSON.',
- ], 400);
- }
- // check if valid json is empty
- if (empty($request->json()->all())) {
- return response()->json([
- 'message' => 'Invalid request.',
- 'error' => 'Empty JSON.',
- ], 400);
- }
-}
-
-function removeUnnecessaryFieldsFromRequest(Request $request)
-{
- $request->offsetUnset('project_uuid');
- $request->offsetUnset('environment_name');
- $request->offsetUnset('environment_uuid');
- $request->offsetUnset('destination_uuid');
- $request->offsetUnset('server_uuid');
- $request->offsetUnset('type');
- $request->offsetUnset('domains');
- $request->offsetUnset('instant_deploy');
- $request->offsetUnset('github_app_uuid');
- $request->offsetUnset('private_key_uuid');
- $request->offsetUnset('use_build_server');
- $request->offsetUnset('is_static');
-}
diff --git a/bootstrap/helpers/applications.php b/bootstrap/helpers/applications.php
deleted file mode 100644
index d5283898e8..0000000000
--- a/bootstrap/helpers/applications.php
+++ /dev/null
@@ -1,122 +0,0 @@
-id;
- $deployment_link = Url::fromString($application->link()."/deployment/{$deployment_uuid}");
- $deployment_url = $deployment_link->getPath();
- $server_id = $application->destination->server->id;
- $server_name = $application->destination->server->name;
- $destination_id = $application->destination->id;
-
- if ($server) {
- $server_id = $server->id;
- $server_name = $server->name;
- }
- if ($destination) {
- $destination_id = $destination->id;
- }
- $deployment = ApplicationDeploymentQueue::create([
- 'application_id' => $application_id,
- 'application_name' => $application->name,
- 'server_id' => $server_id,
- 'server_name' => $server_name,
- 'destination_id' => $destination_id,
- 'deployment_uuid' => $deployment_uuid,
- 'deployment_url' => $deployment_url,
- 'pull_request_id' => $pull_request_id,
- 'force_rebuild' => $force_rebuild,
- 'is_webhook' => $is_webhook,
- 'is_api' => $is_api,
- 'restart_only' => $restart_only,
- 'commit' => $commit,
- 'rollback' => $rollback,
- 'git_type' => $git_type,
- 'only_this_server' => $only_this_server,
- ]);
-
- if ($no_questions_asked) {
- ApplicationDeploymentJob::dispatch(
- application_deployment_queue_id: $deployment->id,
- );
- } elseif (next_queuable($server_id, $application_id)) {
- ApplicationDeploymentJob::dispatch(
- application_deployment_queue_id: $deployment->id,
- );
- }
-}
-function force_start_deployment(ApplicationDeploymentQueue $deployment)
-{
- $deployment->update([
- 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
- ]);
-
- ApplicationDeploymentJob::dispatch(
- application_deployment_queue_id: $deployment->id,
- );
-}
-function queue_next_deployment(Application $application)
-{
- $server_id = $application->destination->server_id;
- $next_found = ApplicationDeploymentQueue::where('server_id', $server_id)->where('status', ApplicationDeploymentStatus::QUEUED)->get()->sortBy('created_at')->first();
- if ($next_found) {
- $next_found->update([
- 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
- ]);
-
- ApplicationDeploymentJob::dispatch(
- application_deployment_queue_id: $next_found->id,
- );
- }
-}
-
-function next_queuable(string $server_id, string $application_id): bool
-{
- $deployments = ApplicationDeploymentQueue::where('server_id', $server_id)->whereIn('status', ['in_progress', ApplicationDeploymentStatus::QUEUED])->get()->sortByDesc('created_at');
- $same_application_deployments = $deployments->where('application_id', $application_id);
- $in_progress = $same_application_deployments->filter(function ($value, $key) {
- return $value->status === 'in_progress';
- });
- if ($in_progress->count() > 0) {
- return false;
- }
- $server = Server::find($server_id);
- $concurrent_builds = $server->settings->concurrent_builds;
-
- if ($deployments->count() > $concurrent_builds) {
- return false;
- }
-
- return true;
-}
-function next_after_cancel(?Server $server = null)
-{
- if ($server) {
- $next_found = ApplicationDeploymentQueue::where('server_id', data_get($server, 'id'))->where('status', ApplicationDeploymentStatus::QUEUED)->get()->sortBy('created_at');
- if ($next_found->count() > 0) {
- foreach ($next_found as $next) {
- $server = Server::find($next->server_id);
- $concurrent_builds = $server->settings->concurrent_builds;
- $inprogress_deployments = ApplicationDeploymentQueue::where('server_id', $next->server_id)->whereIn('status', [ApplicationDeploymentStatus::QUEUED])->get()->sortByDesc('created_at');
- if ($inprogress_deployments->count() < $concurrent_builds) {
- $next->update([
- 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
- ]);
-
- ApplicationDeploymentJob::dispatch(
- application_deployment_queue_id: $next->id,
- );
- }
- break;
- }
- }
- }
-}
diff --git a/bootstrap/helpers/constants.php b/bootstrap/helpers/constants.php
deleted file mode 100644
index b568e090c3..0000000000
--- a/bootstrap/helpers/constants.php
+++ /dev/null
@@ -1,56 +0,0 @@
-';
-const DATABASE_TYPES = ['postgresql', 'redis', 'mongodb', 'mysql', 'mariadb', 'keydb', 'dragonfly', 'clickhouse'];
-const VALID_CRON_STRINGS = [
- 'every_minute' => '* * * * *',
- 'hourly' => '0 * * * *',
- 'daily' => '0 0 * * *',
- 'weekly' => '0 0 * * 0',
- 'monthly' => '0 0 1 * *',
- 'yearly' => '0 0 1 1 *',
- '@hourly' => '0 * * * *',
- '@daily' => '0 0 * * *',
- '@weekly' => '0 0 * * 0',
- '@monthly' => '0 0 1 * *',
- '@yearly' => '0 0 1 1 *',
-];
-const RESTART_MODE = 'unless-stopped';
-
-const DATABASE_DOCKER_IMAGES = [
- 'bitnami/mariadb',
- 'bitnami/mongodb',
- 'bitnami/redis',
- 'mysql',
- 'bitnami/mysql',
- 'mysql/mysql-server',
- 'mariadb',
- 'postgis/postgis',
- 'postgres',
- 'bitnami/postgresql',
- 'supabase/postgres',
- 'elestio/postgres',
- 'mongo',
- 'redis',
- 'memcached',
- 'couchdb',
- 'neo4j',
- 'influxdb',
- 'clickhouse/clickhouse-server',
-];
-const SPECIFIC_SERVICES = [
- 'quay.io/minio/minio',
- 'minio/minio',
- 'svhd/logto',
-];
-
-// Based on /etc/os-release
-const SUPPORTED_OS = [
- 'ubuntu debian raspbian pop',
- 'centos fedora rhel ol rocky amzn almalinux',
- 'sles opensuse-leap opensuse-tumbleweed',
- 'arch',
- 'alpine',
-];
-
-const SHARED_VARIABLE_TYPES = ['team', 'project', 'environment'];
diff --git a/bootstrap/helpers/databases.php b/bootstrap/helpers/databases.php
deleted file mode 100644
index 2fd85337d4..0000000000
--- a/bootstrap/helpers/databases.php
+++ /dev/null
@@ -1,433 +0,0 @@
-firstOrFail();
- $database = new StandalonePostgresql;
- $database->name = generate_database_name('postgresql');
- $database->image = $databaseImage;
- $database->postgres_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
- $database->environment_id = $environmentId;
- $database->destination_id = $destination->id;
- $database->destination_type = $destination->getMorphClass();
- if ($otherData) {
- $database->fill($otherData);
- }
- $database->save();
-
- return $database;
-}
-
-function create_standalone_redis($environment_id, $destination_uuid, ?array $otherData = null): StandaloneRedis
-{
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->firstOrFail();
- $database = new StandaloneRedis;
- $database->name = generate_database_name('redis');
- $redis_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
- $database->environment_id = $environment_id;
- $database->destination_id = $destination->id;
- $database->destination_type = $destination->getMorphClass();
- if ($otherData) {
- $database->fill($otherData);
- }
- $database->save();
-
- EnvironmentVariable::create([
- 'key' => 'REDIS_PASSWORD',
- 'value' => $redis_password,
- 'resourceable_type' => StandaloneRedis::class,
- 'resourceable_id' => $database->id,
- 'is_shared' => false,
- ]);
-
- EnvironmentVariable::create([
- 'key' => 'REDIS_USERNAME',
- 'value' => 'default',
- 'resourceable_type' => StandaloneRedis::class,
- 'resourceable_id' => $database->id,
- 'is_shared' => false,
- ]);
-
- return $database;
-}
-
-function create_standalone_mongodb($environment_id, $destination_uuid, ?array $otherData = null): StandaloneMongodb
-{
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->firstOrFail();
- $database = new StandaloneMongodb;
- $database->name = generate_database_name('mongodb');
- $database->mongo_initdb_root_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
- $database->environment_id = $environment_id;
- $database->destination_id = $destination->id;
- $database->destination_type = $destination->getMorphClass();
- if ($otherData) {
- $database->fill($otherData);
- }
- $database->save();
-
- return $database;
-}
-
-function create_standalone_mysql($environment_id, $destination_uuid, ?array $otherData = null): StandaloneMysql
-{
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->firstOrFail();
- $database = new StandaloneMysql;
- $database->name = generate_database_name('mysql');
- $database->mysql_root_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
- $database->mysql_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
- $database->environment_id = $environment_id;
- $database->destination_id = $destination->id;
- $database->destination_type = $destination->getMorphClass();
- if ($otherData) {
- $database->fill($otherData);
- }
- $database->save();
-
- return $database;
-}
-
-function create_standalone_mariadb($environment_id, $destination_uuid, ?array $otherData = null): StandaloneMariadb
-{
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->firstOrFail();
- $database = new StandaloneMariadb;
- $database->name = generate_database_name('mariadb');
- $database->mariadb_root_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
- $database->mariadb_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
- $database->environment_id = $environment_id;
- $database->destination_id = $destination->id;
- $database->destination_type = $destination->getMorphClass();
- if ($otherData) {
- $database->fill($otherData);
- }
- $database->save();
-
- return $database;
-}
-
-function create_standalone_keydb($environment_id, $destination_uuid, ?array $otherData = null): StandaloneKeydb
-{
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->firstOrFail();
- $database = new StandaloneKeydb;
- $database->name = generate_database_name('keydb');
- $database->keydb_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
- $database->environment_id = $environment_id;
- $database->destination_id = $destination->id;
- $database->destination_type = $destination->getMorphClass();
- if ($otherData) {
- $database->fill($otherData);
- }
- $database->save();
-
- return $database;
-}
-
-function create_standalone_dragonfly($environment_id, $destination_uuid, ?array $otherData = null): StandaloneDragonfly
-{
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->firstOrFail();
- $database = new StandaloneDragonfly;
- $database->name = generate_database_name('dragonfly');
- $database->dragonfly_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
- $database->environment_id = $environment_id;
- $database->destination_id = $destination->id;
- $database->destination_type = $destination->getMorphClass();
- if ($otherData) {
- $database->fill($otherData);
- }
- $database->save();
-
- return $database;
-}
-
-function create_standalone_clickhouse($environment_id, $destination_uuid, ?array $otherData = null): StandaloneClickhouse
-{
- $destination = StandaloneDocker::where('uuid', $destination_uuid)->firstOrFail();
- $database = new StandaloneClickhouse;
- $database->name = generate_database_name('clickhouse');
- $database->clickhouse_admin_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
- $database->environment_id = $environment_id;
- $database->destination_id = $destination->id;
- $database->destination_type = $destination->getMorphClass();
- if ($otherData) {
- $database->fill($otherData);
- }
- $database->save();
-
- return $database;
-}
-
-function deleteBackupsLocally(string|array|null $filenames, Server $server): void
-{
- if (empty($filenames)) {
- return;
- }
- if (is_string($filenames)) {
- $filenames = [$filenames];
- }
- $quotedFiles = array_map(fn ($file) => "\"$file\"", $filenames);
- instant_remote_process(['rm -f '.implode(' ', $quotedFiles)], $server, throwError: false);
-
- $foldersToCheck = collect($filenames)->map(fn ($file) => dirname($file))->unique();
- $foldersToCheck->each(fn ($folder) => deleteEmptyBackupFolder($folder, $server));
-}
-
-function deleteBackupsS3(string|array|null $filenames, S3Storage $s3): void
-{
- if (empty($filenames) || ! $s3) {
- return;
- }
- if (is_string($filenames)) {
- $filenames = [$filenames];
- }
-
- $disk = Storage::build([
- 'driver' => 's3',
- 'key' => $s3->key,
- 'secret' => $s3->secret,
- 'region' => $s3->region,
- 'bucket' => $s3->bucket,
- 'endpoint' => $s3->endpoint,
- 'use_path_style_endpoint' => true,
- 'aws_url' => $s3->awsUrl(),
- ]);
-
- $disk->delete($filenames);
-}
-
-function deleteEmptyBackupFolder($folderPath, Server $server): void
-{
- $escapedPath = escapeshellarg($folderPath);
- $escapedParentPath = escapeshellarg(dirname($folderPath));
-
- $checkEmpty = instant_remote_process(["[ -d $escapedPath ] && [ -z \"$(ls -A $escapedPath)\" ] && echo 'empty' || echo 'not empty'"], $server, throwError: false);
-
- if (trim($checkEmpty) === 'empty') {
- instant_remote_process(["rmdir $escapedPath"], $server, throwError: false);
- $checkParentEmpty = instant_remote_process(["[ -d $escapedParentPath ] && [ -z \"$(ls -A $escapedParentPath)\" ] && echo 'empty' || echo 'not empty'"], $server, throwError: false);
- if (trim($checkParentEmpty) === 'empty') {
- instant_remote_process(["rmdir $escapedParentPath"], $server, throwError: false);
- }
- }
-}
-
-function removeOldBackups($backup): void
-{
- try {
- if ($backup->executions) {
- $localBackupsToDelete = deleteOldBackupsLocally($backup);
- if ($localBackupsToDelete->isNotEmpty()) {
- $backup->executions()
- ->whereIn('id', $localBackupsToDelete->pluck('id'))
- ->update(['local_storage_deleted' => true]);
- }
- }
-
- if ($backup->save_s3 && $backup->executions) {
- $s3BackupsToDelete = deleteOldBackupsFromS3($backup);
- if ($s3BackupsToDelete->isNotEmpty()) {
- $backup->executions()
- ->whereIn('id', $s3BackupsToDelete->pluck('id'))
- ->update(['s3_storage_deleted' => true]);
- }
- }
-
- $backup->executions()
- ->where('local_storage_deleted', true)
- ->where('s3_storage_deleted', true)
- ->delete();
-
- } catch (\Exception $e) {
- throw $e;
- }
-}
-
-function deleteOldBackupsLocally($backup): Collection
-{
- if (! $backup || ! $backup->executions) {
- return collect();
- }
-
- $successfulBackups = $backup->executions()
- ->where('status', 'success')
- ->where('local_storage_deleted', false)
- ->orderBy('created_at', 'desc')
- ->get();
-
- if ($successfulBackups->isEmpty()) {
- return collect();
- }
-
- $retentionAmount = $backup->database_backup_retention_amount_locally;
- $retentionDays = $backup->database_backup_retention_days_locally;
- $maxStorageGB = $backup->database_backup_retention_max_storage_locally;
-
- if ($retentionAmount === 0 && $retentionDays === 0 && $maxStorageGB === 0) {
- return collect();
- }
-
- $backupsToDelete = collect();
-
- if ($retentionAmount > 0) {
- $byAmount = $successfulBackups->skip($retentionAmount);
- $backupsToDelete = $backupsToDelete->merge($byAmount);
- }
-
- if ($retentionDays > 0) {
- $oldestAllowedDate = $successfulBackups->first()->created_at->clone()->utc()->subDays($retentionDays);
- $oldBackups = $successfulBackups->filter(fn ($execution) => $execution->created_at->utc() < $oldestAllowedDate);
- $backupsToDelete = $backupsToDelete->merge($oldBackups);
- }
-
- if ($maxStorageGB > 0) {
- $maxStorageBytes = $maxStorageGB * pow(1024, 3);
- $totalSize = 0;
- $backupsOverLimit = collect();
-
- $backupsToCheck = $successfulBackups->skip(1);
-
- foreach ($backupsToCheck as $backupExecution) {
- $totalSize += (int) $backupExecution->size;
- if ($totalSize > $maxStorageBytes) {
- $backupsOverLimit = $successfulBackups->filter(
- fn ($b) => $b->created_at->utc() <= $backupExecution->created_at->utc()
- )->skip(1);
- break;
- }
- }
-
- $backupsToDelete = $backupsToDelete->merge($backupsOverLimit);
- }
-
- $backupsToDelete = $backupsToDelete->unique('id');
- $processedBackups = collect();
-
- $server = null;
- if ($backup->database_type === \App\Models\ServiceDatabase::class) {
- $server = $backup->database->service->server;
- } else {
- $server = $backup->database->destination->server;
- }
-
- if (! $server) {
- return collect();
- }
-
- $filesToDelete = $backupsToDelete
- ->filter(fn ($execution) => ! empty($execution->filename))
- ->pluck('filename')
- ->all();
-
- if (! empty($filesToDelete)) {
- deleteBackupsLocally($filesToDelete, $server);
- $processedBackups = $backupsToDelete;
- }
-
- return $processedBackups;
-}
-
-function deleteOldBackupsFromS3($backup): Collection
-{
- if (! $backup || ! $backup->executions || ! $backup->s3) {
- return collect();
- }
-
- $successfulBackups = $backup->executions()
- ->where('status', 'success')
- ->where('s3_storage_deleted', false)
- ->orderBy('created_at', 'desc')
- ->get();
-
- if ($successfulBackups->isEmpty()) {
- return collect();
- }
-
- $retentionAmount = $backup->database_backup_retention_amount_s3;
- $retentionDays = $backup->database_backup_retention_days_s3;
- $maxStorageGB = $backup->database_backup_retention_max_storage_s3;
-
- if ($retentionAmount === 0 && $retentionDays === 0 && $maxStorageGB === 0) {
- return collect();
- }
-
- $backupsToDelete = collect();
-
- if ($retentionAmount > 0) {
- $byAmount = $successfulBackups->skip($retentionAmount);
- $backupsToDelete = $backupsToDelete->merge($byAmount);
- }
-
- if ($retentionDays > 0) {
- $oldestAllowedDate = $successfulBackups->first()->created_at->clone()->utc()->subDays($retentionDays);
- $oldBackups = $successfulBackups->filter(fn ($execution) => $execution->created_at->utc() < $oldestAllowedDate);
- $backupsToDelete = $backupsToDelete->merge($oldBackups);
- }
-
- if ($maxStorageGB > 0) {
- $maxStorageBytes = $maxStorageGB * pow(1024, 3);
- $totalSize = 0;
- $backupsOverLimit = collect();
-
- $backupsToCheck = $successfulBackups->skip(1);
-
- foreach ($backupsToCheck as $backupExecution) {
- $totalSize += (int) $backupExecution->size;
- if ($totalSize > $maxStorageBytes) {
- $backupsOverLimit = $successfulBackups->filter(
- fn ($b) => $b->created_at->utc() <= $backupExecution->created_at->utc()
- )->skip(1);
- break;
- }
- }
-
- $backupsToDelete = $backupsToDelete->merge($backupsOverLimit);
- }
-
- $backupsToDelete = $backupsToDelete->unique('id');
- $processedBackups = collect();
-
- $filesToDelete = $backupsToDelete
- ->filter(fn ($execution) => ! empty($execution->filename))
- ->pluck('filename')
- ->all();
-
- if (! empty($filesToDelete)) {
- deleteBackupsS3($filesToDelete, $backup->s3);
- $processedBackups = $backupsToDelete;
- }
-
- return $processedBackups;
-}
-
-function isPublicPortAlreadyUsed(Server $server, int $port, ?string $id = null): bool
-{
- if ($id) {
- $foundDatabase = $server->databases()->where('public_port', $port)->where('is_public', true)->where('id', '!=', $id)->first();
- } else {
- $foundDatabase = $server->databases()->where('public_port', $port)->where('is_public', true)->first();
- }
- if ($foundDatabase) {
- return true;
- }
-
- return false;
-}
diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php
deleted file mode 100644
index 80e19d80f9..0000000000
--- a/bootstrap/helpers/docker.php
+++ /dev/null
@@ -1,887 +0,0 @@
-isSwarm()) {
- $containers = instant_remote_process(["docker ps -a --filter='label=coolify.applicationId={$id}' --format '{{json .}}' "], $server);
- $containers = format_docker_command_output_to_json($containers);
- $containers = $containers->map(function ($container) use ($pullRequestId, $includePullrequests) {
- $labels = data_get($container, 'Labels');
- if (! str($labels)->contains('coolify.pullRequestId=')) {
- data_set($container, 'Labels', $labels.",coolify.pullRequestId={$pullRequestId}");
-
- return $container;
- }
- if ($includePullrequests) {
- return $container;
- }
- if (str($labels)->contains("coolify.pullRequestId=$pullRequestId")) {
- return $container;
- }
-
- return null;
- });
-
- return $containers->filter();
- }
-
- return $containers;
-}
-
-function getCurrentServiceContainerStatus(Server $server, int $id): Collection
-{
- $containers = collect([]);
- if (! $server->isSwarm()) {
- $containers = instant_remote_process(["docker ps -a --filter='label=coolify.serviceId={$id}' --format '{{json .}}' "], $server);
- $containers = format_docker_command_output_to_json($containers);
-
- return $containers->filter();
- }
-
- return $containers;
-}
-
-function format_docker_command_output_to_json($rawOutput): Collection
-{
- $outputLines = explode(PHP_EOL, $rawOutput);
- if (count($outputLines) === 1) {
- $outputLines = collect($outputLines[0]);
- } else {
- $outputLines = collect($outputLines);
- }
-
- try {
- return $outputLines
- ->reject(fn ($line) => empty($line))
- ->map(fn ($outputLine) => json_decode($outputLine, true, flags: JSON_THROW_ON_ERROR));
- } catch (\Throwable) {
- return collect([]);
- }
-}
-
-function format_docker_labels_to_json(string|array $rawOutput): Collection
-{
- if (is_array($rawOutput)) {
- return collect($rawOutput);
- }
- $outputLines = explode(PHP_EOL, $rawOutput);
-
- return collect($outputLines)
- ->reject(fn ($line) => empty($line))
- ->map(function ($outputLine) {
- $outputArray = explode(',', $outputLine);
-
- return collect($outputArray)
- ->map(function ($outputLine) {
- return explode('=', $outputLine);
- })
- ->mapWithKeys(function ($outputLine) {
- return [$outputLine[0] => $outputLine[1]];
- });
- })[0];
-}
-
-function format_docker_envs_to_json($rawOutput)
-{
- try {
- $outputLines = json_decode($rawOutput, true, flags: JSON_THROW_ON_ERROR);
-
- return collect(data_get($outputLines[0], 'Config.Env', []))->mapWithKeys(function ($env) {
- $env = explode('=', $env);
-
- return [$env[0] => $env[1]];
- });
- } catch (\Throwable) {
- return collect([]);
- }
-}
-function checkMinimumDockerEngineVersion($dockerVersion)
-{
- $majorDockerVersion = str($dockerVersion)->before('.')->value();
- $requiredDockerVersion = str(config('constants.docker.minimum_required_version'))->before('.')->value();
- if ($majorDockerVersion < $requiredDockerVersion) {
- $dockerVersion = null;
- }
-
- return $dockerVersion;
-}
-function executeInDocker(string $containerId, string $command)
-{
- return "docker exec {$containerId} bash -c '{$command}'";
- // return "docker exec {$this->deployment_uuid} bash -c '{$command} |& tee -a /proc/1/fd/1; [ \$PIPESTATUS -eq 0 ] || exit \$PIPESTATUS'";
-}
-
-function getContainerStatus(Server $server, string $container_id, bool $all_data = false, bool $throwError = false)
-{
- if ($server->isSwarm()) {
- $container = instant_remote_process(["docker service ls --filter 'name={$container_id}' --format '{{json .}}' "], $server, $throwError);
- } else {
- $container = instant_remote_process(["docker inspect --format '{{json .}}' {$container_id}"], $server, $throwError);
- }
- if (! $container) {
- return 'exited';
- }
- $container = format_docker_command_output_to_json($container);
- if ($container->isEmpty()) {
- return 'exited';
- }
- if ($all_data) {
- return $container[0];
- }
- if ($server->isSwarm()) {
- $replicas = data_get($container[0], 'Replicas');
- $replicas = explode('/', $replicas);
- $active = (int) $replicas[0];
- $total = (int) $replicas[1];
- if ($active === $total) {
- return 'running';
- } else {
- return 'starting';
- }
- } else {
- return data_get($container[0], 'State.Status', 'exited');
- }
-}
-
-function generateApplicationContainerName(Application $application, $pull_request_id = 0)
-{
- // TODO: refactor generateApplicationContainerName, we do not need $application and $pull_request_id
-
- $consistent_container_name = $application->settings->is_consistent_container_name_enabled;
- $now = now()->format('Hisu');
- if ($pull_request_id !== 0 && $pull_request_id !== null) {
- return $application->uuid.'-pr-'.$pull_request_id;
- } else {
- if ($consistent_container_name) {
- return $application->uuid;
- }
-
- return $application->uuid.'-'.$now;
- }
-}
-function get_port_from_dockerfile($dockerfile): ?int
-{
- $dockerfile_array = explode("\n", $dockerfile);
- $found_exposed_port = null;
- foreach ($dockerfile_array as $line) {
- $line_str = str($line)->trim();
- if ($line_str->startsWith('EXPOSE')) {
- $found_exposed_port = $line_str->replace('EXPOSE', '')->trim();
- break;
- }
- }
- if ($found_exposed_port) {
- return (int) $found_exposed_port->value();
- }
-
- return null;
-}
-
-function defaultDatabaseLabels($database)
-{
- $labels = collect([]);
- $labels->push('coolify.managed=true');
- $labels->push('coolify.type=database');
- $labels->push('coolify.databaseId='.$database->id);
- $labels->push('coolify.resourceName='.Str::slug($database->name));
- $labels->push('coolify.serviceName='.Str::slug($database->name));
- $labels->push('coolify.projectName='.Str::slug($database->project()->name));
- $labels->push('coolify.environmentName='.Str::slug($database->environment->name));
- $labels->push('coolify.database.subType='.$database->type());
-
- return $labels;
-}
-
-function defaultLabels($id, $name, string $projectName, string $resourceName, string $environment, $pull_request_id = 0, string $type = 'application', $subType = null, $subId = null, $subName = null)
-{
- $labels = collect([]);
- $labels->push('coolify.managed=true');
- $labels->push('coolify.version='.config('constants.coolify.version'));
- $labels->push('coolify.'.$type.'Id='.$id);
- $labels->push("coolify.type=$type");
- $labels->push('coolify.name='.$name);
- $labels->push('coolify.resourceName='.Str::slug($resourceName));
- $labels->push('coolify.projectName='.Str::slug($projectName));
- $labels->push('coolify.serviceName='.Str::slug($subName ?? $resourceName));
- $labels->push('coolify.environmentName='.Str::slug($environment));
-
- $labels->push('coolify.pullRequestId='.$pull_request_id);
- if ($type === 'service') {
- $subId && $labels->push('coolify.service.subId='.$subId);
- $subType && $labels->push('coolify.service.subType='.$subType);
- $subName && $labels->push('coolify.service.subName='.Str::slug($subName));
- }
-
- return $labels;
-}
-
-function generateServiceSpecificFqdns(ServiceApplication|Application $resource)
-{
- if ($resource->getMorphClass() === \App\Models\ServiceApplication::class) {
- $uuid = data_get($resource, 'uuid');
- $server = data_get($resource, 'service.server');
- $environment_variables = data_get($resource, 'service.environment_variables');
- $type = $resource->serviceType();
- } elseif ($resource->getMorphClass() === \App\Models\Application::class) {
- $uuid = data_get($resource, 'uuid');
- $server = data_get($resource, 'destination.server');
- $environment_variables = data_get($resource, 'environment_variables');
- $type = $resource->serviceType();
- }
- if (is_null($server) || is_null($type)) {
- return collect([]);
- }
- $variables = collect($environment_variables);
- $payload = collect([]);
- switch ($type) {
- case $type?->contains('minio'):
- $MINIO_BROWSER_REDIRECT_URL = $variables->where('key', 'MINIO_BROWSER_REDIRECT_URL')->first();
- $MINIO_SERVER_URL = $variables->where('key', 'MINIO_SERVER_URL')->first();
-
- if (is_null($MINIO_BROWSER_REDIRECT_URL) || is_null($MINIO_SERVER_URL)) {
- return collect([]);
- }
-
- if (str($MINIO_BROWSER_REDIRECT_URL->value ?? '')->isEmpty()) {
- $MINIO_BROWSER_REDIRECT_URL->update([
- 'value' => generateFqdn($server, 'console-'.$uuid, true),
- ]);
- }
- if (str($MINIO_SERVER_URL->value ?? '')->isEmpty()) {
- $MINIO_SERVER_URL->update([
- 'value' => generateFqdn($server, 'minio-'.$uuid, true),
- ]);
- }
- $payload = collect([
- $MINIO_BROWSER_REDIRECT_URL->value.':9001',
- $MINIO_SERVER_URL->value.':9000',
- ]);
- break;
- case $type?->contains('logto'):
- $LOGTO_ENDPOINT = $variables->where('key', 'LOGTO_ENDPOINT')->first();
- $LOGTO_ADMIN_ENDPOINT = $variables->where('key', 'LOGTO_ADMIN_ENDPOINT')->first();
-
- if (is_null($LOGTO_ENDPOINT) || is_null($LOGTO_ADMIN_ENDPOINT)) {
- return collect([]);
- }
-
- if (str($LOGTO_ENDPOINT->value ?? '')->isEmpty()) {
- $LOGTO_ENDPOINT->update([
- 'value' => generateFqdn($server, 'logto-'.$uuid),
- ]);
- }
- if (str($LOGTO_ADMIN_ENDPOINT->value ?? '')->isEmpty()) {
- $LOGTO_ADMIN_ENDPOINT->update([
- 'value' => generateFqdn($server, 'logto-admin-'.$uuid),
- ]);
- }
- $payload = collect([
- $LOGTO_ENDPOINT->value.':3001',
- $LOGTO_ADMIN_ENDPOINT->value.':3002',
- ]);
- break;
- }
-
- return $payload;
-}
-function fqdnLabelsForCaddy(string $network, string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true, ?bool $is_stripprefix_enabled = true, ?string $service_name = null, ?string $image = null, string $redirect_direction = 'both', ?string $predefinedPort = null)
-{
- $labels = collect([]);
- if ($serviceLabels) {
- $labels->push("caddy_ingress_network={$uuid}");
- } else {
- $labels->push("caddy_ingress_network={$network}");
- }
- foreach ($domains as $loop => $domain) {
- $url = Url::fromString($domain);
- $host = $url->getHost();
- $path = $url->getPath();
- $host_without_www = str($host)->replace('www.', '');
- $schema = $url->getScheme();
- $port = $url->getPort();
- $handle = 'handle_path';
- if (! $is_stripprefix_enabled) {
- $handle = 'handle';
- }
- if (is_null($port) && ! is_null($onlyPort)) {
- $port = $onlyPort;
- }
- if (is_null($port) && $predefinedPort) {
- $port = $predefinedPort;
- }
- $labels->push("caddy_{$loop}={$schema}://{$host}");
- $labels->push("caddy_{$loop}.header=-Server");
- $labels->push("caddy_{$loop}.try_files={path} /index.html /index.php");
-
- if ($port) {
- $labels->push("caddy_{$loop}.{$handle}.{$loop}_reverse_proxy={{upstreams $port}}");
- } else {
- $labels->push("caddy_{$loop}.{$handle}.{$loop}_reverse_proxy={{upstreams}}");
- }
- $labels->push("caddy_{$loop}.{$handle}={$path}*");
- if ($is_gzip_enabled) {
- $labels->push("caddy_{$loop}.encode=zstd gzip");
- }
- if ($redirect_direction === 'www' && ! str($host)->startsWith('www.')) {
- $labels->push("caddy_{$loop}.redir={$schema}://www.{$host}{uri}");
- }
- if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) {
- $labels->push("caddy_{$loop}.redir={$schema}://{$host_without_www}{uri}");
- }
- if (isDev()) {
- // $labels->push("caddy_{$loop}.tls=internal");
- }
- }
-
- return $labels->sort();
-}
-function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true, ?bool $is_stripprefix_enabled = true, ?string $service_name = null, bool $generate_unique_uuid = false, ?string $image = null, string $redirect_direction = 'both')
-{
- $labels = collect([]);
- $labels->push('traefik.enable=true');
- $labels->push('traefik.http.middlewares.gzip.compress=true');
- $labels->push('traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https');
-
- $middlewares_from_labels = collect([]);
-
- if ($serviceLabels) {
- $middlewares_from_labels = $serviceLabels->map(function ($item) {
- if (preg_match('/traefik\.http\.middlewares\.(.*?)(\.|$)/', $item, $matches)) {
- return $matches[1];
- }
- if (preg_match('/coolify\.traefik\.middlewares=(.*)/', $item, $matches)) {
- return explode(',', $matches[1]);
- }
-
- return null;
- })->flatten()
- ->filter()
- ->unique();
- }
- foreach ($domains as $loop => $domain) {
- try {
- if ($generate_unique_uuid) {
- $uuid = new Cuid2;
- }
-
- $url = Url::fromString($domain);
- $host = $url->getHost();
- $path = $url->getPath();
- $schema = $url->getScheme();
- $port = $url->getPort();
- if (is_null($port) && ! is_null($onlyPort)) {
- $port = $onlyPort;
- }
- $http_label = "http-{$loop}-{$uuid}";
- $https_label = "https-{$loop}-{$uuid}";
- if ($service_name) {
- $http_label = "http-{$loop}-{$uuid}-{$service_name}";
- $https_label = "https-{$loop}-{$uuid}-{$service_name}";
- }
- if (str($image)->contains('ghost')) {
- $labels->push("traefik.http.middlewares.redir-ghost-{$uuid}.redirectregex.regex=^{$path}/(.*)");
- $labels->push("traefik.http.middlewares.redir-ghost-{$uuid}.redirectregex.replacement=/$1");
- $labels->push("caddy_{$loop}.handle_path.{$loop}_redir-ghost-{$uuid}.handler=rewrite");
- $labels->push("caddy_{$loop}.handle_path.{$loop}_redir-ghost-{$uuid}.rewrite.regexp=^{$path}/(.*)");
- $labels->push("caddy_{$loop}.handle_path.{$loop}_redir-ghost-{$uuid}.rewrite.replacement=/$1");
- }
-
- $to_www_name = "{$loop}-{$uuid}-to-www";
- $to_non_www_name = "{$loop}-{$uuid}-to-non-www";
- $redirect_to_non_www = [
- "traefik.http.middlewares.{$to_non_www_name}.redirectregex.regex=^(http|https)://www\.(.+)",
- "traefik.http.middlewares.{$to_non_www_name}.redirectregex.replacement=\${1}://\${2}",
- "traefik.http.middlewares.{$to_non_www_name}.redirectregex.permanent=false",
- ];
- $redirect_to_www = [
- "traefik.http.middlewares.{$to_www_name}.redirectregex.regex=^(http|https)://(?:www\.)?(.+)",
- "traefik.http.middlewares.{$to_www_name}.redirectregex.replacement=\${1}://www.\${2}",
- "traefik.http.middlewares.{$to_www_name}.redirectregex.permanent=false",
- ];
- if ($schema === 'https') {
- // Set labels for https
- $labels->push("traefik.http.routers.{$https_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)");
- $labels->push("traefik.http.routers.{$https_label}.entryPoints=https");
- if ($port) {
- $labels->push("traefik.http.routers.{$https_label}.service={$https_label}");
- $labels->push("traefik.http.services.{$https_label}.loadbalancer.server.port=$port");
- }
- if ($path !== '/') {
- // Middleware handling
- $middlewares = collect([]);
- if ($is_stripprefix_enabled && ! str($image)->contains('ghost')) {
- $labels->push("traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}");
- $middlewares->push("{$https_label}-stripprefix");
- }
- if ($is_gzip_enabled) {
- $middlewares->push('gzip');
- }
- if (str($image)->contains('ghost')) {
- $middlewares->push("redir-ghost-{$uuid}");
- }
- if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) {
- $labels = $labels->merge($redirect_to_non_www);
- $middlewares->push($to_non_www_name);
- }
- if ($redirect_direction === 'www' && ! str($host)->startsWith('www.')) {
- $labels = $labels->merge($redirect_to_www);
- $middlewares->push($to_www_name);
- }
- $middlewares_from_labels->each(function ($middleware_name) use ($middlewares) {
- $middlewares->push($middleware_name);
- });
- if ($middlewares->isNotEmpty()) {
- $middlewares = $middlewares->join(',');
- $labels->push("traefik.http.routers.{$https_label}.middlewares={$middlewares}");
- }
- } else {
- $middlewares = collect([]);
- if ($is_gzip_enabled) {
- $middlewares->push('gzip');
- }
- if (str($image)->contains('ghost')) {
- $middlewares->push("redir-ghost-{$uuid}");
- }
- if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) {
- $labels = $labels->merge($redirect_to_non_www);
- $middlewares->push($to_non_www_name);
- }
- if ($redirect_direction === 'www' && ! str($host)->startsWith('www.')) {
- $labels = $labels->merge($redirect_to_www);
- $middlewares->push($to_www_name);
- }
- $middlewares_from_labels->each(function ($middleware_name) use ($middlewares) {
- $middlewares->push($middleware_name);
- });
- if ($middlewares->isNotEmpty()) {
- $middlewares = $middlewares->join(',');
- $labels->push("traefik.http.routers.{$https_label}.middlewares={$middlewares}");
- }
- }
- $labels->push("traefik.http.routers.{$https_label}.tls=true");
- $labels->push("traefik.http.routers.{$https_label}.tls.certresolver=letsencrypt");
-
- // Set labels for http (redirect to https)
- $labels->push("traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)");
- $labels->push("traefik.http.routers.{$http_label}.entryPoints=http");
- if ($port) {
- $labels->push("traefik.http.services.{$http_label}.loadbalancer.server.port=$port");
- $labels->push("traefik.http.routers.{$http_label}.service={$http_label}");
- }
- if ($is_force_https_enabled) {
- $labels->push("traefik.http.routers.{$http_label}.middlewares=redirect-to-https");
- }
- } else {
- // Set labels for http
- $labels->push("traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)");
- $labels->push("traefik.http.routers.{$http_label}.entryPoints=http");
- if ($port) {
- $labels->push("traefik.http.services.{$http_label}.loadbalancer.server.port=$port");
- $labels->push("traefik.http.routers.{$http_label}.service={$http_label}");
- }
- if ($path !== '/') {
- $middlewares = collect([]);
- if ($is_stripprefix_enabled && ! str($image)->contains('ghost')) {
- $labels->push("traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}");
- $middlewares->push("{$http_label}-stripprefix");
- }
- if ($is_gzip_enabled) {
- $middlewares->push('gzip');
- }
- if (str($image)->contains('ghost')) {
- $middlewares->push("redir-ghost-{$uuid}");
- }
- if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) {
- $labels = $labels->merge($redirect_to_non_www);
- $middlewares->push($to_non_www_name);
- }
- if ($redirect_direction === 'www' && ! str($host)->startsWith('www.')) {
- $labels = $labels->merge($redirect_to_www);
- $middlewares->push($to_www_name);
- }
- $middlewares_from_labels->each(function ($middleware_name) use ($middlewares) {
- $middlewares->push($middleware_name);
- });
- if ($middlewares->isNotEmpty()) {
- $middlewares = $middlewares->join(',');
- $labels->push("traefik.http.routers.{$http_label}.middlewares={$middlewares}");
- }
- } else {
- $middlewares = collect([]);
- if ($is_gzip_enabled) {
- $middlewares->push('gzip');
- }
- if (str($image)->contains('ghost')) {
- $middlewares->push("redir-ghost-{$uuid}");
- }
- if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) {
- $labels = $labels->merge($redirect_to_non_www);
- $middlewares->push($to_non_www_name);
- }
- if ($redirect_direction === 'www' && ! str($host)->startsWith('www.')) {
- $labels = $labels->merge($redirect_to_www);
- $middlewares->push($to_www_name);
- }
- $middlewares_from_labels->each(function ($middleware_name) use ($middlewares) {
- $middlewares->push($middleware_name);
- });
- if ($middlewares->isNotEmpty()) {
- $middlewares = $middlewares->join(',');
- $labels->push("traefik.http.routers.{$http_label}.middlewares={$middlewares}");
- }
- }
- }
- } catch (\Throwable) {
- continue;
- }
- }
-
- return $labels->sort();
-}
-function generateLabelsApplication(Application $application, ?ApplicationPreview $preview = null): array
-{
- $ports = $application->settings->is_static ? [80] : $application->ports_exposes_array;
- $onlyPort = null;
- if (count($ports) > 0) {
- $onlyPort = $ports[0];
- }
- $pull_request_id = data_get($preview, 'pull_request_id', 0);
- $appUuid = $application->uuid;
- if ($pull_request_id !== 0) {
- $appUuid = $appUuid.'-pr-'.$pull_request_id;
- }
- $labels = collect([]);
- if ($pull_request_id === 0) {
- if ($application->fqdn) {
- $domains = str(data_get($application, 'fqdn'))->explode(',');
- $shouldGenerateLabelsExactly = $application->destination->server->settings->generate_exact_labels;
- if ($shouldGenerateLabelsExactly) {
- switch ($application->destination->server->proxyType()) {
- case ProxyTypes::TRAEFIK->value:
- $labels = $labels->merge(fqdnLabelsForTraefik(
- uuid: $appUuid,
- domains: $domains,
- onlyPort: $onlyPort,
- is_force_https_enabled: $application->isForceHttpsEnabled(),
- is_gzip_enabled: $application->isGzipEnabled(),
- is_stripprefix_enabled: $application->isStripprefixEnabled(),
- redirect_direction: $application->redirect
- ));
- break;
- case ProxyTypes::CADDY->value:
- $labels = $labels->merge(fqdnLabelsForCaddy(
- network: $application->destination->network,
- uuid: $appUuid,
- domains: $domains,
- onlyPort: $onlyPort,
- is_force_https_enabled: $application->isForceHttpsEnabled(),
- is_gzip_enabled: $application->isGzipEnabled(),
- is_stripprefix_enabled: $application->isStripprefixEnabled(),
- redirect_direction: $application->redirect
- ));
- break;
- }
- } else {
- $labels = $labels->merge(fqdnLabelsForTraefik(
- uuid: $appUuid,
- domains: $domains,
- onlyPort: $onlyPort,
- is_force_https_enabled: $application->isForceHttpsEnabled(),
- is_gzip_enabled: $application->isGzipEnabled(),
- is_stripprefix_enabled: $application->isStripprefixEnabled(),
- redirect_direction: $application->redirect
- ));
- $labels = $labels->merge(fqdnLabelsForCaddy(
- network: $application->destination->network,
- uuid: $appUuid,
- domains: $domains,
- onlyPort: $onlyPort,
- is_force_https_enabled: $application->isForceHttpsEnabled(),
- is_gzip_enabled: $application->isGzipEnabled(),
- is_stripprefix_enabled: $application->isStripprefixEnabled(),
- redirect_direction: $application->redirect
- ));
- }
- }
- } else {
- if (data_get($preview, 'fqdn')) {
- $domains = str(data_get($preview, 'fqdn'))->explode(',');
- } else {
- $domains = collect([]);
- }
- $shouldGenerateLabelsExactly = $application->destination->server->settings->generate_exact_labels;
- if ($shouldGenerateLabelsExactly) {
- switch ($application->destination->server->proxyType()) {
- case ProxyTypes::TRAEFIK->value:
- $labels = $labels->merge(fqdnLabelsForTraefik(
- uuid: $appUuid,
- domains: $domains,
- onlyPort: $onlyPort,
- is_force_https_enabled: $application->isForceHttpsEnabled(),
- is_gzip_enabled: $application->isGzipEnabled(),
- is_stripprefix_enabled: $application->isStripprefixEnabled()
- ));
- break;
- case ProxyTypes::CADDY->value:
- $labels = $labels->merge(fqdnLabelsForCaddy(
- network: $application->destination->network,
- uuid: $appUuid,
- domains: $domains,
- onlyPort: $onlyPort,
- is_force_https_enabled: $application->isForceHttpsEnabled(),
- is_gzip_enabled: $application->isGzipEnabled(),
- is_stripprefix_enabled: $application->isStripprefixEnabled()
- ));
- break;
- }
- } else {
- $labels = $labels->merge(fqdnLabelsForTraefik(
- uuid: $appUuid,
- domains: $domains,
- onlyPort: $onlyPort,
- is_force_https_enabled: $application->isForceHttpsEnabled(),
- is_gzip_enabled: $application->isGzipEnabled(),
- is_stripprefix_enabled: $application->isStripprefixEnabled()
- ));
- $labels = $labels->merge(fqdnLabelsForCaddy(
- network: $application->destination->network,
- uuid: $appUuid,
- domains: $domains,
- onlyPort: $onlyPort,
- is_force_https_enabled: $application->isForceHttpsEnabled(),
- is_gzip_enabled: $application->isGzipEnabled(),
- is_stripprefix_enabled: $application->isStripprefixEnabled()
- ));
- }
- }
-
- return $labels->all();
-}
-
-function isDatabaseImage(?string $image = null)
-{
- if (is_null($image)) {
- return false;
- }
- $image = str($image);
- if ($image->contains(':')) {
- $image = str($image);
- } else {
- $image = str($image)->append(':latest');
- }
- $imageName = $image->before(':');
- if (collect(DATABASE_DOCKER_IMAGES)->contains($imageName)) {
- return true;
- }
-
- return false;
-}
-
-function convertDockerRunToCompose(?string $custom_docker_run_options = null)
-{
- $options = [];
- $compose_options = collect([]);
- preg_match_all('/(--\w+(?:-\w+)*)(?:\s|=)?([^\s-]+)?/', $custom_docker_run_options, $matches, PREG_SET_ORDER);
- $list_options = collect([
- '--cap-add',
- '--cap-drop',
- '--security-opt',
- '--sysctl',
- '--ulimit',
- '--device',
- '--shm-size',
- ]);
- $mapping = collect([
- '--cap-add' => 'cap_add',
- '--cap-drop' => 'cap_drop',
- '--security-opt' => 'security_opt',
- '--sysctl' => 'sysctls',
- '--device' => 'devices',
- '--init' => 'init',
- '--ulimit' => 'ulimits',
- '--privileged' => 'privileged',
- '--ip' => 'ip',
- '--shm-size' => 'shm_size',
- '--gpus' => 'gpus',
- ]);
- foreach ($matches as $match) {
- $option = $match[1];
- if ($option === '--gpus') {
- $regexForParsingDeviceIds = '/device=([0-9A-Za-z-,]+)/';
- preg_match($regexForParsingDeviceIds, $custom_docker_run_options, $device_matches);
- $value = $device_matches[1] ?? 'all';
- $options[$option][] = $value;
- $options[$option] = array_unique($options[$option]);
- }
- if (isset($match[2]) && $match[2] !== '') {
- $value = $match[2];
- $options[$option][] = $value;
- $options[$option] = array_unique($options[$option]);
- } else {
- $value = true;
- $options[$option] = $value;
- }
- }
- $options = collect($options);
- // Easily get mappings from https://github.com/composerize/composerize/blob/master/packages/composerize/src/mappings.js
- foreach ($options as $option => $value) {
- if (! data_get($mapping, $option)) {
- continue;
- }
- if ($option === '--ulimit') {
- $ulimits = collect([]);
- collect($value)->map(function ($ulimit) use ($ulimits) {
- $ulimit = explode('=', $ulimit);
- $type = $ulimit[0];
- $limits = explode(':', $ulimit[1]);
- if (count($limits) == 2) {
- $soft_limit = $limits[0];
- $hard_limit = $limits[1];
- $ulimits->put($type, [
- 'soft' => $soft_limit,
- 'hard' => $hard_limit,
- ]);
- } else {
- $soft_limit = $ulimit[1];
- $ulimits->put($type, [
- 'soft' => $soft_limit,
- ]);
- }
- });
- $compose_options->put($mapping[$option], $ulimits);
- } elseif ($option === '--shm-size') {
- if (! is_null($value) && is_array($value) && count($value) > 0) {
- $compose_options->put($mapping[$option], $value[0]);
- }
- } elseif ($option === '--gpus') {
- $payload = [
- 'driver' => 'nvidia',
- 'capabilities' => ['gpu'],
- ];
- if (! is_null($value) && is_array($value) && count($value) > 0) {
- if (str($value[0]) != 'all') {
- if (str($value[0])->contains(',')) {
- $payload['device_ids'] = str($value[0])->explode(',')->toArray();
- } else {
- $payload['device_ids'] = [$value[0]];
- }
- }
- }
- $compose_options->put('deploy', [
- 'resources' => [
- 'reservations' => [
- 'devices' => [$payload],
- ],
- ],
- ]);
- } else {
- if ($list_options->contains($option)) {
- if ($compose_options->has($mapping[$option])) {
- $compose_options->put($mapping[$option], $options->get($mapping[$option]).','.$value);
- } else {
- $compose_options->put($mapping[$option], $value);
- }
-
- continue;
- } else {
- $compose_options->put($mapping[$option], $value);
-
- continue;
- }
- $compose_options->forget($option);
- }
- }
-
- return $compose_options->toArray();
-}
-
-function generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker_compose, $container_name, $network)
-{
- $ipv4 = data_get($docker_run_options, 'ip.0');
- $ipv6 = data_get($docker_run_options, 'ip6.0');
- data_forget($docker_run_options, 'ip');
- data_forget($docker_run_options, 'ip6');
- if ($ipv4 || $ipv6) {
- data_forget($docker_compose['services'][$container_name], 'networks');
- }
- if ($ipv4) {
- $docker_compose['services'][$container_name]['networks'][$network]['ipv4_address'] = $ipv4;
- }
- if ($ipv6) {
- $docker_compose['services'][$container_name]['networks'][$network]['ipv6_address'] = $ipv6;
- }
- $docker_compose['services'][$container_name] = array_merge_recursive($docker_compose['services'][$container_name], $docker_run_options);
-
- return $docker_compose;
-}
-
-function validateComposeFile(string $compose, int $server_id): string|Throwable
-{
- $uuid = Str::random(18);
- $server = Server::ownedByCurrentTeam()->find($server_id);
- try {
- if (! $server) {
- throw new \Exception('Server not found');
- }
- $base64_compose = base64_encode($compose);
- instant_remote_process([
- "echo {$base64_compose} | base64 -d | tee /tmp/{$uuid}.yml > /dev/null",
- "chmod 600 /tmp/{$uuid}.yml",
- "docker compose -f /tmp/{$uuid}.yml config --no-interpolate --no-path-resolution -q",
- "rm /tmp/{$uuid}.yml",
- ], $server);
-
- return 'OK';
- } catch (\Throwable $e) {
- return $e->getMessage();
- } finally {
- if (filled($server)) {
- instant_remote_process([
- "rm /tmp/{$uuid}.yml",
- ], $server, throwError: false);
- }
- }
-}
-
-function getContainerLogs(Server $server, string $container_id, int $lines = 100): string
-{
- if ($server->isSwarm()) {
- $output = instant_remote_process([
- "docker service logs -n {$lines} {$container_id}",
- ], $server);
- } else {
- $output = instant_remote_process([
- "docker logs -n {$lines} {$container_id}",
- ], $server);
- }
-
- $output .= removeAnsiColors($output);
-
- return $output;
-}
-
-function escapeEnvVariables($value)
-{
- $search = ['\\', "\r", "\t", "\x0", '"', "'"];
- $replace = ['\\\\', '\\r', '\\t', '\\0', '\"', "\'"];
-
- return str_replace($search, $replace, $value);
-}
-function escapeDollarSign($value)
-{
- $search = ['$'];
- $replace = ['$$'];
-
- return str_replace($search, $replace, $value);
-}
diff --git a/bootstrap/helpers/github.php b/bootstrap/helpers/github.php
deleted file mode 100644
index 3a3f6e7b25..0000000000
--- a/bootstrap/helpers/github.php
+++ /dev/null
@@ -1,131 +0,0 @@
-api_url}/zen");
- $serverTime = CarbonImmutable::now()->setTimezone('UTC');
- $githubTime = Carbon::parse($response->header('date'));
- $timeDiff = abs($serverTime->diffInSeconds($githubTime));
-
- if ($timeDiff > 50) {
- throw new \Exception(
- 'System time is out of sync with GitHub API time: '.
- '- System time: '.$serverTime->format('Y-m-d H:i:s').' UTC '.
- '- GitHub time: '.$githubTime->format('Y-m-d H:i:s').' UTC '.
- '- Difference: '.$timeDiff.' seconds '.
- 'Please synchronize your system clock.'
- );
- }
-
- $signingKey = InMemory::plainText($source->privateKey->private_key);
- $algorithm = new Sha256;
- $tokenBuilder = (new Builder(new JoseEncoder, ChainedFormatter::default()));
- $now = CarbonImmutable::now()->setTimezone('UTC');
- $now = $now->setTime($now->format('H'), $now->format('i'), $now->format('s'));
-
- $jwt = $tokenBuilder
- ->issuedBy($source->app_id)
- ->issuedAt($now->modify('-1 minute'))
- ->expiresAt($now->modify('+8 minutes'))
- ->getToken($algorithm, $signingKey)
- ->toString();
-
- return match ($type) {
- 'jwt' => $jwt,
- 'installation' => (function () use ($source, $jwt) {
- $response = Http::withHeaders([
- 'Authorization' => "Bearer $jwt",
- 'Accept' => 'application/vnd.github.machine-man-preview+json',
- ])->post("{$source->api_url}/app/installations/{$source->installation_id}/access_tokens");
-
- if (! $response->successful()) {
- $error = data_get($response->json(), 'message', 'no error message found');
- throw new RuntimeException("Failed to get installation token for {$source->name} with error: ".$error);
- }
-
- return $response->json()['token'];
- })(),
- default => throw new \InvalidArgumentException("Unsupported token type: {$type}")
- };
-}
-
-function generateGithubInstallationToken(GithubApp $source)
-{
- return generateGithubToken($source, 'installation');
-}
-
-function generateGithubJwt(GithubApp $source)
-{
- return generateGithubToken($source, 'jwt');
-}
-
-function githubApi(GithubApp|GitlabApp|null $source, string $endpoint, string $method = 'get', ?array $data = null, bool $throwError = true)
-{
- if (is_null($source)) {
- throw new \Exception('Source is required for API calls');
- }
-
- if ($source->getMorphClass() !== GithubApp::class) {
- throw new \InvalidArgumentException("Unsupported source type: {$source->getMorphClass()}");
- }
-
- if ($source->is_public) {
- $response = Http::GitHub($source->api_url)->$method($endpoint);
- } else {
- $token = generateGithubInstallationToken($source);
- if ($data && in_array(strtolower($method), ['post', 'patch', 'put'])) {
- $response = Http::GitHub($source->api_url, $token)->$method($endpoint, $data);
- } else {
- $response = Http::GitHub($source->api_url, $token)->$method($endpoint);
- }
- }
-
- if (! $response->successful() && $throwError) {
- $resetTime = Carbon::parse((int) $response->header('X-RateLimit-Reset'))->format('Y-m-d H:i:s');
- $errorMessage = data_get($response->json(), 'message', 'no error message found');
- $remainingCalls = $response->header('X-RateLimit-Remaining', '0');
-
- throw new \Exception(
- 'GitHub API call failed: '.
- "Error: {$errorMessage} ".
- 'Rate Limit Status: '.
- "- Remaining Calls: {$remainingCalls} ".
- "- Reset Time: {$resetTime} UTC"
- );
- }
-
- return [
- 'rate_limit_remaining' => $response->header('X-RateLimit-Remaining'),
- 'rate_limit_reset' => $response->header('X-RateLimit-Reset'),
- 'data' => collect($response->json()),
- ];
-}
-
-function getInstallationPath(GithubApp $source)
-{
- $github = GithubApp::where('uuid', $source->uuid)->first();
- $name = str(Str::kebab($github->name));
- $installation_path = $github->html_url === 'https://github.com' ? 'apps' : 'github-apps';
-
- return "$github->html_url/$installation_path/$name/installations/new";
-}
-
-function getPermissionsPath(GithubApp $source)
-{
- $github = GithubApp::where('uuid', $source->uuid)->first();
- $name = str(Str::kebab($github->name));
-
- return "$github->html_url/settings/apps/$name/permissions";
-}
diff --git a/bootstrap/helpers/notifications.php b/bootstrap/helpers/notifications.php
deleted file mode 100644
index b0345df7ed..0000000000
--- a/bootstrap/helpers/notifications.php
+++ /dev/null
@@ -1,100 +0,0 @@
-smtp_enabled || $settings->resend_enabled;
-}
-
-function send_internal_notification(string $message): void
-{
- try {
- $team = Team::find(0);
- $team?->notify(new GeneralNotification($message));
- } catch (\Throwable $e) {
- ray($e->getMessage());
- }
-}
-
-function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null): void
-{
- $settings = instanceSettings();
- $type = set_transanctional_email_settings($settings);
- if (blank($type)) {
- throw new Exception('No email settings found.');
- }
- if ($cc) {
- Mail::send(
- [],
- [],
- fn (Message $message) => $message
- ->to($email)
- ->replyTo($email)
- ->cc($cc)
- ->subject($mail->subject)
- ->html((string) $mail->render())
- );
- } else {
- Mail::send(
- [],
- [],
- fn (Message $message) => $message
- ->to($email)
- ->subject($mail->subject)
- ->html((string) $mail->render())
- );
- }
-}
-
-function set_transanctional_email_settings(?InstanceSettings $settings = null): ?string // returns null|resend|smtp and defaults to array based on mail.php config
-{
- if (! $settings) {
- $settings = instanceSettings();
- }
- if (! data_get($settings, 'smtp_enabled') && ! data_get($settings, 'resend_enabled')) {
- return null;
- }
-
- if (data_get($settings, 'resend_enabled')) {
- config()->set('mail.default', 'resend');
- config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
- config()->set('mail.from.name', data_get($settings, 'smtp_from_name'));
- config()->set('resend.api_key', data_get($settings, 'resend_api_key'));
-
- return 'resend';
- }
-
- $encryption = match (strtolower(data_get($settings, 'smtp_encryption'))) {
- 'starttls' => null,
- 'tls' => 'tls',
- 'none' => null,
- default => null,
- };
-
- if (data_get($settings, 'smtp_enabled')) {
- config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
- config()->set('mail.from.name', data_get($settings, 'smtp_from_name'));
- config()->set('mail.default', 'smtp');
- config()->set('mail.mailers.smtp', [
- 'transport' => 'smtp',
- 'host' => data_get($settings, 'smtp_host'),
- 'port' => data_get($settings, 'smtp_port'),
- 'encryption' => $encryption,
- 'username' => data_get($settings, 'smtp_username'),
- 'password' => data_get($settings, 'smtp_password'),
- 'timeout' => data_get($settings, 'smtp_timeout'),
- 'local_domain' => null,
- 'auto_tls' => data_get($settings, 'smtp_encryption') === 'none' ? '0' : '', // If encryption is "none", it will not try to upgrade to TLS via StartTLS to make sure it is unencrypted.
- ]);
-
- return 'smtp';
- }
-}
diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php
deleted file mode 100644
index 714358e37f..0000000000
--- a/bootstrap/helpers/proxy.php
+++ /dev/null
@@ -1,271 +0,0 @@
-isFunctional()) {
- return collect();
- }
- $proxyType = $server->proxyType();
- if (is_null($proxyType) || $proxyType === 'NONE') {
- return collect();
- }
- $networks = instant_remote_process(['docker inspect --format="{{json .NetworkSettings.Networks }}" coolify-proxy'], $server, false);
-
- return collect($networks)->map(function ($network) {
- return collect(json_decode($network))->keys();
- })->flatten()->unique();
-}
-function collectDockerNetworksByServer(Server $server)
-{
- $allNetworks = collect([]);
- if ($server->isSwarm()) {
- $networks = collect($server->swarmDockers)->map(function ($docker) {
- return $docker['network'];
- });
- } else {
- // Standalone networks
- $networks = collect($server->standaloneDockers)->map(function ($docker) {
- return $docker['network'];
- });
- }
- $allNetworks = $allNetworks->merge($networks);
- // Service networks
- foreach ($server->services()->get() as $service) {
- if ($service->isRunning()) {
- $networks->push($service->networks());
- }
- $allNetworks->push($service->networks());
- }
- // Docker compose based apps
- $docker_compose_apps = $server->dockerComposeBasedApplications();
- foreach ($docker_compose_apps as $app) {
- if ($app->isRunning()) {
- $networks->push($app->uuid);
- }
- $allNetworks->push($app->uuid);
- }
- // Docker compose based preview deployments
- $docker_compose_previews = $server->dockerComposeBasedPreviewDeployments();
- foreach ($docker_compose_previews as $preview) {
- if (! $preview->isRunning()) {
- continue;
- }
- $pullRequestId = $preview->pull_request_id;
- $applicationId = $preview->application_id;
- $application = Application::find($applicationId);
- if (! $application) {
- continue;
- }
- $network = "{$application->uuid}-{$pullRequestId}";
- $networks->push($network);
- $allNetworks->push($network);
- }
- $networks = collect($networks)->flatten()->unique();
- $allNetworks = $allNetworks->flatten()->unique();
- if ($server->isSwarm()) {
- if ($networks->count() === 0) {
- $networks = collect(['coolify-overlay']);
- $allNetworks = collect(['coolify-overlay']);
- }
- } else {
- if ($networks->count() === 0) {
- $networks = collect(['coolify']);
- $allNetworks = collect(['coolify']);
- }
- }
-
- return [
- 'networks' => $networks,
- 'allNetworks' => $allNetworks,
- ];
-}
-function connectProxyToNetworks(Server $server)
-{
- ['networks' => $networks] = collectDockerNetworksByServer($server);
- if ($server->isSwarm()) {
- $commands = $networks->map(function ($network) {
- return [
- "echo 'Connecting coolify-proxy to $network network...'",
- "docker network ls --format '{{.Name}}' | grep '^$network$' >/dev/null || docker network create --driver overlay --attachable $network >/dev/null",
- "docker network connect $network coolify-proxy >/dev/null 2>&1 || true",
- "echo 'Successfully connected coolify-proxy to $network network.'",
- "echo 'Proxy started and configured successfully!'",
- ];
- });
- } else {
- $commands = $networks->map(function ($network) {
- return [
- "echo 'Connecting coolify-proxy to $network network...'",
- "docker network ls --format '{{.Name}}' | grep '^$network$' >/dev/null || docker network create --attachable $network >/dev/null",
- "docker network connect $network coolify-proxy >/dev/null 2>&1 || true",
- "echo 'Successfully connected coolify-proxy to $network network.'",
- "echo 'Proxy started and configured successfully!'",
- ];
- });
- }
-
- return $commands->flatten();
-}
-function generate_default_proxy_configuration(Server $server)
-{
- $proxy_path = $server->proxyPath();
- $proxy_type = $server->proxyType();
-
- if ($server->isSwarm()) {
- $networks = collect($server->swarmDockers)->map(function ($docker) {
- return $docker['network'];
- })->unique();
- if ($networks->count() === 0) {
- $networks = collect(['coolify-overlay']);
- }
- } else {
- $networks = collect($server->standaloneDockers)->map(function ($docker) {
- return $docker['network'];
- })->unique();
- if ($networks->count() === 0) {
- $networks = collect(['coolify']);
- }
- }
-
- $array_of_networks = collect([]);
- $networks->map(function ($network) use ($array_of_networks) {
- $array_of_networks[$network] = [
- 'external' => true,
- ];
- });
- if ($proxy_type === ProxyTypes::TRAEFIK->value) {
- $labels = [
- 'traefik.enable=true',
- 'traefik.http.routers.traefik.entrypoints=http',
- 'traefik.http.routers.traefik.service=api@internal',
- 'traefik.http.services.traefik.loadbalancer.server.port=8080',
- 'coolify.managed=true',
- 'coolify.proxy=true',
- ];
- $config = [
- 'name' => 'coolify-proxy',
- 'networks' => $array_of_networks->toArray(),
- 'services' => [
- 'traefik' => [
- 'container_name' => 'coolify-proxy',
- 'image' => 'traefik:v3.1',
- 'restart' => RESTART_MODE,
- 'extra_hosts' => [
- 'host.docker.internal:host-gateway',
- ],
- 'networks' => $networks->toArray(),
- 'ports' => [
- '80:80',
- '443:443',
- '443:443/udp',
- '8080:8080',
- ],
- 'healthcheck' => [
- 'test' => 'wget -qO- http://localhost:80/ping || exit 1',
- 'interval' => '4s',
- 'timeout' => '2s',
- 'retries' => 5,
- ],
- 'volumes' => [
- '/var/run/docker.sock:/var/run/docker.sock:ro',
-
- ],
- 'command' => [
- '--ping=true',
- '--ping.entrypoint=http',
- '--api.dashboard=true',
- '--entrypoints.http.address=:80',
- '--entrypoints.https.address=:443',
- '--entrypoints.http.http.encodequerysemicolons=true',
- '--entryPoints.http.http2.maxConcurrentStreams=250',
- '--entrypoints.https.http.encodequerysemicolons=true',
- '--entryPoints.https.http2.maxConcurrentStreams=250',
- '--entrypoints.https.http3',
- '--providers.file.directory=/traefik/dynamic/',
- '--providers.file.watch=true',
- '--certificatesresolvers.letsencrypt.acme.httpchallenge=true',
- '--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http',
- '--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json',
- ],
- 'labels' => $labels,
- ],
- ],
- ];
- if (isDev()) {
- $config['services']['traefik']['command'][] = '--api.insecure=true';
- $config['services']['traefik']['command'][] = '--log.level=debug';
- $config['services']['traefik']['command'][] = '--accesslog.filepath=/traefik/access.log';
- $config['services']['traefik']['command'][] = '--accesslog.bufferingsize=100';
- $config['services']['traefik']['volumes'][] = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/:/traefik';
- } else {
- $config['services']['traefik']['command'][] = '--api.insecure=false';
- $config['services']['traefik']['volumes'][] = "{$proxy_path}:/traefik";
- }
- if ($server->isSwarm()) {
- data_forget($config, 'services.traefik.container_name');
- data_forget($config, 'services.traefik.restart');
- data_forget($config, 'services.traefik.labels');
-
- $config['services']['traefik']['command'][] = '--providers.swarm.endpoint=unix:///var/run/docker.sock';
- $config['services']['traefik']['command'][] = '--providers.swarm.exposedbydefault=false';
- $config['services']['traefik']['deploy'] = [
- 'labels' => $labels,
- 'placement' => [
- 'constraints' => [
- 'node.role==manager',
- ],
- ],
- ];
- } else {
- $config['services']['traefik']['command'][] = '--providers.docker=true';
- $config['services']['traefik']['command'][] = '--providers.docker.exposedbydefault=false';
- }
- } elseif ($proxy_type === 'CADDY') {
- $config = [
- 'networks' => $array_of_networks->toArray(),
- 'services' => [
- 'caddy' => [
- 'container_name' => 'coolify-proxy',
- 'image' => 'lucaslorentz/caddy-docker-proxy:2.8-alpine',
- 'restart' => RESTART_MODE,
- 'extra_hosts' => [
- 'host.docker.internal:host-gateway',
- ],
- 'environment' => [
- 'CADDY_DOCKER_POLLING_INTERVAL=5s',
- 'CADDY_DOCKER_CADDYFILE_PATH=/dynamic/Caddyfile',
- ],
- 'networks' => $networks->toArray(),
- 'ports' => [
- '80:80',
- '443:443',
- '443:443/udp',
- ],
- 'labels' => [
- 'coolify.managed=true',
- 'coolify.proxy=true',
- ],
- 'volumes' => [
- '/var/run/docker.sock:/var/run/docker.sock:ro',
- "{$proxy_path}/dynamic:/dynamic",
- "{$proxy_path}/config:/config",
- "{$proxy_path}/data:/data",
- ],
- ],
- ],
- ];
- } else {
- return null;
- }
-
- $config = Yaml::dump($config, 12, 2);
- SaveConfiguration::run($server, $config);
-
- return $config;
-}
diff --git a/bootstrap/helpers/remoteProcess.php b/bootstrap/helpers/remoteProcess.php
deleted file mode 100644
index d1cb93d9af..0000000000
--- a/bootstrap/helpers/remoteProcess.php
+++ /dev/null
@@ -1,240 +0,0 @@
-value;
- $command = $command instanceof Collection ? $command->toArray() : $command;
-
- if ($server->isNonRoot()) {
- $command = parseCommandsByLineForSudo(collect($command), $server);
- }
-
- $command_string = implode("\n", $command);
-
- if (Auth::check()) {
- $teams = Auth::user()->teams->pluck('id');
- if (! $teams->contains($server->team_id) && ! $teams->contains(0)) {
- throw new \Exception('User is not part of the team that owns this server');
- }
- }
-
- SshMultiplexingHelper::ensureMultiplexedConnection($server);
-
- return resolve(PrepareCoolifyTask::class, [
- 'remoteProcessArgs' => new CoolifyTaskArgs(
- server_uuid: $server->uuid,
- command: $command_string,
- type: $type,
- type_uuid: $type_uuid,
- model: $model,
- ignore_errors: $ignore_errors,
- call_event_on_finish: $callEventOnFinish,
- call_event_data: $callEventData,
- ),
- ])();
-}
-
-function instant_scp(string $source, string $dest, Server $server, $throwError = true)
-{
- $scp_command = SshMultiplexingHelper::generateScpCommand($server, $source, $dest);
- $process = Process::timeout(config('constants.ssh.command_timeout'))->run($scp_command);
- $output = trim($process->output());
- $exitCode = $process->exitCode();
- if ($exitCode !== 0) {
- return $throwError ? excludeCertainErrors($process->errorOutput(), $exitCode) : null;
- }
-
- return $output === 'null' ? null : $output;
-}
-
-function instant_remote_process_with_timeout(Collection|array $command, Server $server, bool $throwError = true, bool $no_sudo = false): ?string
-{
- $command = $command instanceof Collection ? $command->toArray() : $command;
- if ($server->isNonRoot() && ! $no_sudo) {
- $command = parseCommandsByLineForSudo(collect($command), $server);
- }
- $command_string = implode("\n", $command);
-
- // $start_time = microtime(true);
- $sshCommand = SshMultiplexingHelper::generateSshCommand($server, $command_string);
- $process = Process::timeout(30)->run($sshCommand);
- // $end_time = microtime(true);
-
- // $execution_time = ($end_time - $start_time) * 1000; // Convert to milliseconds
- // ray('SSH command execution time:', $execution_time.' ms')->orange();
-
- $output = trim($process->output());
- $exitCode = $process->exitCode();
-
- if ($exitCode !== 0) {
- return $throwError ? excludeCertainErrors($process->errorOutput(), $exitCode) : null;
- }
-
- return $output === 'null' ? null : $output;
-}
-function instant_remote_process(Collection|array $command, Server $server, bool $throwError = true, bool $no_sudo = false): ?string
-{
- $command = $command instanceof Collection ? $command->toArray() : $command;
- if ($server->isNonRoot() && ! $no_sudo) {
- $command = parseCommandsByLineForSudo(collect($command), $server);
- }
- $command_string = implode("\n", $command);
-
- // $start_time = microtime(true);
- $sshCommand = SshMultiplexingHelper::generateSshCommand($server, $command_string);
- $process = Process::timeout(config('constants.ssh.command_timeout'))->run($sshCommand);
- // $end_time = microtime(true);
-
- // $execution_time = ($end_time - $start_time) * 1000; // Convert to milliseconds
- // ray('SSH command execution time:', $execution_time.' ms')->orange();
-
- $output = trim($process->output());
- $exitCode = $process->exitCode();
-
- if ($exitCode !== 0) {
- return $throwError ? excludeCertainErrors($process->errorOutput(), $exitCode) : null;
- }
-
- return $output === 'null' ? null : $output;
-}
-
-function excludeCertainErrors(string $errorOutput, ?int $exitCode = null)
-{
- $ignoredErrors = collect([
- 'Permission denied (publickey',
- 'Could not resolve hostname',
- ]);
- $ignored = $ignoredErrors->contains(fn ($error) => Str::contains($errorOutput, $error));
- if ($ignored) {
- // TODO: Create new exception and disable in sentry
- throw new \RuntimeException($errorOutput, $exitCode);
- }
- throw new \RuntimeException($errorOutput, $exitCode);
-}
-
-function decode_remote_command_output(?ApplicationDeploymentQueue $application_deployment_queue = null): Collection
-{
- if (is_null($application_deployment_queue)) {
- return collect([]);
- }
- $application = Application::find(data_get($application_deployment_queue, 'application_id'));
- $is_debug_enabled = data_get($application, 'settings.is_debug_enabled');
- try {
- $decoded = json_decode(
- data_get($application_deployment_queue, 'logs'),
- associative: true,
- flags: JSON_THROW_ON_ERROR
- );
- } catch (\JsonException) {
- return collect([]);
- }
- $seenCommands = collect();
- $formatted = collect($decoded);
- if (! $is_debug_enabled) {
- $formatted = $formatted->filter(fn ($i) => $i['hidden'] === false ?? false);
- }
-
- return $formatted
- ->sortBy(fn ($i) => data_get($i, 'order'))
- ->map(function ($i) {
- data_set($i, 'timestamp', Carbon::parse(data_get($i, 'timestamp'))->format('Y-M-d H:i:s.u'));
-
- return $i;
- })
- ->reduce(function ($deploymentLogLines, $logItem) use ($seenCommands) {
- $command = data_get($logItem, 'command');
- $isStderr = data_get($logItem, 'type') === 'stderr';
- $isNewCommand = ! is_null($command) && ! $seenCommands->first(function ($seenCommand) use ($logItem) {
- return data_get($seenCommand, 'command') === data_get($logItem, 'command') && data_get($seenCommand, 'batch') === data_get($logItem, 'batch');
- });
-
- if ($isNewCommand) {
- $deploymentLogLines->push([
- 'line' => $command,
- 'timestamp' => data_get($logItem, 'timestamp'),
- 'stderr' => $isStderr,
- 'hidden' => data_get($logItem, 'hidden'),
- 'command' => true,
- ]);
-
- $seenCommands->push([
- 'command' => $command,
- 'batch' => data_get($logItem, 'batch'),
- ]);
- }
-
- $lines = explode(PHP_EOL, data_get($logItem, 'output'));
-
- foreach ($lines as $line) {
- $deploymentLogLines->push([
- 'line' => $line,
- 'timestamp' => data_get($logItem, 'timestamp'),
- 'stderr' => $isStderr,
- 'hidden' => data_get($logItem, 'hidden'),
- ]);
- }
-
- return $deploymentLogLines;
- }, collect());
-}
-
-function remove_iip($text)
-{
- $text = preg_replace('/x-access-token:.*?(?=@)/', 'x-access-token:'.REDACTED, $text);
-
- return preg_replace('/\x1b\[[0-9;]*m/', '', $text);
-}
-
-function refresh_server_connection(?PrivateKey $private_key = null)
-{
- if (is_null($private_key)) {
- return;
- }
- foreach ($private_key->servers as $server) {
- SshMultiplexingHelper::removeMuxFile($server);
- }
-}
-
-function checkRequiredCommands(Server $server)
-{
- $commands = collect(['jq', 'jc']);
- foreach ($commands as $command) {
- $commandFound = instant_remote_process(["docker run --rm --privileged --net=host --pid=host --ipc=host --volume /:/host busybox chroot /host bash -c 'command -v {$command}'"], $server, false);
- if ($commandFound) {
- continue;
- }
- try {
- instant_remote_process(["docker run --rm --privileged --net=host --pid=host --ipc=host --volume /:/host busybox chroot /host bash -c 'apt update && apt install -y {$command}'"], $server);
- } catch (\Throwable) {
- break;
- }
- $commandFound = instant_remote_process(["docker run --rm --privileged --net=host --pid=host --ipc=host --volume /:/host busybox chroot /host bash -c 'command -v {$command}'"], $server, false);
- if (! $commandFound) {
- break;
- }
- }
-}
diff --git a/bootstrap/helpers/services.php b/bootstrap/helpers/services.php
deleted file mode 100644
index cd99713a27..0000000000
--- a/bootstrap/helpers/services.php
+++ /dev/null
@@ -1,280 +0,0 @@
-before('}')->replaceFirst('$', '')->replaceFirst('{', '');
-}
-
-function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase|Application $oneService, bool $isInit = false)
-{
- try {
- if ($oneService->getMorphClass() === \App\Models\Application::class) {
- $workdir = $oneService->workdir();
- $server = $oneService->destination->server;
- } else {
- $workdir = $oneService->service->workdir();
- $server = $oneService->service->server;
- }
- $fileVolumes = $oneService->fileStorages()->get();
- $commands = collect([
- "mkdir -p $workdir > /dev/null 2>&1 || true",
- "cd $workdir",
- ]);
- instant_remote_process($commands, $server);
- foreach ($fileVolumes as $fileVolume) {
- $path = str(data_get($fileVolume, 'fs_path'));
- $content = data_get($fileVolume, 'content');
- if ($path->startsWith('.')) {
- $path = $path->after('.');
- $fileLocation = $workdir.$path;
- } else {
- $fileLocation = $path;
- }
- // Exists and is a file
- $isFile = instant_remote_process(["test -f $fileLocation && echo OK || echo NOK"], $server);
- // Exists and is a directory
- $isDir = instant_remote_process(["test -d $fileLocation && echo OK || echo NOK"], $server);
-
- if ($isFile === 'OK') {
- // If its a file & exists
- $filesystemContent = instant_remote_process(["cat $fileLocation"], $server);
- if ($fileVolume->is_based_on_git) {
- $fileVolume->content = $filesystemContent;
- }
- $fileVolume->is_directory = false;
- $fileVolume->save();
- } elseif ($isDir === 'OK') {
- // If its a directory & exists
- $fileVolume->content = null;
- $fileVolume->is_directory = true;
- $fileVolume->save();
- } elseif ($isFile === 'NOK' && $isDir === 'NOK' && ! $fileVolume->is_directory && $isInit && $content) {
- // Does not exists (no dir or file), not flagged as directory, is init, has content
- $fileVolume->content = $content;
- $fileVolume->is_directory = false;
- $fileVolume->save();
- $content = base64_encode($content);
- $dir = str($fileLocation)->dirname();
- instant_remote_process([
- "mkdir -p $dir",
- "echo '$content' | base64 -d | tee $fileLocation",
- ], $server);
- } elseif ($isFile === 'NOK' && $isDir === 'NOK' && $fileVolume->is_directory && $isInit) {
- // Does not exists (no dir or file), flagged as directory, is init
- $fileVolume->content = null;
- $fileVolume->is_directory = true;
- $fileVolume->save();
- instant_remote_process(["mkdir -p $fileLocation"], $server);
- } elseif ($isFile === 'NOK' && $isDir === 'NOK' && ! $fileVolume->is_directory && $isInit && is_null($content)) {
- // Does not exists (no dir or file), not flagged as directory, is init, has no content => create directory
- $fileVolume->content = null;
- $fileVolume->is_directory = true;
- $fileVolume->save();
- instant_remote_process(["mkdir -p $fileLocation"], $server);
- }
- }
- } catch (\Throwable $e) {
- return handleError($e);
- }
-}
-function updateCompose(ServiceApplication|ServiceDatabase $resource)
-{
- try {
- $name = data_get($resource, 'name');
- $dockerComposeRaw = data_get($resource, 'service.docker_compose_raw');
- if (! $dockerComposeRaw) {
- throw new \Exception('No compose file found or not a valid YAML file.');
- }
- $dockerCompose = Yaml::parse($dockerComposeRaw);
-
- // Switch Image
- $updatedImage = data_get_str($resource, 'image');
- $currentImage = data_get_str($dockerCompose, "services.{$name}.image");
- if ($currentImage !== $updatedImage) {
- data_set($dockerCompose, "services.{$name}.image", $updatedImage->value());
- $dockerComposeRaw = Yaml::dump($dockerCompose, 10, 2);
- $resource->service->docker_compose_raw = $dockerComposeRaw;
- $resource->service->save();
- $resource->image = $updatedImage;
- $resource->save();
- }
- if ($resource->fqdn) {
- $resourceFqdns = str($resource->fqdn)->explode(',');
- if ($resourceFqdns->count() === 1) {
- $resourceFqdns = $resourceFqdns->first();
- $variableName = 'SERVICE_FQDN_'.str($resource->name)->upper()->replace('-', '');
- $generatedEnv = EnvironmentVariable::where('resourceable_type', Service::class)
- ->where('resourceable_id', $resource->service_id)
- ->where('key', $variableName)
- ->first();
- $fqdn = Url::fromString($resourceFqdns);
- $port = $fqdn->getPort();
- $path = $fqdn->getPath();
- $fqdn = $fqdn->getScheme().'://'.$fqdn->getHost();
- if ($generatedEnv) {
- if ($path === '/') {
- $generatedEnv->value = $fqdn;
- } else {
- $generatedEnv->value = $fqdn.$path;
- }
- $generatedEnv->save();
- }
- if ($port) {
- $variableName = $variableName."_$port";
- $generatedEnv = EnvironmentVariable::where('resourceable_type', Service::class)
- ->where('resourceable_id', $resource->service_id)
- ->where('key', $variableName)
- ->first();
- if ($generatedEnv) {
- if ($path === '/') {
- $generatedEnv->value = $fqdn;
- } else {
- $generatedEnv->value = $fqdn.$path;
- }
- $generatedEnv->save();
- }
- }
- $variableName = 'SERVICE_URL_'.str($resource->name)->upper()->replace('-', '');
- $generatedEnv = EnvironmentVariable::where('resourceable_type', Service::class)
- ->where('resourceable_id', $resource->service_id)
- ->where('key', $variableName)
- ->first();
- $url = Url::fromString($fqdn);
- $port = $url->getPort();
- $path = $url->getPath();
- $url = $url->getHost();
- if ($generatedEnv) {
- $url = str($fqdn)->after('://');
- if ($path === '/') {
- $generatedEnv->value = $url;
- } else {
- $generatedEnv->value = $url.$path;
- }
- $generatedEnv->save();
- }
- if ($port) {
- $variableName = $variableName."_$port";
- $generatedEnv = EnvironmentVariable::where('resourceable_type', Service::class)
- ->where('resourceable_id', $resource->service_id)
- ->where('key', $variableName)
- ->first();
- if ($generatedEnv) {
- if ($path === '/') {
- $generatedEnv->value = $url;
- } else {
- $generatedEnv->value = $url.$path;
- }
- $generatedEnv->save();
- }
- }
- } elseif ($resourceFqdns->count() > 1) {
- foreach ($resourceFqdns as $fqdn) {
- $host = Url::fromString($fqdn);
- $port = $host->getPort();
- $url = $host->getHost();
- $path = $host->getPath();
- $host = $host->getScheme().'://'.$host->getHost();
- if ($port) {
- $port_envs = EnvironmentVariable::where('resourceable_type', Service::class)
- ->where('resourceable_id', $resource->service_id)
- ->where('key', 'like', "SERVICE_FQDN_%_$port")
- ->get();
- foreach ($port_envs as $port_env) {
- $service_fqdn = str($port_env->key)->beforeLast('_')->after('SERVICE_FQDN_');
- $env = EnvironmentVariable::where('resourceable_type', Service::class)
- ->where('resourceable_id', $resource->service_id)
- ->where('key', 'SERVICE_FQDN_'.$service_fqdn)
- ->first();
- if ($env) {
- if ($path === '/') {
- $env->value = $host;
- } else {
- $env->value = $host.$path;
- }
- $env->save();
- }
- if ($path === '/') {
- $port_env->value = $host;
- } else {
- $port_env->value = $host.$path;
- }
- $port_env->save();
- }
- $port_envs_url = EnvironmentVariable::where('resourceable_type', Service::class)
- ->where('resourceable_id', $resource->service_id)
- ->where('key', 'like', "SERVICE_URL_%_$port")
- ->get();
- foreach ($port_envs_url as $port_env_url) {
- $service_url = str($port_env_url->key)->beforeLast('_')->after('SERVICE_URL_');
- $env = EnvironmentVariable::where('resourceable_type', Service::class)
- ->where('resourceable_id', $resource->service_id)
- ->where('key', 'SERVICE_URL_'.$service_url)
- ->first();
- if ($env) {
- if ($path === '/') {
- $env->value = $url;
- } else {
- $env->value = $url.$path;
- }
- $env->save();
- }
- if ($path === '/') {
- $port_env_url->value = $url;
- } else {
- $port_env_url->value = $url.$path;
- }
- $port_env_url->save();
- }
- } else {
- $variableName = 'SERVICE_FQDN_'.str($resource->name)->upper()->replace('-', '');
- $generatedEnv = EnvironmentVariable::where('resourceable_type', Service::class)
- ->where('resourceable_id', $resource->service_id)
- ->where('key', $variableName)
- ->first();
- $fqdn = Url::fromString($fqdn);
- $fqdn = $fqdn->getScheme().'://'.$fqdn->getHost().$fqdn->getPath();
- if ($generatedEnv) {
- $generatedEnv->value = $fqdn;
- $generatedEnv->save();
- }
- $variableName = 'SERVICE_URL_'.str($resource->name)->upper()->replace('-', '');
- $generatedEnv = EnvironmentVariable::where('resourceable_type', Service::class)
- ->where('resourceable_id', $resource->service_id)
- ->where('key', $variableName)
- ->first();
- $url = Url::fromString($fqdn);
- $url = $url->getHost().$url->getPath();
- if ($generatedEnv) {
- $url = str($fqdn)->after('://');
- $generatedEnv->value = $url;
- $generatedEnv->save();
- }
- }
- }
- }
- }
- } catch (\Throwable $e) {
- return handleError($e);
- }
-}
-function serviceKeys()
-{
- return get_service_templates()->keys();
-}
diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php
deleted file mode 100644
index db3085649a..0000000000
--- a/bootstrap/helpers/shared.php
+++ /dev/null
@@ -1,4139 +0,0 @@
-user()?->isInstanceAdmin() ?? false;
-}
-
-function currentTeam()
-{
- return Auth::user()?->currentTeam() ?? null;
-}
-
-function showBoarding(): bool
-{
- if (Auth::user()?->isMember()) {
- return false;
- }
-
- return currentTeam()->show_boarding ?? false;
-}
-function refreshSession(?Team $team = null): void
-{
- if (! $team) {
- if (Auth::user()->currentTeam()) {
- $team = Team::find(Auth::user()->currentTeam()->id);
- } else {
- $team = User::find(Auth::id())->teams->first();
- }
- }
- Cache::forget('team:'.Auth::id());
- Cache::remember('team:'.Auth::id(), 3600, function () use ($team) {
- return $team;
- });
- session(['currentTeam' => $team]);
-}
-function handleError(?Throwable $error = null, ?Livewire\Component $livewire = null, ?string $customErrorMessage = null)
-{
- if ($error instanceof TooManyRequestsException) {
- if (isset($livewire)) {
- return $livewire->dispatch('error', "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.");
- }
-
- return "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.";
- }
- if ($error instanceof UniqueConstraintViolationException) {
- if (isset($livewire)) {
- return $livewire->dispatch('error', 'Duplicate entry found. Please use a different name.');
- }
-
- return 'Duplicate entry found. Please use a different name.';
- }
-
- if ($error instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
- abort(404);
- }
-
- if ($error instanceof Throwable) {
- $message = $error->getMessage();
- } else {
- $message = null;
- }
- if ($customErrorMessage) {
- $message = $customErrorMessage.' '.$message;
- }
-
- if (isset($livewire)) {
- return $livewire->dispatch('error', $message);
- }
- throw new Exception($message);
-}
-function get_route_parameters(): array
-{
- return Route::current()->parameters();
-}
-
-function get_latest_sentinel_version(): string
-{
- try {
- $response = Http::get('https://cdn.coollabs.io/coolify/versions.json');
- $versions = $response->json();
-
- return data_get($versions, 'coolify.sentinel.version');
- } catch (\Throwable) {
- return '0.0.0';
- }
-}
-function get_latest_version_of_coolify(): string
-{
- try {
- $versions = File::get(base_path('versions.json'));
- $versions = json_decode($versions, true);
-
- return data_get($versions, 'coolify.v4.version');
- } catch (\Throwable $e) {
- ray($e->getMessage());
-
- return '0.0.0';
- }
-}
-
-function generate_random_name(?string $cuid = null): string
-{
- $generator = new \Nubs\RandomNameGenerator\All(
- [
- new \Nubs\RandomNameGenerator\Alliteration,
- ]
- );
- if (is_null($cuid)) {
- $cuid = new Cuid2;
- }
-
- return Str::kebab("{$generator->getName()}-$cuid");
-}
-function generateSSHKey(string $type = 'rsa')
-{
- if ($type === 'rsa') {
- $key = RSA::createKey();
-
- return [
- 'private' => $key->toString('PKCS1'),
- 'public' => $key->getPublicKey()->toString('OpenSSH', ['comment' => 'coolify-generated-ssh-key']),
- ];
- } elseif ($type === 'ed25519') {
- $key = EC::createKey('Ed25519');
-
- return [
- 'private' => $key->toString('OpenSSH'),
- 'public' => $key->getPublicKey()->toString('OpenSSH', ['comment' => 'coolify-generated-ssh-key']),
- ];
- }
- throw new Exception('Invalid key type');
-}
-function formatPrivateKey(string $privateKey)
-{
- $privateKey = trim($privateKey);
- if (! str_ends_with($privateKey, "\n")) {
- $privateKey .= "\n";
- }
-
- return $privateKey;
-}
-function generate_application_name(string $git_repository, string $git_branch, ?string $cuid = null): string
-{
- if (is_null($cuid)) {
- $cuid = new Cuid2;
- }
-
- return Str::kebab("$git_repository:$git_branch-$cuid");
-}
-
-function base_ip(): string
-{
- if (isDev()) {
- return 'localhost';
- }
- $settings = instanceSettings();
- if ($settings->public_ipv4) {
- return "$settings->public_ipv4";
- }
- if ($settings->public_ipv6) {
- return "$settings->public_ipv6";
- }
-
- return 'localhost';
-}
-function getFqdnWithoutPort(string $fqdn)
-{
- try {
- $url = Url::fromString($fqdn);
- $host = $url->getHost();
- $scheme = $url->getScheme();
- $path = $url->getPath();
-
- return "$scheme://$host$path";
- } catch (\Throwable) {
- return $fqdn;
- }
-}
-/**
- * If fqdn is set, return it, otherwise return public ip.
- */
-function base_url(bool $withPort = true): string
-{
- $settings = instanceSettings();
- if ($settings->fqdn) {
- return $settings->fqdn;
- }
- $port = config('app.port');
- if ($settings->public_ipv4) {
- if ($withPort) {
- if (isDev()) {
- return "http://localhost:$port";
- }
-
- return "http://$settings->public_ipv4:$port";
- }
- if (isDev()) {
- return 'http://localhost';
- }
-
- return "http://$settings->public_ipv4";
- }
- if ($settings->public_ipv6) {
- if ($withPort) {
- return "http://$settings->public_ipv6:$port";
- }
-
- return "http://$settings->public_ipv6";
- }
-
- return url('/');
-}
-
-function isSubscribed()
-{
- return isSubscriptionActive() || auth()->user()->isInstanceAdmin();
-}
-
-function isProduction(): bool
-{
- return ! isDev();
-}
-function isDev(): bool
-{
- return config('app.env') === 'local';
-}
-
-function isCloud(): bool
-{
- return ! config('constants.coolify.self_hosted');
-}
-
-function translate_cron_expression($expression_to_validate): string
-{
- if (isset(VALID_CRON_STRINGS[$expression_to_validate])) {
- return VALID_CRON_STRINGS[$expression_to_validate];
- }
-
- return $expression_to_validate;
-}
-function validate_cron_expression($expression_to_validate): bool
-{
- if (empty($expression_to_validate)) {
- return false;
- }
- $isValid = false;
- $expression = new CronExpression($expression_to_validate);
- $isValid = $expression->isValid();
-
- if (isset(VALID_CRON_STRINGS[$expression_to_validate])) {
- $isValid = true;
- }
-
- return $isValid;
-}
-
-function validate_timezone(string $timezone): bool
-{
- return in_array($timezone, timezone_identifiers_list());
-}
-
-function parseEnvFormatToArray($env_file_contents)
-{
- $env_array = [];
- $lines = explode("\n", $env_file_contents);
- foreach ($lines as $line) {
- if ($line === '' || substr($line, 0, 1) === '#') {
- continue;
- }
- $equals_pos = strpos($line, '=');
- if ($equals_pos !== false) {
- $key = substr($line, 0, $equals_pos);
- $value = substr($line, $equals_pos + 1);
- if (substr($value, 0, 1) === '"' && substr($value, -1) === '"') {
- $value = substr($value, 1, -1);
- } elseif (substr($value, 0, 1) === "'" && substr($value, -1) === "'") {
- $value = substr($value, 1, -1);
- }
- $env_array[$key] = $value;
- }
- }
-
- return $env_array;
-}
-
-function data_get_str($data, $key, $default = null): Stringable
-{
- $str = data_get($data, $key, $default) ?? $default;
-
- return str($str);
-}
-
-function generateFqdn(Server $server, string $random, bool $forceHttps = false): string
-{
- $wildcard = data_get($server, 'settings.wildcard_domain');
- if (is_null($wildcard) || $wildcard === '') {
- $wildcard = sslip($server);
- }
- $url = Url::fromString($wildcard);
- $host = $url->getHost();
- $path = $url->getPath() === '/' ? '' : $url->getPath();
- $scheme = $url->getScheme();
- if ($forceHttps) {
- $scheme = 'https';
- }
-
- return "$scheme://{$random}.$host$path";
-}
-function sslip(Server $server)
-{
- if (isDev() && $server->id === 0) {
- return 'http://127.0.0.1.sslip.io';
- }
- if ($server->ip === 'host.docker.internal') {
- $baseIp = base_ip();
-
- return "http://$baseIp.sslip.io";
- }
- // ipv6
- if (str($server->ip)->contains(':')) {
- $ipv6 = str($server->ip)->replace(':', '-');
-
- return "http://{$ipv6}.sslip.io";
- }
-
- return "http://{$server->ip}.sslip.io";
-}
-
-function get_service_templates(bool $force = false): Collection
-{
-
- if ($force) {
- try {
- $response = Http::retry(3, 1000)->get(config('constants.services.official'));
- if ($response->failed()) {
- return collect([]);
- }
- $services = $response->json();
-
- return collect($services);
- } catch (\Throwable) {
- $services = File::get(base_path('templates/service-templates.json'));
-
- return collect(json_decode($services))->sortKeys();
- }
- } else {
- $services = File::get(base_path('templates/service-templates.json'));
-
- return collect(json_decode($services))->sortKeys();
- }
-}
-
-function getResourceByUuid(string $uuid, ?int $teamId = null)
-{
- if (is_null($teamId)) {
- return null;
- }
- $resource = queryResourcesByUuid($uuid);
- if (! is_null($resource) && $resource->environment->project->team_id === $teamId) {
- return $resource;
- }
-
- return null;
-}
-function queryDatabaseByUuidWithinTeam(string $uuid, string $teamId)
-{
- $postgresql = StandalonePostgresql::whereUuid($uuid)->first();
- if ($postgresql && $postgresql->team()->id == $teamId) {
- return $postgresql->unsetRelation('environment')->unsetRelation('destination');
- }
- $redis = StandaloneRedis::whereUuid($uuid)->first();
- if ($redis && $redis->team()->id == $teamId) {
- return $redis->unsetRelation('environment');
- }
- $mongodb = StandaloneMongodb::whereUuid($uuid)->first();
- if ($mongodb && $mongodb->team()->id == $teamId) {
- return $mongodb->unsetRelation('environment');
- }
- $mysql = StandaloneMysql::whereUuid($uuid)->first();
- if ($mysql && $mysql->team()->id == $teamId) {
- return $mysql->unsetRelation('environment');
- }
- $mariadb = StandaloneMariadb::whereUuid($uuid)->first();
- if ($mariadb && $mariadb->team()->id == $teamId) {
- return $mariadb->unsetRelation('environment');
- }
- $keydb = StandaloneKeydb::whereUuid($uuid)->first();
- if ($keydb && $keydb->team()->id == $teamId) {
- return $keydb->unsetRelation('environment');
- }
- $dragonfly = StandaloneDragonfly::whereUuid($uuid)->first();
- if ($dragonfly && $dragonfly->team()->id == $teamId) {
- return $dragonfly->unsetRelation('environment');
- }
- $clickhouse = StandaloneClickhouse::whereUuid($uuid)->first();
- if ($clickhouse && $clickhouse->team()->id == $teamId) {
- return $clickhouse->unsetRelation('environment');
- }
-
- return null;
-}
-function queryResourcesByUuid(string $uuid)
-{
- $resource = null;
- $application = Application::whereUuid($uuid)->first();
- if ($application) {
- return $application;
- }
- $service = Service::whereUuid($uuid)->first();
- if ($service) {
- return $service;
- }
- $postgresql = StandalonePostgresql::whereUuid($uuid)->first();
- if ($postgresql) {
- return $postgresql;
- }
- $redis = StandaloneRedis::whereUuid($uuid)->first();
- if ($redis) {
- return $redis;
- }
- $mongodb = StandaloneMongodb::whereUuid($uuid)->first();
- if ($mongodb) {
- return $mongodb;
- }
- $mysql = StandaloneMysql::whereUuid($uuid)->first();
- if ($mysql) {
- return $mysql;
- }
- $mariadb = StandaloneMariadb::whereUuid($uuid)->first();
- if ($mariadb) {
- return $mariadb;
- }
- $keydb = StandaloneKeydb::whereUuid($uuid)->first();
- if ($keydb) {
- return $keydb;
- }
- $dragonfly = StandaloneDragonfly::whereUuid($uuid)->first();
- if ($dragonfly) {
- return $dragonfly;
- }
- $clickhouse = StandaloneClickhouse::whereUuid($uuid)->first();
- if ($clickhouse) {
- return $clickhouse;
- }
-
- return $resource;
-}
-function generateTagDeployWebhook($tag_name)
-{
- $baseUrl = base_url();
- $api = Url::fromString($baseUrl).'/api/v1';
- $endpoint = "/deploy?tag=$tag_name";
-
- return $api.$endpoint;
-}
-function generateDeployWebhook($resource)
-{
- $baseUrl = base_url();
- $api = Url::fromString($baseUrl).'/api/v1';
- $endpoint = '/deploy';
- $uuid = data_get($resource, 'uuid');
-
- return $api.$endpoint."?uuid=$uuid&force=false";
-}
-function generateGitManualWebhook($resource, $type)
-{
- if ($resource->source_id !== 0 && ! is_null($resource->source_id)) {
- return null;
- }
- if ($resource->getMorphClass() === \App\Models\Application::class) {
- $baseUrl = base_url();
-
- return Url::fromString($baseUrl)."/webhooks/source/$type/events/manual";
- }
-
- return null;
-}
-function removeAnsiColors($text)
-{
- return preg_replace('/\e[[][A-Za-z0-9];?[0-9]*m?/', '', $text);
-}
-
-function getTopLevelNetworks(Service|Application $resource)
-{
- if ($resource->getMorphClass() === \App\Models\Service::class) {
- if ($resource->docker_compose_raw) {
- try {
- $yaml = Yaml::parse($resource->docker_compose_raw);
- } catch (\Exception $e) {
- throw new \Exception($e->getMessage());
- }
- $services = data_get($yaml, 'services');
- $topLevelNetworks = collect(data_get($yaml, 'networks', []));
- $definedNetwork = collect([$resource->uuid]);
- $services = collect($services)->map(function ($service, $_) use ($topLevelNetworks, $definedNetwork) {
- $serviceNetworks = collect(data_get($service, 'networks', []));
- $hasHostNetworkMode = data_get($service, 'network_mode') === 'host' ? true : false;
-
- // Only add 'networks' key if 'network_mode' is not 'host'
- if (! $hasHostNetworkMode) {
- // Collect/create/update networks
- if ($serviceNetworks->count() > 0) {
- foreach ($serviceNetworks as $networkName => $networkDetails) {
- if ($networkName === 'default') {
- continue;
- }
- // ignore alias
- if ($networkDetails['aliases'] ?? false) {
- continue;
- }
- $networkExists = $topLevelNetworks->contains(function ($value, $key) use ($networkName) {
- return $value == $networkName || $key == $networkName;
- });
- if (! $networkExists) {
- if (is_string($networkDetails) || is_int($networkDetails)) {
- $topLevelNetworks->put($networkDetails, null);
- }
- }
- }
- }
-
- $definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
- return $value == $definedNetwork;
- });
- if (! $definedNetworkExists) {
- foreach ($definedNetwork as $network) {
- $topLevelNetworks->put($network, [
- 'name' => $network,
- 'external' => true,
- ]);
- }
- }
- }
-
- return $service;
- });
-
- return $topLevelNetworks->keys();
- }
- } elseif ($resource->getMorphClass() === \App\Models\Application::class) {
- try {
- $yaml = Yaml::parse($resource->docker_compose_raw);
- } catch (\Exception $e) {
- throw new \Exception($e->getMessage());
- }
- $server = $resource->destination->server;
- $topLevelNetworks = collect(data_get($yaml, 'networks', []));
- $services = data_get($yaml, 'services');
- $definedNetwork = collect([$resource->uuid]);
- $services = collect($services)->map(function ($service, $_) use ($topLevelNetworks, $definedNetwork) {
- $serviceNetworks = collect(data_get($service, 'networks', []));
-
- // Collect/create/update networks
- if ($serviceNetworks->count() > 0) {
- foreach ($serviceNetworks as $networkName => $networkDetails) {
- if ($networkName === 'default') {
- continue;
- }
- // ignore alias
- if ($networkDetails['aliases'] ?? false) {
- continue;
- }
- $networkExists = $topLevelNetworks->contains(function ($value, $key) use ($networkName) {
- return $value == $networkName || $key == $networkName;
- });
- if (! $networkExists) {
- if (is_string($networkDetails) || is_int($networkDetails)) {
- $topLevelNetworks->put($networkDetails, null);
- }
- }
- }
- }
- $definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
- return $value == $definedNetwork;
- });
- if (! $definedNetworkExists) {
- foreach ($definedNetwork as $network) {
- $topLevelNetworks->put($network, [
- 'name' => $network,
- 'external' => true,
- ]);
- }
- }
-
- return $service;
- });
-
- return $topLevelNetworks->keys();
- }
-}
-function sourceIsLocal(Stringable $source)
-{
- if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~') || $source->startsWith('..') || $source->startsWith('~/') || $source->startsWith('../')) {
- return true;
- }
-
- return false;
-}
-
-function replaceLocalSource(Stringable $source, Stringable $replacedWith)
-{
- if ($source->startsWith('.')) {
- $source = $source->replaceFirst('.', $replacedWith->value());
- }
- if ($source->startsWith('~')) {
- $source = $source->replaceFirst('~', $replacedWith->value());
- }
- if ($source->startsWith('..')) {
- $source = $source->replaceFirst('..', $replacedWith->value());
- }
- if ($source->endsWith('/') && $source->value() !== '/') {
- $source = $source->replaceLast('/', '');
- }
-
- return $source;
-}
-
-function convertToArray($collection)
-{
- if ($collection instanceof Collection) {
- return $collection->map(function ($item) {
- return convertToArray($item);
- })->toArray();
- } elseif ($collection instanceof Stringable) {
- return (string) $collection;
- } elseif (is_array($collection)) {
- return array_map(function ($item) {
- return convertToArray($item);
- }, $collection);
- }
-
- return $collection;
-}
-
-function parseCommandFromMagicEnvVariable(Str|string $key): Stringable
-{
- $value = str($key);
- $count = substr_count($value->value(), '_');
- $command = null;
- if ($count === 2) {
- if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) {
- // SERVICE_FQDN_UMAMI
- $command = $value->after('SERVICE_')->beforeLast('_');
- } else {
- // SERVICE_BASE64_UMAMI
- $command = $value->after('SERVICE_')->beforeLast('_');
- }
- }
- if ($count === 3) {
- if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) {
- // SERVICE_FQDN_UMAMI_1000
- $command = $value->after('SERVICE_')->before('_');
- } else {
- // SERVICE_BASE64_64_UMAMI
- $command = $value->after('SERVICE_')->beforeLast('_');
- }
- }
-
- return str($command);
-}
-function parseEnvVariable(Str|string $value)
-{
- $value = str($value);
- $count = substr_count($value->value(), '_');
- $command = null;
- $forService = null;
- $generatedValue = null;
- $port = null;
- if ($value->startsWith('SERVICE')) {
- if ($count === 2) {
- if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) {
- // SERVICE_FQDN_UMAMI
- $command = $value->after('SERVICE_')->beforeLast('_');
- $forService = $value->afterLast('_');
- } else {
- // SERVICE_BASE64_UMAMI
- $command = $value->after('SERVICE_')->beforeLast('_');
- }
- }
- if ($count === 3) {
- if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) {
- // SERVICE_FQDN_UMAMI_1000
- $command = $value->after('SERVICE_')->before('_');
- $forService = $value->after('SERVICE_')->after('_')->before('_');
- $port = $value->afterLast('_');
- if (filter_var($port, FILTER_VALIDATE_INT) === false) {
- $port = null;
- }
- } else {
- // SERVICE_BASE64_64_UMAMI
- $command = $value->after('SERVICE_')->beforeLast('_');
- }
- }
- }
-
- return [
- 'command' => $command,
- 'forService' => $forService,
- 'generatedValue' => $generatedValue,
- 'port' => $port,
- ];
-}
-function generateEnvValue(string $command, Service|Application|null $service = null)
-{
- switch ($command) {
- case 'PASSWORD':
- $generatedValue = Str::password(symbols: false);
- break;
- case 'PASSWORD_64':
- $generatedValue = Str::password(length: 64, symbols: false);
- break;
- case 'PASSWORDWITHSYMBOLS':
- $generatedValue = Str::password(symbols: true);
- break;
- case 'PASSWORDWITHSYMBOLS_64':
- $generatedValue = Str::password(length: 64, symbols: true);
- break;
- // This is not base64, it's just a random string
- case 'BASE64_64':
- $generatedValue = Str::random(64);
- break;
- case 'BASE64_128':
- $generatedValue = Str::random(128);
- break;
- case 'BASE64':
- case 'BASE64_32':
- $generatedValue = Str::random(32);
- break;
- // This is base64,
- case 'REALBASE64_64':
- $generatedValue = base64_encode(Str::random(64));
- break;
- case 'REALBASE64_128':
- $generatedValue = base64_encode(Str::random(128));
- break;
- case 'REALBASE64':
- case 'REALBASE64_32':
- $generatedValue = base64_encode(Str::random(32));
- break;
- case 'HEX_32':
- $generatedValue = bin2hex(Str::random(32));
- break;
- case 'HEX_64':
- $generatedValue = bin2hex(Str::random(64));
- break;
- case 'HEX_128':
- $generatedValue = bin2hex(Str::random(128));
- break;
- case 'USER':
- $generatedValue = Str::random(16);
- break;
- case 'SUPABASEANON':
- $signingKey = $service->environment_variables()->where('key', 'SERVICE_PASSWORD_JWT')->first();
- if (is_null($signingKey)) {
- return;
- } else {
- $signingKey = $signingKey->value;
- }
- $key = InMemory::plainText($signingKey);
- $algorithm = new Sha256;
- $tokenBuilder = (new Builder(new JoseEncoder, ChainedFormatter::default()));
- $now = CarbonImmutable::now();
- $now = $now->setTime($now->format('H'), $now->format('i'));
- $token = $tokenBuilder
- ->issuedBy('supabase')
- ->issuedAt($now)
- ->expiresAt($now->modify('+100 year'))
- ->withClaim('role', 'anon')
- ->getToken($algorithm, $key);
- $generatedValue = $token->toString();
- break;
- case 'SUPABASESERVICE':
- $signingKey = $service->environment_variables()->where('key', 'SERVICE_PASSWORD_JWT')->first();
- if (is_null($signingKey)) {
- return;
- } else {
- $signingKey = $signingKey->value;
- }
- $key = InMemory::plainText($signingKey);
- $algorithm = new Sha256;
- $tokenBuilder = (new Builder(new JoseEncoder, ChainedFormatter::default()));
- $now = CarbonImmutable::now();
- $now = $now->setTime($now->format('H'), $now->format('i'));
- $token = $tokenBuilder
- ->issuedBy('supabase')
- ->issuedAt($now)
- ->expiresAt($now->modify('+100 year'))
- ->withClaim('role', 'service_role')
- ->getToken($algorithm, $key);
- $generatedValue = $token->toString();
- break;
- default:
- // $generatedValue = Str::random(16);
- $generatedValue = null;
- break;
- }
-
- return $generatedValue;
-}
-
-function getRealtime()
-{
- $envDefined = config('constants.pusher.port');
- if (empty($envDefined)) {
- $url = Url::fromString(Request::getSchemeAndHttpHost());
- $port = $url->getPort();
- if ($port) {
- return '6001';
- } else {
- return null;
- }
- } else {
- return $envDefined;
- }
-}
-
-function validate_dns_entry(string $fqdn, Server $server)
-{
- // https://www.cloudflare.com/ips-v4/#
- $cloudflare_ips = collect(['173.245.48.0/20', '103.21.244.0/22', '103.22.200.0/22', '103.31.4.0/22', '141.101.64.0/18', '108.162.192.0/18', '190.93.240.0/20', '188.114.96.0/20', '197.234.240.0/22', '198.41.128.0/17', '162.158.0.0/15', '104.16.0.0/13', '172.64.0.0/13', '131.0.72.0/22']);
-
- $url = Url::fromString($fqdn);
- $host = $url->getHost();
- if (str($host)->contains('sslip.io')) {
- return true;
- }
- $settings = instanceSettings();
- $is_dns_validation_enabled = data_get($settings, 'is_dns_validation_enabled');
- if (! $is_dns_validation_enabled) {
- return true;
- }
- $dns_servers = data_get($settings, 'custom_dns_servers');
- $dns_servers = str($dns_servers)->explode(',');
- if ($server->id === 0) {
- $ip = data_get($settings, 'public_ipv4', data_get($settings, 'public_ipv6', $server->ip));
- } else {
- $ip = $server->ip;
- }
- $found_matching_ip = false;
- $type = \PurplePixie\PhpDns\DNSTypes::NAME_A;
- foreach ($dns_servers as $dns_server) {
- try {
- $query = new DNSQuery($dns_server);
- $results = $query->query($host, $type);
- if ($results === false || $query->hasError()) {
- ray('Error: '.$query->getLasterror());
- } else {
- foreach ($results as $result) {
- if ($result->getType() == $type) {
- if (ip_match($result->getData(), $cloudflare_ips->toArray(), $match)) {
- $found_matching_ip = true;
- break;
- }
- if ($result->getData() === $ip) {
- $found_matching_ip = true;
- break;
- }
- }
- }
- }
- } catch (\Exception) {
- }
- }
-
- return $found_matching_ip;
-}
-
-function ip_match($ip, $cidrs, &$match = null)
-{
- foreach ((array) $cidrs as $cidr) {
- [$subnet, $mask] = explode('/', $cidr);
- if (((ip2long($ip) & ($mask = ~((1 << (32 - $mask)) - 1))) == (ip2long($subnet) & $mask))) {
- $match = $cidr;
-
- return true;
- }
- }
-
- return false;
-}
-function checkIfDomainIsAlreadyUsed(Collection|array $domains, ?string $teamId = null, ?string $uuid = null)
-{
- if (is_null($teamId)) {
- return response()->json(['error' => 'Team ID is required.'], 400);
- }
- if (is_array($domains)) {
- $domains = collect($domains);
- }
-
- $domains = $domains->map(function ($domain) {
- if (str($domain)->endsWith('/')) {
- $domain = str($domain)->beforeLast('/');
- }
-
- return str($domain);
- });
- $applications = Application::ownedByCurrentTeamAPI($teamId)->get(['fqdn', 'uuid']);
- $serviceApplications = ServiceApplication::ownedByCurrentTeamAPI($teamId)->get(['fqdn', 'uuid']);
- if ($uuid) {
- $applications = $applications->filter(fn ($app) => $app->uuid !== $uuid);
- $serviceApplications = $serviceApplications->filter(fn ($app) => $app->uuid !== $uuid);
- }
- $domainFound = false;
- foreach ($applications as $app) {
- if (is_null($app->fqdn)) {
- continue;
- }
- $list_of_domains = collect(explode(',', $app->fqdn))->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)) {
- $domainFound = true;
- break;
- }
- }
- }
- if ($domainFound) {
- return true;
- }
- foreach ($serviceApplications as $app) {
- if (str($app->fqdn)->isEmpty()) {
- continue;
- }
- $list_of_domains = collect(explode(',', $app->fqdn))->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)) {
- $domainFound = true;
- break;
- }
- }
- }
- if ($domainFound) {
- return true;
- }
- $settings = instanceSettings();
- if (data_get($settings, 'fqdn')) {
- $domain = data_get($settings, 'fqdn');
- if (str($domain)->endsWith('/')) {
- $domain = str($domain)->beforeLast('/');
- }
- $naked_domain = str($domain)->value();
- if ($domains->contains($naked_domain)) {
- return true;
- }
- }
-}
-function check_domain_usage(ServiceApplication|Application|null $resource = null, ?string $domain = null)
-{
- if ($resource) {
- if ($resource->getMorphClass() === \App\Models\Application::class && $resource->build_pack === 'dockercompose') {
- $domains = data_get(json_decode($resource->docker_compose_domains, true), '*.domain');
- $domains = collect($domains);
- } else {
- $domains = collect($resource->fqdns);
- }
- } elseif ($domain) {
- $domains = collect($domain);
- } else {
- throw new \RuntimeException('No resource or FQDN provided.');
- }
- $domains = $domains->map(function ($domain) {
- if (str($domain)->endsWith('/')) {
- $domain = str($domain)->beforeLast('/');
- }
-
- return str($domain);
- });
- $apps = Application::all();
- foreach ($apps as $app) {
- $list_of_domains = collect(explode(',', $app->fqdn))->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)) {
- if (data_get($resource, 'uuid')) {
- if ($resource->uuid !== $app->uuid) {
- throw new \RuntimeException("Domain $naked_domain is already in use by another resource: Link: {$app->name} ");
- }
- } elseif ($domain) {
- throw new \RuntimeException("Domain $naked_domain is already in use by another resource: Link: {$app->name} ");
- }
- }
- }
- }
- $apps = ServiceApplication::all();
- foreach ($apps as $app) {
- $list_of_domains = collect(explode(',', $app->fqdn))->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)) {
- if (data_get($resource, 'uuid')) {
- if ($resource->uuid !== $app->uuid) {
- throw new \RuntimeException("Domain $naked_domain is already in use by another resource: Link: {$app->service->name} ");
- }
- } elseif ($domain) {
- throw new \RuntimeException("Domain $naked_domain is already in use by another resource: Link: {$app->service->name} ");
- }
- }
- }
- }
- if ($resource) {
- $settings = instanceSettings();
- if (data_get($settings, 'fqdn')) {
- $domain = data_get($settings, 'fqdn');
- if (str($domain)->endsWith('/')) {
- $domain = str($domain)->beforeLast('/');
- }
- $naked_domain = str($domain)->value();
- if ($domains->contains($naked_domain)) {
- throw new \RuntimeException("Domain $naked_domain is already in use by this Coolify instance.");
- }
- }
- }
-}
-
-function parseCommandsByLineForSudo(Collection $commands, Server $server): array
-{
- $commands = $commands->map(function ($line) {
- if (
- ! str(trim($line))->startsWith([
- 'cd',
- 'command',
- 'echo',
- 'true',
- 'if',
- 'fi',
- ])
- ) {
- return "sudo $line";
- }
-
- if (str(trim($line))->startsWith('if')) {
- return str_replace('if', 'if sudo', $line);
- }
-
- return $line;
- });
-
- $commands = $commands->map(function ($line) use ($server) {
- if (Str::startsWith($line, 'sudo mkdir -p')) {
- return "$line && sudo chown -R $server->user:$server->user ".Str::after($line, 'sudo mkdir -p').' && sudo chmod -R o-rwx '.Str::after($line, 'sudo mkdir -p');
- }
-
- return $line;
- });
-
- $commands = $commands->map(function ($line) {
- $line = str($line);
- if (str($line)->contains('$(')) {
- $line = $line->replace('$(', '$(sudo ');
- }
- if (str($line)->contains('||')) {
- $line = $line->replace('||', '|| sudo');
- }
- if (str($line)->contains('&&')) {
- $line = $line->replace('&&', '&& sudo');
- }
- if (str($line)->contains(' | ')) {
- $line = $line->replace(' | ', ' | sudo ');
- }
-
- return $line->value();
- });
-
- return $commands->toArray();
-}
-function parseLineForSudo(string $command, Server $server): string
-{
- if (! str($command)->startSwith('cd') && ! str($command)->startSwith('command')) {
- $command = "sudo $command";
- }
- if (Str::startsWith($command, 'sudo mkdir -p')) {
- $command = "$command && sudo chown -R $server->user:$server->user ".Str::after($command, 'sudo mkdir -p').' && sudo chmod -R o-rwx '.Str::after($command, 'sudo mkdir -p');
- }
- if (str($command)->contains('$(') || str($command)->contains('`')) {
- $command = str($command)->replace('$(', '$(sudo ')->replace('`', '`sudo ')->value();
- }
- if (str($command)->contains('||')) {
- $command = str($command)->replace('||', '|| sudo ')->value();
- }
- if (str($command)->contains('&&')) {
- $command = str($command)->replace('&&', '&& sudo ')->value();
- }
-
- return $command;
-}
-
-function get_public_ips()
-{
- try {
- [$first, $second] = Process::concurrently(function (Pool $pool) {
- $pool->path(__DIR__)->command('curl -4s https://ifconfig.io');
- $pool->path(__DIR__)->command('curl -6s https://ifconfig.io');
- });
- $ipv4 = $first->output();
- if ($ipv4) {
- $ipv4 = trim($ipv4);
- $validate_ipv4 = filter_var($ipv4, FILTER_VALIDATE_IP);
- if ($validate_ipv4 == false) {
- echo "Invalid ipv4: $ipv4\n";
-
- return;
- }
- InstanceSettings::get()->update(['public_ipv4' => $ipv4]);
- }
- } catch (\Exception $e) {
- echo "Error: {$e->getMessage()}\n";
- }
- try {
- $ipv6 = $second->output();
- if ($ipv6) {
- $ipv6 = trim($ipv6);
- $validate_ipv6 = filter_var($ipv6, FILTER_VALIDATE_IP);
- if ($validate_ipv6 == false) {
- echo "Invalid ipv6: $ipv6\n";
-
- return;
- }
- InstanceSettings::get()->update(['public_ipv6' => $ipv6]);
- }
- } catch (\Throwable $e) {
- echo "Error: {$e->getMessage()}\n";
- }
-}
-
-function isAnyDeploymentInprogress()
-{
- $runningJobs = ApplicationDeploymentQueue::where('horizon_job_worker', gethostname())->where('status', ApplicationDeploymentStatus::IN_PROGRESS->value)->get();
- $horizonJobIds = [];
- foreach ($runningJobs as $runningJob) {
- $horizonJobStatus = getJobStatus($runningJob->horizon_job_id);
- if ($horizonJobStatus === 'unknown') {
- return true;
- }
- $horizonJobIds[] = $runningJob->horizon_job_id;
- }
- if (count($horizonJobIds) === 0) {
- echo "No deployments in progress.\n";
- exit(0);
- }
- $horizonJobIds = collect($horizonJobIds)->unique()->toArray();
- echo 'There are '.count($horizonJobIds)." deployments in progress.\n";
- exit(1);
-}
-
-function isBase64Encoded($strValue)
-{
- return base64_encode(base64_decode($strValue, true)) === $strValue;
-}
-function customApiValidator(Collection|array $item, array $rules)
-{
- if (is_array($item)) {
- $item = collect($item);
- }
-
- return Validator::make($item->toArray(), $rules, [
- 'required' => 'This field is required.',
- ]);
-}
-
-function parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull_request_id = 0)
-{
- $serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
- $type = null;
- $source = null;
- $target = null;
- $content = null;
- $isDirectory = false;
- if (is_string($volume)) {
- $source = str($volume)->before(':');
- $target = str($volume)->after(':')->beforeLast(':');
- $foundConfig = $resource->fileStorages()->whereMountPath($target)->first();
- if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
- $type = str('bind');
- if ($foundConfig) {
- $contentNotNull = data_get($foundConfig, 'content');
- if ($contentNotNull) {
- $content = $contentNotNull;
- }
- $isDirectory = data_get($foundConfig, 'is_directory');
- } else {
- // By default, we cannot determine if the bind is a directory or not, so we set it to directory
- $isDirectory = true;
- }
- } else {
- $type = str('volume');
- }
- } elseif (is_array($volume)) {
- $type = data_get_str($volume, 'type');
- $source = data_get_str($volume, 'source');
- $target = data_get_str($volume, 'target');
- $content = data_get($volume, 'content');
- $isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
- $foundConfig = $resource->fileStorages()->whereMountPath($target)->first();
- if ($foundConfig) {
- $contentNotNull = data_get($foundConfig, 'content');
- if ($contentNotNull) {
- $content = $contentNotNull;
- }
- $isDirectory = data_get($foundConfig, 'is_directory');
- } else {
- $isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
- if ((is_null($isDirectory) || ! $isDirectory) && is_null($content)) {
- // if isDirectory is not set (or false) & content is also not set, we assume it is a directory
- $isDirectory = true;
- }
- }
- }
- if ($type?->value() === 'bind') {
- if ($source->value() === '/var/run/docker.sock') {
- return $volume;
- }
- if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
- return $volume;
- }
- if (get_class($resource) === \App\Models\Application::class) {
- $dir = base_configuration_dir().'/applications/'.$resource->uuid;
- } else {
- $dir = base_configuration_dir().'/services/'.$resource->service->uuid;
- }
-
- if ($source->startsWith('.')) {
- $source = $source->replaceFirst('.', $dir);
- }
- if ($source->startsWith('~')) {
- $source = $source->replaceFirst('~', $dir);
- }
- if ($pull_request_id !== 0) {
- $source = $source."-pr-$pull_request_id";
- }
- if (! $resource?->settings?->is_preserve_repository_enabled || $foundConfig?->is_based_on_git) {
- LocalFileVolume::updateOrCreate(
- [
- 'mount_path' => $target,
- 'resource_id' => $resource->id,
- 'resource_type' => get_class($resource),
- ],
- [
- 'fs_path' => $source,
- 'mount_path' => $target,
- 'content' => $content,
- 'is_directory' => $isDirectory,
- 'resource_id' => $resource->id,
- 'resource_type' => get_class($resource),
- ]
- );
- }
- } elseif ($type->value() === 'volume') {
- if ($topLevelVolumes->has($source->value())) {
- $v = $topLevelVolumes->get($source->value());
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- return $volume;
- }
- }
- $slugWithoutUuid = Str::slug($source, '-');
- if (get_class($resource) === \App\Models\Application::class) {
- $name = "{$resource->uuid}_{$slugWithoutUuid}";
- } else {
- $name = "{$resource->service->uuid}_{$slugWithoutUuid}";
- }
- if (is_string($volume)) {
- $source = str($volume)->before(':');
- $target = str($volume)->after(':')->beforeLast(':');
- $source = $name;
- $volume = "$source:$target";
- } elseif (is_array($volume)) {
- data_set($volume, 'source', $name);
- }
- $topLevelVolumes->put($name, [
- 'name' => $name,
- ]);
- LocalPersistentVolume::updateOrCreate(
- [
- 'mount_path' => $target,
- 'resource_id' => $resource->id,
- 'resource_type' => get_class($resource),
- ],
- [
- 'name' => $name,
- 'mount_path' => $target,
- 'resource_id' => $resource->id,
- 'resource_type' => get_class($resource),
- ]
- );
- }
- dispatch(new ServerFilesFromServerJob($resource));
-
- return $volume;
- });
-
- return [
- 'serviceVolumes' => $serviceVolumes,
- 'topLevelVolumes' => $topLevelVolumes,
- ];
-}
-
-function parseDockerComposeFile(Service|Application $resource, bool $isNew = false, int $pull_request_id = 0, ?int $preview_id = null)
-{
- if ($resource->getMorphClass() === \App\Models\Service::class) {
- if ($resource->docker_compose_raw) {
- try {
- $yaml = Yaml::parse($resource->docker_compose_raw);
- } catch (\Exception $e) {
- throw new \Exception($e->getMessage());
- }
- $allServices = get_service_templates();
- $topLevelVolumes = collect(data_get($yaml, 'volumes', []));
- $topLevelNetworks = collect(data_get($yaml, 'networks', []));
- $topLevelConfigs = collect(data_get($yaml, 'configs', []));
- $topLevelSecrets = collect(data_get($yaml, 'secrets', []));
- $services = data_get($yaml, 'services');
-
- $generatedServiceFQDNS = collect([]);
- if (is_null($resource->destination)) {
- $destination = $resource->server->destinations()->first();
- if ($destination) {
- $resource->destination()->associate($destination);
- $resource->save();
- }
- }
- $definedNetwork = collect([$resource->uuid]);
- if ($topLevelVolumes->count() > 0) {
- $tempTopLevelVolumes = collect([]);
- foreach ($topLevelVolumes as $volumeName => $volume) {
- if (is_null($volume)) {
- continue;
- }
- $tempTopLevelVolumes->put($volumeName, $volume);
- }
- $topLevelVolumes = collect($tempTopLevelVolumes);
- }
- $services = collect($services)->map(function ($service, $serviceName) use ($topLevelVolumes, $topLevelNetworks, $definedNetwork, $isNew, $generatedServiceFQDNS, $resource, $allServices) {
- // Workarounds for beta users.
- if ($serviceName === 'registry') {
- $tempServiceName = 'docker-registry';
- } else {
- $tempServiceName = $serviceName;
- }
- if (str(data_get($service, 'image'))->contains('glitchtip')) {
- $tempServiceName = 'glitchtip';
- }
- if ($serviceName === 'supabase-kong') {
- $tempServiceName = 'supabase';
- }
- $serviceDefinition = data_get($allServices, $tempServiceName);
- $predefinedPort = data_get($serviceDefinition, 'port');
- if ($serviceName === 'plausible') {
- $predefinedPort = '8000';
- }
- // End of workarounds for beta users.
- $serviceVolumes = collect(data_get($service, 'volumes', []));
- $servicePorts = collect(data_get($service, 'ports', []));
- $serviceNetworks = collect(data_get($service, 'networks', []));
- $serviceVariables = collect(data_get($service, 'environment', []));
- $serviceLabels = collect(data_get($service, 'labels', []));
- $hasHostNetworkMode = data_get($service, 'network_mode') === 'host' ? true : false;
- if ($serviceLabels->count() > 0) {
- $removedLabels = collect([]);
- $serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) {
- if (! str($serviceLabel)->contains('=')) {
- $removedLabels->put($serviceLabelName, $serviceLabel);
-
- return false;
- }
-
- return $serviceLabel;
- });
- foreach ($removedLabels as $removedLabelName => $removedLabel) {
- $serviceLabels->push("$removedLabelName=$removedLabel");
- }
- }
- $containerName = "$serviceName-{$resource->uuid}";
-
- // Decide if the service is a database
- $isDatabase = isDatabaseImage(data_get_str($service, 'image'));
- $image = data_get_str($service, 'image');
- data_set($service, 'is_database', $isDatabase);
-
- // Create new serviceApplication or serviceDatabase
- if ($isDatabase) {
- if ($isNew) {
- $savedService = ServiceDatabase::create([
- 'name' => $serviceName,
- 'image' => $image,
- 'service_id' => $resource->id,
- ]);
- } else {
- $savedService = ServiceDatabase::where([
- 'name' => $serviceName,
- 'service_id' => $resource->id,
- ])->first();
- }
- } else {
- if ($isNew) {
- $savedService = ServiceApplication::create([
- 'name' => $serviceName,
- 'image' => $image,
- 'service_id' => $resource->id,
- ]);
- } else {
- $savedService = ServiceApplication::where([
- 'name' => $serviceName,
- 'service_id' => $resource->id,
- ])->first();
- }
- }
- if (is_null($savedService)) {
- if ($isDatabase) {
- $savedService = ServiceDatabase::create([
- 'name' => $serviceName,
- 'image' => $image,
- 'service_id' => $resource->id,
- ]);
- } else {
- $savedService = ServiceApplication::create([
- 'name' => $serviceName,
- 'image' => $image,
- 'service_id' => $resource->id,
- ]);
- }
- }
-
- // Check if image changed
- if ($savedService->image !== $image) {
- $savedService->image = $image;
- $savedService->save();
- }
- // Collect/create/update networks
- if ($serviceNetworks->count() > 0) {
- foreach ($serviceNetworks as $networkName => $networkDetails) {
- if ($networkName === 'default') {
- continue;
- }
- // ignore alias
- if ($networkDetails['aliases'] ?? false) {
- continue;
- }
- $networkExists = $topLevelNetworks->contains(function ($value, $key) use ($networkName) {
- return $value == $networkName || $key == $networkName;
- });
- if (! $networkExists) {
- if (is_string($networkDetails) || is_int($networkDetails)) {
- $topLevelNetworks->put($networkDetails, null);
- }
- }
- }
- }
-
- // Collect/create/update ports
- $collectedPorts = collect([]);
- if ($servicePorts->count() > 0) {
- foreach ($servicePorts as $sport) {
- if (is_string($sport) || is_numeric($sport)) {
- $collectedPorts->push($sport);
- }
- if (is_array($sport)) {
- $target = data_get($sport, 'target');
- $published = data_get($sport, 'published');
- $protocol = data_get($sport, 'protocol');
- $collectedPorts->push("$target:$published/$protocol");
- }
- }
- }
- $savedService->ports = $collectedPorts->implode(',');
- $savedService->save();
-
- if (! $hasHostNetworkMode) {
- // Add Coolify specific networks
- $definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
- return $value == $definedNetwork;
- });
- if (! $definedNetworkExists) {
- foreach ($definedNetwork as $network) {
- $topLevelNetworks->put($network, [
- 'name' => $network,
- 'external' => true,
- ]);
- }
- }
- $networks = collect();
- foreach ($serviceNetworks as $key => $serviceNetwork) {
- if (gettype($serviceNetwork) === 'string') {
- // networks:
- // - appwrite
- $networks->put($serviceNetwork, null);
- } elseif (gettype($serviceNetwork) === 'array') {
- // networks:
- // default:
- // ipv4_address: 192.168.203.254
- // $networks->put($serviceNetwork, null);
- $networks->put($key, $serviceNetwork);
- }
- }
- foreach ($definedNetwork as $key => $network) {
- $networks->put($network, null);
- }
- data_set($service, 'networks', $networks->toArray());
- }
-
- // Collect/create/update volumes
- if ($serviceVolumes->count() > 0) {
- $serviceVolumes = $serviceVolumes->map(function ($volume) use ($savedService, $topLevelVolumes) {
- $type = null;
- $source = null;
- $target = null;
- $content = null;
- $isDirectory = false;
- if (is_string($volume)) {
- $source = str($volume)->before(':');
- $target = str($volume)->after(':')->beforeLast(':');
- if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
- $type = str('bind');
- // By default, we cannot determine if the bind is a directory or not, so we set it to directory
- $isDirectory = true;
- } else {
- $type = str('volume');
- }
- } elseif (is_array($volume)) {
- $type = data_get_str($volume, 'type');
- $source = data_get_str($volume, 'source');
- $target = data_get_str($volume, 'target');
- $content = data_get($volume, 'content');
- $isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
- $foundConfig = $savedService->fileStorages()->whereMountPath($target)->first();
- if ($foundConfig) {
- $contentNotNull = data_get($foundConfig, 'content');
- if ($contentNotNull) {
- $content = $contentNotNull;
- }
- $isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
- }
- if (is_null($isDirectory) && is_null($content)) {
- // if isDirectory is not set & content is also not set, we assume it is a directory
- $isDirectory = true;
- }
- }
- if ($type?->value() === 'bind') {
- if ($source->value() === '/var/run/docker.sock') {
- return $volume;
- }
- if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
- return $volume;
- }
- LocalFileVolume::updateOrCreate(
- [
- 'mount_path' => $target,
- 'resource_id' => $savedService->id,
- 'resource_type' => get_class($savedService),
- ],
- [
- 'fs_path' => $source,
- 'mount_path' => $target,
- 'content' => $content,
- 'is_directory' => $isDirectory,
- 'resource_id' => $savedService->id,
- 'resource_type' => get_class($savedService),
- ]
- );
- } elseif ($type->value() === 'volume') {
- if ($topLevelVolumes->has($source->value())) {
- $v = $topLevelVolumes->get($source->value());
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- return $volume;
- }
- }
- $slugWithoutUuid = Str::slug($source, '-');
- $name = "{$savedService->service->uuid}_{$slugWithoutUuid}";
- if (is_string($volume)) {
- $source = str($volume)->before(':');
- $target = str($volume)->after(':')->beforeLast(':');
- $source = $name;
- $volume = "$source:$target";
- } elseif (is_array($volume)) {
- data_set($volume, 'source', $name);
- }
- $topLevelVolumes->put($name, [
- 'name' => $name,
- ]);
- LocalPersistentVolume::updateOrCreate(
- [
- 'mount_path' => $target,
- 'resource_id' => $savedService->id,
- 'resource_type' => get_class($savedService),
- ],
- [
- 'name' => $name,
- 'mount_path' => $target,
- 'resource_id' => $savedService->id,
- 'resource_type' => get_class($savedService),
- ]
- );
- }
- dispatch(new ServerFilesFromServerJob($savedService));
-
- return $volume;
- });
- data_set($service, 'volumes', $serviceVolumes->toArray());
- }
-
- // convert - SESSION_SECRET: 123 to - SESSION_SECRET=123
- $convertedServiceVariables = collect([]);
- foreach ($serviceVariables as $variableName => $variable) {
- if (is_numeric($variableName)) {
- if (is_array($variable)) {
- $key = str(collect($variable)->keys()->first());
- $value = str(collect($variable)->values()->first());
- $variable = "$key=$value";
- $convertedServiceVariables->put($variableName, $variable);
- } elseif (is_string($variable)) {
- $convertedServiceVariables->put($variableName, $variable);
- }
- } elseif (is_string($variableName)) {
- $convertedServiceVariables->put($variableName, $variable);
- }
- }
- $serviceVariables = $convertedServiceVariables;
- // Get variables from the service
- foreach ($serviceVariables as $variableName => $variable) {
- if (is_numeric($variableName)) {
- if (is_array($variable)) {
- // - SESSION_SECRET: 123
- // - SESSION_SECRET:
- $key = str(collect($variable)->keys()->first());
- $value = str(collect($variable)->values()->first());
- } else {
- $variable = str($variable);
- if ($variable->contains('=')) {
- // - SESSION_SECRET=123
- // - SESSION_SECRET=
- $key = $variable->before('=');
- $value = $variable->after('=');
- } else {
- // - SESSION_SECRET
- $key = $variable;
- $value = null;
- }
- }
- } else {
- // SESSION_SECRET: 123
- // SESSION_SECRET:
- $key = str($variableName);
- $value = str($variable);
- }
- if ($key->startsWith('SERVICE_FQDN')) {
- if ($isNew || $savedService->fqdn === null) {
- $name = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower();
- $fqdn = generateFqdn($resource->server, "{$name->value()}-{$resource->uuid}");
- if (substr_count($key->value(), '_') === 3) {
- // SERVICE_FQDN_UMAMI_1000
- $port = $key->afterLast('_');
- } else {
- $last = $key->afterLast('_');
- if (is_numeric($last->value())) {
- // SERVICE_FQDN_3001
- $port = $last;
- } else {
- // SERVICE_FQDN_UMAMI
- $port = null;
- }
- }
- if ($port) {
- $fqdn = "$fqdn:$port";
- }
- if (substr_count($key->value(), '_') >= 2) {
- if ($value) {
- $path = $value->value();
- } else {
- $path = null;
- }
- if ($generatedServiceFQDNS->count() > 0) {
- $alreadyGenerated = $generatedServiceFQDNS->has($key->value());
- if ($alreadyGenerated) {
- $fqdn = $generatedServiceFQDNS->get($key->value());
- } else {
- $generatedServiceFQDNS->put($key->value(), $fqdn);
- }
- } else {
- $generatedServiceFQDNS->put($key->value(), $fqdn);
- }
- $fqdn = "$fqdn$path";
- }
-
- if (! $isDatabase) {
- if ($savedService->fqdn) {
- data_set($savedService, 'fqdn', $savedService->fqdn.','.$fqdn);
- } else {
- data_set($savedService, 'fqdn', $fqdn);
- }
- $savedService->save();
- }
- EnvironmentVariable::create([
- 'key' => $key,
- 'value' => $fqdn,
- 'is_build_time' => false,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- 'is_preview' => false,
- ]);
- }
- // Caddy needs exact port in some cases.
- if ($predefinedPort && ! $key->endsWith("_{$predefinedPort}")) {
- $fqdns_exploded = str($savedService->fqdn)->explode(',');
- if ($fqdns_exploded->count() > 1) {
- continue;
- }
- $env = EnvironmentVariable::where([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ])->first();
- if ($env) {
- $env_url = Url::fromString($savedService->fqdn);
- $env_port = $env_url->getPort();
- if ($env_port !== $predefinedPort) {
- $env_url = $env_url->withPort($predefinedPort);
- $savedService->fqdn = $env_url->__toString();
- $savedService->save();
- }
- }
- }
-
- // data_forget($service, "environment.$variableName");
- // $yaml = data_forget($yaml, "services.$serviceName.environment.$variableName");
- // if (count(data_get($yaml, 'services.' . $serviceName . '.environment')) === 0) {
- // $yaml = data_forget($yaml, "services.$serviceName.environment");
- // }
- continue;
- }
- if ($value?->startsWith('$')) {
- $foundEnv = EnvironmentVariable::where([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ])->first();
- $value = replaceVariables($value);
- $key = $value;
- if ($value->startsWith('SERVICE_')) {
- $foundEnv = EnvironmentVariable::where([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ])->first();
- ['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
- if (! is_null($command)) {
- if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
- if (Str::lower($forService) === $serviceName) {
- $fqdn = generateFqdn($resource->server, $containerName);
- } else {
- $fqdn = generateFqdn($resource->server, Str::lower($forService).'-'.$resource->uuid);
- }
- if ($port) {
- $fqdn = "$fqdn:$port";
- }
- if ($foundEnv) {
- $fqdn = data_get($foundEnv, 'value');
- // if ($savedService->fqdn) {
- // $savedServiceFqdn = Url::fromString($savedService->fqdn);
- // $parsedFqdn = Url::fromString($fqdn);
- // $savedServicePath = $savedServiceFqdn->getPath();
- // $parsedFqdnPath = $parsedFqdn->getPath();
- // if ($savedServicePath != $parsedFqdnPath) {
- // $fqdn = $parsedFqdn->withPath($savedServicePath)->__toString();
- // $foundEnv->value = $fqdn;
- // $foundEnv->save();
- // }
- // }
- } else {
- if ($command->value() === 'URL') {
- $fqdn = str($fqdn)->after('://')->value();
- }
- EnvironmentVariable::create([
- 'key' => $key,
- 'value' => $fqdn,
- 'is_build_time' => false,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- 'is_preview' => false,
- ]);
- }
- if (! $isDatabase) {
- if ($command->value() === 'FQDN' && is_null($savedService->fqdn) && ! $foundEnv) {
- $savedService->fqdn = $fqdn;
- $savedService->save();
- }
- // Caddy needs exact port in some cases.
- if ($predefinedPort && ! $key->endsWith("_{$predefinedPort}") && $command?->value() === 'FQDN' && $resource->server->proxyType() === 'CADDY') {
- $fqdns_exploded = str($savedService->fqdn)->explode(',');
- if ($fqdns_exploded->count() > 1) {
- continue;
- }
- $env = EnvironmentVariable::where([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ])->first();
- if ($env) {
- $env_url = Url::fromString($env->value);
- $env_port = $env_url->getPort();
- if ($env_port !== $predefinedPort) {
- $env_url = $env_url->withPort($predefinedPort);
- $savedService->fqdn = $env_url->__toString();
- $savedService->save();
- }
- }
- }
- }
- } else {
- $generatedValue = generateEnvValue($command, $resource);
- if (! $foundEnv) {
- EnvironmentVariable::create([
- 'key' => $key,
- 'value' => $generatedValue,
- 'is_build_time' => false,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- 'is_preview' => false,
- ]);
- }
- }
- }
- } else {
- if ($value->contains(':-')) {
- $key = $value->before(':');
- $defaultValue = $value->after(':-');
- } elseif ($value->contains('-')) {
- $key = $value->before('-');
- $defaultValue = $value->after('-');
- } elseif ($value->contains(':?')) {
- $key = $value->before(':');
- $defaultValue = $value->after(':?');
- } elseif ($value->contains('?')) {
- $key = $value->before('?');
- $defaultValue = $value->after('?');
- } else {
- $key = $value;
- $defaultValue = null;
- }
- $foundEnv = EnvironmentVariable::where([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ])->first();
- if ($foundEnv) {
- $defaultValue = data_get($foundEnv, 'value');
- }
- EnvironmentVariable::updateOrCreate([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ], [
- 'value' => $defaultValue,
- 'is_build_time' => false,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- 'is_preview' => false,
- ]);
- }
- }
- }
- // Add labels to the service
- if ($savedService->serviceType()) {
- $fqdns = generateServiceSpecificFqdns($savedService);
- } else {
- $fqdns = collect(data_get($savedService, 'fqdns'))->filter();
- }
- $defaultLabels = defaultLabels(
- id: $resource->id,
- name: $containerName,
- projectName: $resource->project()->name,
- resourceName: $resource->name,
- type: 'service',
- subType: $isDatabase ? 'database' : 'application',
- subId: $savedService->id,
- subName: $savedService->name,
- environment: $resource->environment->name,
- );
- $serviceLabels = $serviceLabels->merge($defaultLabels);
- if (! $isDatabase && $fqdns->count() > 0) {
- if ($fqdns) {
- $shouldGenerateLabelsExactly = $resource->server->settings->generate_exact_labels;
- if ($shouldGenerateLabelsExactly) {
- switch ($resource->server->proxyType()) {
- case ProxyTypes::TRAEFIK->value:
- $serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik(
- uuid: $resource->uuid,
- domains: $fqdns,
- is_force_https_enabled: true,
- serviceLabels: $serviceLabels,
- is_gzip_enabled: $savedService->isGzipEnabled(),
- is_stripprefix_enabled: $savedService->isStripprefixEnabled(),
- service_name: $serviceName,
- image: data_get($service, 'image')
- ));
- break;
- case ProxyTypes::CADDY->value:
- $serviceLabels = $serviceLabels->merge(fqdnLabelsForCaddy(
- network: $resource->destination->network,
- uuid: $resource->uuid,
- domains: $fqdns,
- is_force_https_enabled: true,
- serviceLabels: $serviceLabels,
- is_gzip_enabled: $savedService->isGzipEnabled(),
- is_stripprefix_enabled: $savedService->isStripprefixEnabled(),
- service_name: $serviceName,
- image: data_get($service, 'image')
- ));
- break;
- }
- } else {
- $serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik(
- uuid: $resource->uuid,
- domains: $fqdns,
- is_force_https_enabled: true,
- serviceLabels: $serviceLabels,
- is_gzip_enabled: $savedService->isGzipEnabled(),
- is_stripprefix_enabled: $savedService->isStripprefixEnabled(),
- service_name: $serviceName,
- image: data_get($service, 'image')
- ));
- $serviceLabels = $serviceLabels->merge(fqdnLabelsForCaddy(
- network: $resource->destination->network,
- uuid: $resource->uuid,
- domains: $fqdns,
- is_force_https_enabled: true,
- serviceLabels: $serviceLabels,
- is_gzip_enabled: $savedService->isGzipEnabled(),
- is_stripprefix_enabled: $savedService->isStripprefixEnabled(),
- service_name: $serviceName,
- image: data_get($service, 'image')
- ));
- }
- }
- }
- if ($resource->server->isLogDrainEnabled() && $savedService->isLogDrainEnabled()) {
- data_set($service, 'logging', generate_fluentd_configuration());
- }
- if ($serviceLabels->count() > 0) {
- if ($resource->is_container_label_escape_enabled) {
- $serviceLabels = $serviceLabels->map(function ($value, $key) {
- return escapeDollarSign($value);
- });
- }
- }
- data_set($service, 'labels', $serviceLabels->toArray());
- data_forget($service, 'is_database');
- if (! data_get($service, 'restart')) {
- data_set($service, 'restart', RESTART_MODE);
- }
- if (data_get($service, 'restart') === 'no' || data_get($service, 'exclude_from_hc')) {
- $savedService->update(['exclude_from_status' => true]);
- }
- data_set($service, 'container_name', $containerName);
- data_forget($service, 'volumes.*.content');
- data_forget($service, 'volumes.*.isDirectory');
- data_forget($service, 'volumes.*.is_directory');
- data_forget($service, 'exclude_from_hc');
- data_set($service, 'environment', $serviceVariables->toArray());
- updateCompose($savedService);
-
- return $service;
- });
-
- $envs_from_coolify = $resource->environment_variables()->get();
- $services = collect($services)->map(function ($service, $serviceName) use ($resource, $envs_from_coolify) {
- $serviceVariables = collect(data_get($service, 'environment', []));
- $parsedServiceVariables = collect([]);
- foreach ($serviceVariables as $key => $value) {
- if (is_numeric($key)) {
- $value = str($value);
- if ($value->contains('=')) {
- $key = $value->before('=')->value();
- $value = $value->after('=')->value();
- } else {
- $key = $value->value();
- $value = null;
- }
- $parsedServiceVariables->put($key, $value);
- } else {
- $parsedServiceVariables->put($key, $value);
- }
- }
- $parsedServiceVariables->put('COOLIFY_RESOURCE_UUID', "{$resource->uuid}");
- $parsedServiceVariables->put('COOLIFY_CONTAINER_NAME', "$serviceName-{$resource->uuid}");
-
- // TODO: move this in a shared function
- if (! $parsedServiceVariables->has('COOLIFY_APP_NAME')) {
- $parsedServiceVariables->put('COOLIFY_APP_NAME', "\"{$resource->name}\"");
- }
- if (! $parsedServiceVariables->has('COOLIFY_SERVER_IP')) {
- $parsedServiceVariables->put('COOLIFY_SERVER_IP', "\"{$resource->destination->server->ip}\"");
- }
- if (! $parsedServiceVariables->has('COOLIFY_ENVIRONMENT_NAME')) {
- $parsedServiceVariables->put('COOLIFY_ENVIRONMENT_NAME', "\"{$resource->environment->name}\"");
- }
- if (! $parsedServiceVariables->has('COOLIFY_PROJECT_NAME')) {
- $parsedServiceVariables->put('COOLIFY_PROJECT_NAME', "\"{$resource->project()->name}\"");
- }
-
- $parsedServiceVariables = $parsedServiceVariables->map(function ($value, $key) use ($envs_from_coolify) {
- if (! str($value)->startsWith('$')) {
- $found_env = $envs_from_coolify->where('key', $key)->first();
- if ($found_env) {
- return $found_env->value;
- }
- }
-
- return $value;
- });
-
- data_set($service, 'environment', $parsedServiceVariables->toArray());
-
- return $service;
- });
- $finalServices = [
- 'services' => $services->toArray(),
- 'volumes' => $topLevelVolumes->toArray(),
- 'networks' => $topLevelNetworks->toArray(),
- 'configs' => $topLevelConfigs->toArray(),
- 'secrets' => $topLevelSecrets->toArray(),
- ];
- $yaml = data_forget($yaml, 'services.*.volumes.*.content');
- $resource->docker_compose_raw = Yaml::dump($yaml, 10, 2);
- $resource->docker_compose = Yaml::dump($finalServices, 10, 2);
-
- $resource->save();
- $resource->saveComposeConfigs();
-
- return collect($finalServices);
- } else {
- return collect([]);
- }
- } elseif ($resource->getMorphClass() === \App\Models\Application::class) {
- try {
- $yaml = Yaml::parse($resource->docker_compose_raw);
- } catch (\Exception) {
- return;
- }
- $server = $resource->destination->server;
- $topLevelVolumes = collect(data_get($yaml, 'volumes', []));
- if ($pull_request_id !== 0) {
- $topLevelVolumes = collect([]);
- }
-
- if ($topLevelVolumes->count() > 0) {
- $tempTopLevelVolumes = collect([]);
- foreach ($topLevelVolumes as $volumeName => $volume) {
- if (is_null($volume)) {
- continue;
- }
- $tempTopLevelVolumes->put($volumeName, $volume);
- }
- $topLevelVolumes = collect($tempTopLevelVolumes);
- }
-
- $topLevelNetworks = collect(data_get($yaml, 'networks', []));
- $topLevelConfigs = collect(data_get($yaml, 'configs', []));
- $topLevelSecrets = collect(data_get($yaml, 'secrets', []));
- $services = data_get($yaml, 'services');
-
- $generatedServiceFQDNS = collect([]);
- if (is_null($resource->destination)) {
- $destination = $server->destinations()->first();
- if ($destination) {
- $resource->destination()->associate($destination);
- $resource->save();
- }
- }
- $definedNetwork = collect([$resource->uuid]);
- if ($pull_request_id !== 0) {
- $definedNetwork = collect(["{$resource->uuid}-$pull_request_id"]);
- }
- $services = collect($services)->map(function ($service, $serviceName) use ($topLevelVolumes, $topLevelNetworks, $definedNetwork, $isNew, $generatedServiceFQDNS, $resource, $server, $pull_request_id, $preview_id) {
- $serviceVolumes = collect(data_get($service, 'volumes', []));
- $servicePorts = collect(data_get($service, 'ports', []));
- $serviceNetworks = collect(data_get($service, 'networks', []));
- $serviceVariables = collect(data_get($service, 'environment', []));
- $serviceDependencies = collect(data_get($service, 'depends_on', []));
- $serviceLabels = collect(data_get($service, 'labels', []));
- $serviceBuildVariables = collect(data_get($service, 'build.args', []));
- $serviceVariables = $serviceVariables->merge($serviceBuildVariables);
- if ($serviceLabels->count() > 0) {
- $removedLabels = collect([]);
- $serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) {
- if (! str($serviceLabel)->contains('=')) {
- $removedLabels->put($serviceLabelName, $serviceLabel);
-
- return false;
- }
-
- return $serviceLabel;
- });
- foreach ($removedLabels as $removedLabelName => $removedLabel) {
- $serviceLabels->push("$removedLabelName=$removedLabel");
- }
- }
-
- $baseName = generateApplicationContainerName($resource, $pull_request_id);
- $containerName = "$serviceName-$baseName";
- if ($resource->compose_parsing_version === '1') {
- if (count($serviceVolumes) > 0) {
- $serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
- if (is_string($volume)) {
- $volume = str($volume);
- if ($volume->contains(':') && ! $volume->startsWith('/')) {
- $name = $volume->before(':');
- $mount = $volume->after(':');
- if ($name->startsWith('.') || $name->startsWith('~')) {
- $dir = base_configuration_dir().'/applications/'.$resource->uuid;
- if ($name->startsWith('.')) {
- $name = $name->replaceFirst('.', $dir);
- }
- if ($name->startsWith('~')) {
- $name = $name->replaceFirst('~', $dir);
- }
- if ($pull_request_id !== 0) {
- $name = $name."-pr-$pull_request_id";
- }
- $volume = str("$name:$mount");
- } else {
- if ($pull_request_id !== 0) {
- $name = $name."-pr-$pull_request_id";
- $volume = str("$name:$mount");
- if ($topLevelVolumes->has($name)) {
- $v = $topLevelVolumes->get($name);
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- // Do nothing
- } else {
- if (is_null(data_get($v, 'name'))) {
- data_set($v, 'name', $name);
- data_set($topLevelVolumes, $name, $v);
- }
- }
- } else {
- $topLevelVolumes->put($name, [
- 'name' => $name,
- ]);
- }
- } else {
- if ($topLevelVolumes->has($name->value())) {
- $v = $topLevelVolumes->get($name->value());
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- // Do nothing
- } else {
- if (is_null(data_get($v, 'name'))) {
- data_set($topLevelVolumes, $name->value(), $v);
- }
- }
- } else {
- $topLevelVolumes->put($name->value(), [
- 'name' => $name->value(),
- ]);
- }
- }
- }
- } else {
- if ($volume->startsWith('/')) {
- $name = $volume->before(':');
- $mount = $volume->after(':');
- if ($pull_request_id !== 0) {
- $name = $name."-pr-$pull_request_id";
- }
- $volume = str("$name:$mount");
- }
- }
- } elseif (is_array($volume)) {
- $source = data_get($volume, 'source');
- $target = data_get($volume, 'target');
- $read_only = data_get($volume, 'read_only');
- if ($source && $target) {
- if ((str($source)->startsWith('.') || str($source)->startsWith('~'))) {
- $dir = base_configuration_dir().'/applications/'.$resource->uuid;
- if (str($source, '.')) {
- $source = str($source)->replaceFirst('.', $dir);
- }
- if (str($source, '~')) {
- $source = str($source)->replaceFirst('~', $dir);
- }
- if ($pull_request_id !== 0) {
- $source = $source."-pr-$pull_request_id";
- }
- if ($read_only) {
- data_set($volume, 'source', $source.':'.$target.':ro');
- } else {
- data_set($volume, 'source', $source.':'.$target);
- }
- } else {
- if ($pull_request_id !== 0) {
- $source = $source."-pr-$pull_request_id";
- }
- if ($read_only) {
- data_set($volume, 'source', $source.':'.$target.':ro');
- } else {
- data_set($volume, 'source', $source.':'.$target);
- }
- if (! str($source)->startsWith('/')) {
- if ($topLevelVolumes->has($source)) {
- $v = $topLevelVolumes->get($source);
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- // Do nothing
- } else {
- if (is_null(data_get($v, 'name'))) {
- data_set($v, 'name', $source);
- data_set($topLevelVolumes, $source, $v);
- }
- }
- } else {
- $topLevelVolumes->put($source, [
- 'name' => $source,
- ]);
- }
- }
- }
- }
- }
- if (is_array($volume)) {
- return data_get($volume, 'source');
- }
-
- return $volume->value();
- });
- data_set($service, 'volumes', $serviceVolumes->toArray());
- }
- } elseif ($resource->compose_parsing_version === '2') {
- if (count($serviceVolumes) > 0) {
- $serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
- if (is_string($volume)) {
- $volume = str($volume);
- if ($volume->contains(':') && ! $volume->startsWith('/')) {
- $name = $volume->before(':');
- $mount = $volume->after(':');
- if ($name->startsWith('.') || $name->startsWith('~')) {
- $dir = base_configuration_dir().'/applications/'.$resource->uuid;
- if ($name->startsWith('.')) {
- $name = $name->replaceFirst('.', $dir);
- }
- if ($name->startsWith('~')) {
- $name = $name->replaceFirst('~', $dir);
- }
- if ($pull_request_id !== 0) {
- $name = $name."-pr-$pull_request_id";
- }
- $volume = str("$name:$mount");
- } else {
- if ($pull_request_id !== 0) {
- $uuid = $resource->uuid;
- $name = $uuid."-$name-pr-$pull_request_id";
- $volume = str("$name:$mount");
- if ($topLevelVolumes->has($name)) {
- $v = $topLevelVolumes->get($name);
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- // Do nothing
- } else {
- if (is_null(data_get($v, 'name'))) {
- data_set($v, 'name', $name);
- data_set($topLevelVolumes, $name, $v);
- }
- }
- } else {
- $topLevelVolumes->put($name, [
- 'name' => $name,
- ]);
- }
- } else {
- $uuid = $resource->uuid;
- $name = str($uuid."-$name");
- $volume = str("$name:$mount");
- if ($topLevelVolumes->has($name->value())) {
- $v = $topLevelVolumes->get($name->value());
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- // Do nothing
- } else {
- if (is_null(data_get($v, 'name'))) {
- data_set($topLevelVolumes, $name->value(), $v);
- }
- }
- } else {
- $topLevelVolumes->put($name->value(), [
- 'name' => $name->value(),
- ]);
- }
- }
- }
- } else {
- if ($volume->startsWith('/')) {
- $name = $volume->before(':');
- $mount = $volume->after(':');
- if ($pull_request_id !== 0) {
- $name = $name."-pr-$pull_request_id";
- }
- $volume = str("$name:$mount");
- }
- }
- } elseif (is_array($volume)) {
- $source = data_get($volume, 'source');
- $target = data_get($volume, 'target');
- $read_only = data_get($volume, 'read_only');
- if ($source && $target) {
- $uuid = $resource->uuid;
- if ((str($source)->startsWith('.') || str($source)->startsWith('~') || str($source)->startsWith('/'))) {
- $dir = base_configuration_dir().'/applications/'.$resource->uuid;
- if (str($source, '.')) {
- $source = str($source)->replaceFirst('.', $dir);
- }
- if (str($source, '~')) {
- $source = str($source)->replaceFirst('~', $dir);
- }
- if ($read_only) {
- data_set($volume, 'source', $source.':'.$target.':ro');
- } else {
- data_set($volume, 'source', $source.':'.$target);
- }
- } else {
- if ($pull_request_id === 0) {
- $source = $uuid."-$source";
- } else {
- $source = $uuid."-$source-pr-$pull_request_id";
- }
- if ($read_only) {
- data_set($volume, 'source', $source.':'.$target.':ro');
- } else {
- data_set($volume, 'source', $source.':'.$target);
- }
- if (! str($source)->startsWith('/')) {
- if ($topLevelVolumes->has($source)) {
- $v = $topLevelVolumes->get($source);
- if (data_get($v, 'driver_opts.type') === 'cifs') {
- // Do nothing
- } else {
- if (is_null(data_get($v, 'name'))) {
- data_set($v, 'name', $source);
- data_set($topLevelVolumes, $source, $v);
- }
- }
- } else {
- $topLevelVolumes->put($source, [
- 'name' => $source,
- ]);
- }
- }
- }
- }
- }
- if (is_array($volume)) {
- return data_get($volume, 'source');
- }
- dispatch(new ServerFilesFromServerJob($resource));
-
- return $volume->value();
- });
- data_set($service, 'volumes', $serviceVolumes->toArray());
- }
- }
-
- if ($pull_request_id !== 0 && count($serviceDependencies) > 0) {
- $serviceDependencies = $serviceDependencies->map(function ($dependency) use ($pull_request_id) {
- return $dependency."-pr-$pull_request_id";
- });
- data_set($service, 'depends_on', $serviceDependencies->toArray());
- }
-
- // Decide if the service is a database
- $isDatabase = isDatabaseImage(data_get_str($service, 'image'));
- data_set($service, 'is_database', $isDatabase);
-
- // Collect/create/update networks
- if ($serviceNetworks->count() > 0) {
- foreach ($serviceNetworks as $networkName => $networkDetails) {
- if ($networkName === 'default') {
- continue;
- }
- // ignore alias
- if ($networkDetails['aliases'] ?? false) {
- continue;
- }
- $networkExists = $topLevelNetworks->contains(function ($value, $key) use ($networkName) {
- return $value == $networkName || $key == $networkName;
- });
- if (! $networkExists) {
- if (is_string($networkDetails) || is_int($networkDetails)) {
- $topLevelNetworks->put($networkDetails, null);
- }
- }
- }
- }
- // Collect/create/update ports
- $collectedPorts = collect([]);
- if ($servicePorts->count() > 0) {
- foreach ($servicePorts as $sport) {
- if (is_string($sport) || is_numeric($sport)) {
- $collectedPorts->push($sport);
- }
- if (is_array($sport)) {
- $target = data_get($sport, 'target');
- $published = data_get($sport, 'published');
- $protocol = data_get($sport, 'protocol');
- $collectedPorts->push("$target:$published/$protocol");
- }
- }
- }
- $definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
- return $value == $definedNetwork;
- });
- if (! $definedNetworkExists) {
- foreach ($definedNetwork as $network) {
- if ($pull_request_id !== 0) {
- $topLevelNetworks->put($network, [
- 'name' => $network,
- 'external' => true,
- ]);
- } else {
- $topLevelNetworks->put($network, [
- 'name' => $network,
- 'external' => true,
- ]);
- }
- }
- }
- $networks = collect();
- foreach ($serviceNetworks as $key => $serviceNetwork) {
- if (gettype($serviceNetwork) === 'string') {
- // networks:
- // - appwrite
- $networks->put($serviceNetwork, null);
- } elseif (gettype($serviceNetwork) === 'array') {
- // networks:
- // default:
- // ipv4_address: 192.168.203.254
- // $networks->put($serviceNetwork, null);
- $networks->put($key, $serviceNetwork);
- }
- }
- foreach ($definedNetwork as $key => $network) {
- $networks->put($network, null);
- }
- if (data_get($resource, 'settings.connect_to_docker_network')) {
- $network = $resource->destination->network;
- $networks->put($network, null);
- $topLevelNetworks->put($network, [
- 'name' => $network,
- 'external' => true,
- ]);
- }
- data_set($service, 'networks', $networks->toArray());
- // Get variables from the service
- foreach ($serviceVariables as $variableName => $variable) {
- if (is_numeric($variableName)) {
- if (is_array($variable)) {
- // - SESSION_SECRET: 123
- // - SESSION_SECRET:
- $key = str(collect($variable)->keys()->first());
- $value = str(collect($variable)->values()->first());
- } else {
- $variable = str($variable);
- if ($variable->contains('=')) {
- // - SESSION_SECRET=123
- // - SESSION_SECRET=
- $key = $variable->before('=');
- $value = $variable->after('=');
- } else {
- // - SESSION_SECRET
- $key = $variable;
- $value = null;
- }
- }
- } else {
- // SESSION_SECRET: 123
- // SESSION_SECRET:
- $key = str($variableName);
- $value = str($variable);
- }
- if ($key->startsWith('SERVICE_FQDN')) {
- if ($isNew) {
- $name = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower();
- $fqdn = generateFqdn($server, "{$name->value()}-{$resource->uuid}");
- if (substr_count($key->value(), '_') === 3) {
- // SERVICE_FQDN_UMAMI_1000
- $port = $key->afterLast('_');
- } else {
- // SERVICE_FQDN_UMAMI
- $port = null;
- }
- if ($port) {
- $fqdn = "$fqdn:$port";
- }
- if (substr_count($key->value(), '_') >= 2) {
- if ($value) {
- $path = $value->value();
- } else {
- $path = null;
- }
- if ($generatedServiceFQDNS->count() > 0) {
- $alreadyGenerated = $generatedServiceFQDNS->has($key->value());
- if ($alreadyGenerated) {
- $fqdn = $generatedServiceFQDNS->get($key->value());
- } else {
- $generatedServiceFQDNS->put($key->value(), $fqdn);
- }
- } else {
- $generatedServiceFQDNS->put($key->value(), $fqdn);
- }
- $fqdn = "$fqdn$path";
- }
- }
-
- continue;
- }
- if ($value?->startsWith('$')) {
- $foundEnv = EnvironmentVariable::where([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- 'is_preview' => false,
- ])->first();
- $value = replaceVariables($value);
- $key = $value;
- if ($value->startsWith('SERVICE_')) {
- $foundEnv = EnvironmentVariable::where([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ])->first();
- ['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
- if (! is_null($command)) {
- if ($command?->value() === 'FQDN' || $command?->value() === 'URL') {
- if (Str::lower($forService) === $serviceName) {
- $fqdn = generateFqdn($server, $containerName);
- } else {
- $fqdn = generateFqdn($server, Str::lower($forService).'-'.$resource->uuid);
- }
- if ($port) {
- $fqdn = "$fqdn:$port";
- }
- if ($foundEnv) {
- $fqdn = data_get($foundEnv, 'value');
- } else {
- if ($command?->value() === 'URL') {
- $fqdn = str($fqdn)->after('://')->value();
- }
- EnvironmentVariable::create([
- 'key' => $key,
- 'value' => $fqdn,
- 'is_build_time' => false,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- 'is_preview' => false,
- ]);
- }
- } else {
- $generatedValue = generateEnvValue($command);
- if (! $foundEnv) {
- EnvironmentVariable::create([
- 'key' => $key,
- 'value' => $generatedValue,
- 'is_build_time' => false,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- 'is_preview' => false,
- ]);
- }
- }
- }
- } else {
- if ($value->contains(':-')) {
- $key = $value->before(':');
- $defaultValue = $value->after(':-');
- } elseif ($value->contains('-')) {
- $key = $value->before('-');
- $defaultValue = $value->after('-');
- } elseif ($value->contains(':?')) {
- $key = $value->before(':');
- $defaultValue = $value->after(':?');
- } elseif ($value->contains('?')) {
- $key = $value->before('?');
- $defaultValue = $value->after('?');
- } else {
- $key = $value;
- $defaultValue = null;
- }
- $foundEnv = EnvironmentVariable::where([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- 'is_preview' => false,
- ])->first();
- if ($foundEnv) {
- $defaultValue = data_get($foundEnv, 'value');
- }
- $isBuildTime = data_get($foundEnv, 'is_build_time', false);
- if ($foundEnv) {
- $foundEnv->update([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- 'is_build_time' => $isBuildTime,
- 'value' => $defaultValue,
- ]);
- } else {
- EnvironmentVariable::create([
- 'key' => $key,
- 'value' => $defaultValue,
- 'is_build_time' => $isBuildTime,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- 'is_preview' => false,
- ]);
- }
- }
- }
- }
- // Add labels to the service
- if ($resource->serviceType()) {
- $fqdns = generateServiceSpecificFqdns($resource);
- } else {
- $domains = collect(json_decode($resource->docker_compose_domains)) ?? [];
- if ($domains) {
- $fqdns = data_get($domains, "$serviceName.domain");
- if ($fqdns) {
- $fqdns = str($fqdns)->explode(',');
- if ($pull_request_id !== 0) {
- $preview = $resource->previews()->find($preview_id);
- $docker_compose_domains = collect(json_decode(data_get($preview, 'docker_compose_domains')));
- if ($docker_compose_domains->count() > 0) {
- $found_fqdn = data_get($docker_compose_domains, "$serviceName.domain");
- if ($found_fqdn) {
- $fqdns = collect($found_fqdn);
- } else {
- $fqdns = collect([]);
- }
- } else {
- $fqdns = $fqdns->map(function ($fqdn) use ($pull_request_id, $resource) {
- $preview = ApplicationPreview::findPreviewByApplicationAndPullId($resource->id, $pull_request_id);
- $url = Url::fromString($fqdn);
- $template = $resource->preview_url_template;
- $host = $url->getHost();
- $schema = $url->getScheme();
- $random = new Cuid2;
- $preview_fqdn = str_replace('{{random}}', $random, $template);
- $preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
- $preview_fqdn = str_replace('{{pr_id}}', $pull_request_id, $preview_fqdn);
- $preview_fqdn = "$schema://$preview_fqdn";
- $preview->fqdn = $preview_fqdn;
- $preview->save();
-
- return $preview_fqdn;
- });
- }
- }
- $shouldGenerateLabelsExactly = $server->settings->generate_exact_labels;
- if ($shouldGenerateLabelsExactly) {
- switch ($server->proxyType()) {
- case ProxyTypes::TRAEFIK->value:
- $serviceLabels = $serviceLabels->merge(
- fqdnLabelsForTraefik(
- uuid: $resource->uuid,
- domains: $fqdns,
- serviceLabels: $serviceLabels,
- generate_unique_uuid: $resource->build_pack === 'dockercompose',
- image: data_get($service, 'image'),
- is_force_https_enabled: $resource->isForceHttpsEnabled(),
- is_gzip_enabled: $resource->isGzipEnabled(),
- is_stripprefix_enabled: $resource->isStripprefixEnabled(),
- )
- );
- break;
- case ProxyTypes::CADDY->value:
- $serviceLabels = $serviceLabels->merge(
- fqdnLabelsForCaddy(
- network: $resource->destination->network,
- uuid: $resource->uuid,
- domains: $fqdns,
- serviceLabels: $serviceLabels,
- image: data_get($service, 'image'),
- is_force_https_enabled: $resource->isForceHttpsEnabled(),
- is_gzip_enabled: $resource->isGzipEnabled(),
- is_stripprefix_enabled: $resource->isStripprefixEnabled(),
- )
- );
- break;
- }
- } else {
- $serviceLabels = $serviceLabels->merge(
- fqdnLabelsForTraefik(
- uuid: $resource->uuid,
- domains: $fqdns,
- serviceLabels: $serviceLabels,
- generate_unique_uuid: $resource->build_pack === 'dockercompose',
- image: data_get($service, 'image'),
- is_force_https_enabled: $resource->isForceHttpsEnabled(),
- is_gzip_enabled: $resource->isGzipEnabled(),
- is_stripprefix_enabled: $resource->isStripprefixEnabled(),
- )
- );
- $serviceLabels = $serviceLabels->merge(
- fqdnLabelsForCaddy(
- network: $resource->destination->network,
- uuid: $resource->uuid,
- domains: $fqdns,
- serviceLabels: $serviceLabels,
- image: data_get($service, 'image'),
- is_force_https_enabled: $resource->isForceHttpsEnabled(),
- is_gzip_enabled: $resource->isGzipEnabled(),
- is_stripprefix_enabled: $resource->isStripprefixEnabled(),
- )
- );
- }
- }
- }
- }
-
- $defaultLabels = defaultLabels(
- id: $resource->id,
- name: $containerName,
- projectName: $resource->project()->name,
- resourceName: $resource->name,
- environment: $resource->environment->name,
- pull_request_id: $pull_request_id,
- type: 'application'
- );
- $serviceLabels = $serviceLabels->merge($defaultLabels);
-
- if ($server->isLogDrainEnabled()) {
- if ($resource instanceof Application && $resource->isLogDrainEnabled()) {
- data_set($service, 'logging', generate_fluentd_configuration());
- }
- }
- if ($serviceLabels->count() > 0) {
- if ($resource->settings->is_container_label_escape_enabled) {
- $serviceLabels = $serviceLabels->map(function ($value, $key) {
- return escapeDollarSign($value);
- });
- }
- }
- data_set($service, 'labels', $serviceLabels->toArray());
- data_forget($service, 'is_database');
- if (! data_get($service, 'restart')) {
- data_set($service, 'restart', RESTART_MODE);
- }
- data_set($service, 'container_name', $containerName);
- data_forget($service, 'volumes.*.content');
- data_forget($service, 'volumes.*.isDirectory');
- data_forget($service, 'volumes.*.is_directory');
- data_forget($service, 'exclude_from_hc');
- data_set($service, 'environment', $serviceVariables->toArray());
-
- return $service;
- });
- if ($pull_request_id !== 0) {
- $services->each(function ($service, $serviceName) use ($pull_request_id, $services) {
- $services[$serviceName."-pr-$pull_request_id"] = $service;
- data_forget($services, $serviceName);
- });
- }
- $finalServices = [
- 'services' => $services->toArray(),
- 'volumes' => $topLevelVolumes->toArray(),
- 'networks' => $topLevelNetworks->toArray(),
- 'configs' => $topLevelConfigs->toArray(),
- 'secrets' => $topLevelSecrets->toArray(),
- ];
- $resource->docker_compose_raw = Yaml::dump($yaml, 10, 2);
- $resource->docker_compose = Yaml::dump($finalServices, 10, 2);
- data_forget($resource, 'environment_variables');
- data_forget($resource, 'environment_variables_preview');
- $resource->save();
-
- return collect($finalServices);
- }
-}
-
-function newParser(Application|Service $resource, int $pull_request_id = 0, ?int $preview_id = null): Collection
-{
- $isApplication = $resource instanceof Application;
- $isService = $resource instanceof Service;
-
- $uuid = data_get($resource, 'uuid');
- $compose = data_get($resource, 'docker_compose_raw');
- if (! $compose) {
- return collect([]);
- }
-
- if ($isApplication) {
- $pullRequestId = $pull_request_id;
- $isPullRequest = $pullRequestId == 0 ? false : true;
- $server = data_get($resource, 'destination.server');
- $fileStorages = $resource->fileStorages();
- } elseif ($isService) {
- $server = data_get($resource, 'server');
- $allServices = get_service_templates();
- } else {
- return collect([]);
- }
-
- try {
- $yaml = Yaml::parse($compose);
- } catch (\Exception) {
- return collect([]);
- }
-
- $services = data_get($yaml, 'services', collect([]));
- $topLevel = collect([
- 'volumes' => collect(data_get($yaml, 'volumes', [])),
- 'networks' => collect(data_get($yaml, 'networks', [])),
- 'configs' => collect(data_get($yaml, 'configs', [])),
- 'secrets' => collect(data_get($yaml, 'secrets', [])),
- ]);
- // If there are predefined volumes, make sure they are not null
- if ($topLevel->get('volumes')->count() > 0) {
- $temp = collect([]);
- foreach ($topLevel['volumes'] as $volumeName => $volume) {
- if (is_null($volume)) {
- continue;
- }
- $temp->put($volumeName, $volume);
- }
- $topLevel['volumes'] = $temp;
- }
- // Get the base docker network
- $baseNetwork = collect([$uuid]);
- if ($isApplication && $isPullRequest) {
- $baseNetwork = collect(["{$uuid}-{$pullRequestId}"]);
- }
-
- $parsedServices = collect([]);
-
- $allMagicEnvironments = collect([]);
- foreach ($services as $serviceName => $service) {
- $predefinedPort = null;
- $magicEnvironments = collect([]);
- $image = data_get_str($service, 'image');
- $environment = collect(data_get($service, 'environment', []));
- $buildArgs = collect(data_get($service, 'build.args', []));
- $environment = $environment->merge($buildArgs);
- $isDatabase = isDatabaseImage(data_get_str($service, 'image'));
-
- if ($isService) {
- $containerName = "$serviceName-{$resource->uuid}";
-
- if ($serviceName === 'registry') {
- $tempServiceName = 'docker-registry';
- } else {
- $tempServiceName = $serviceName;
- }
- if (str(data_get($service, 'image'))->contains('glitchtip')) {
- $tempServiceName = 'glitchtip';
- }
- if ($serviceName === 'supabase-kong') {
- $tempServiceName = 'supabase';
- }
- $serviceDefinition = data_get($allServices, $tempServiceName);
- $predefinedPort = data_get($serviceDefinition, 'port');
- if ($serviceName === 'plausible') {
- $predefinedPort = '8000';
- }
- if ($isDatabase) {
- $applicationFound = ServiceApplication::where('name', $serviceName)->where('image', $image)->where('service_id', $resource->id)->first();
- if ($applicationFound) {
- $savedService = $applicationFound;
- $savedService = ServiceDatabase::firstOrCreate([
- 'name' => $applicationFound->name,
- 'image' => $applicationFound->image,
- 'service_id' => $applicationFound->service_id,
- ]);
- $applicationFound->delete();
- } else {
- $savedService = ServiceDatabase::firstOrCreate([
- 'name' => $serviceName,
- 'image' => $image,
- 'service_id' => $resource->id,
- ]);
- }
- } else {
- $savedService = ServiceApplication::firstOrCreate([
- 'name' => $serviceName,
- 'image' => $image,
- 'service_id' => $resource->id,
- ]);
- }
- $environment = collect(data_get($service, 'environment', []));
- $buildArgs = collect(data_get($service, 'build.args', []));
- $environment = $environment->merge($buildArgs);
-
- // convert environment variables to one format
- $environment = convertToKeyValueCollection($environment);
-
- // Add Coolify defined environments
- $allEnvironments = $resource->environment_variables()->get(['key', 'value']);
-
- $allEnvironments = $allEnvironments->mapWithKeys(function ($item) {
- return [$item['key'] => $item['value']];
- });
- // filter and add magic environments
- foreach ($environment as $key => $value) {
- // Get all SERVICE_ variables from keys and values
- $key = str($key);
- $value = str($value);
-
- $regex = '/\$(\{?([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\}?)/';
- preg_match_all($regex, $value, $valueMatches);
- if (count($valueMatches[1]) > 0) {
- foreach ($valueMatches[1] as $match) {
- $match = replaceVariables($match);
- if ($match->startsWith('SERVICE_')) {
- if ($magicEnvironments->has($match->value())) {
- continue;
- }
- $magicEnvironments->put($match->value(), '');
- }
- }
- }
-
- // Get magic environments where we need to preset the FQDN
- if ($key->startsWith('SERVICE_FQDN_')) {
- // SERVICE_FQDN_APP or SERVICE_FQDN_APP_3000
- if (substr_count(str($key)->value(), '_') === 3) {
- $fqdnFor = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower()->value();
- $port = $key->afterLast('_')->value();
- } else {
- $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value();
- $port = null;
- }
- if ($isApplication) {
- $fqdn = generateFqdn($server, "{$resource->name}-$uuid");
- } elseif ($isService) {
- if ($fqdnFor) {
- $fqdn = generateFqdn($server, "$fqdnFor-$uuid");
- } else {
- $fqdn = generateFqdn($server, "{$savedService->name}-$uuid");
- }
- }
-
- if ($value && get_class($value) === \Illuminate\Support\Stringable::class && $value->startsWith('/')) {
- $path = $value->value();
- if ($path !== '/') {
- $fqdn = "$fqdn$path";
- }
- }
- $fqdnWithPort = $fqdn;
- if ($port) {
- $fqdnWithPort = "$fqdn:$port";
- }
- if ($isApplication && is_null($resource->fqdn)) {
- data_forget($resource, 'environment_variables');
- data_forget($resource, 'environment_variables_preview');
- $resource->fqdn = $fqdnWithPort;
- $resource->save();
- } elseif ($isService && is_null($savedService->fqdn)) {
- $savedService->fqdn = $fqdnWithPort;
- $savedService->save();
- }
-
- if (substr_count(str($key)->value(), '_') === 2) {
- $resource->environment_variables()->firstOrCreate([
- 'key' => $key->value(),
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ], [
- 'value' => $fqdn,
- 'is_build_time' => false,
- 'is_preview' => false,
- ]);
- }
- if (substr_count(str($key)->value(), '_') === 3) {
- $newKey = str($key)->beforeLast('_');
- $resource->environment_variables()->firstOrCreate([
- 'key' => $newKey->value(),
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ], [
- 'value' => $fqdn,
- 'is_build_time' => false,
- 'is_preview' => false,
- ]);
- }
- }
- }
-
- $allMagicEnvironments = $allMagicEnvironments->merge($magicEnvironments);
- if ($magicEnvironments->count() > 0) {
- foreach ($magicEnvironments as $key => $value) {
- $key = str($key);
- $value = replaceVariables($value);
- $command = parseCommandFromMagicEnvVariable($key);
- $found = $resource->environment_variables()->where('key', $key->value())->where('resourceable_type', get_class($resource))->where('resourceable_id', $resource->id)->first();
- if ($found) {
- continue;
- }
- if ($command->value() === 'FQDN') {
- $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value();
- if (str($fqdnFor)->contains('_')) {
- $fqdnFor = str($fqdnFor)->before('_');
- }
- if ($isApplication) {
- $fqdn = generateFqdn($server, "{$resource->name}-$uuid");
- } elseif ($isService) {
- $fqdn = generateFqdn($server, "$fqdnFor-$uuid");
- }
- $resource->environment_variables()->firstOrCreate([
- 'key' => $key->value(),
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ], [
- 'value' => $fqdn,
- 'is_build_time' => false,
- 'is_preview' => false,
- ]);
- } elseif ($command->value() === 'URL') {
- $fqdnFor = $key->after('SERVICE_URL_')->lower()->value();
- if (str($fqdnFor)->contains('_')) {
- $fqdnFor = str($fqdnFor)->before('_');
- }
- if ($isApplication) {
- $fqdn = generateFqdn($server, "{$resource->name}-$uuid");
- } elseif ($isService) {
- $fqdn = generateFqdn($server, "$fqdnFor-$uuid");
- }
- $fqdn = str($fqdn)->replace('http://', '')->replace('https://', '');
- $resource->environment_variables()->firstOrCreate([
- 'key' => $key->value(),
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ], [
- 'value' => $fqdn,
- 'is_build_time' => false,
- 'is_preview' => false,
- ]);
- } else {
- $value = generateEnvValue($command, $resource);
- $resource->environment_variables()->firstOrCreate([
- 'key' => $key->value(),
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ], [
- 'value' => $value,
- 'is_build_time' => false,
- 'is_preview' => false,
- ]);
- }
- }
- }
- }
- }
-
- // Parse the rest of the services
- foreach ($services as $serviceName => $service) {
- $image = data_get_str($service, 'image');
- $restart = data_get_str($service, 'restart', RESTART_MODE);
- $logging = data_get($service, 'logging');
-
- if ($server->isLogDrainEnabled()) {
- if ($resource instanceof Application && $resource->isLogDrainEnabled()) {
- $logging = generate_fluentd_configuration();
- }
- }
- $volumes = collect(data_get($service, 'volumes', []));
- $networks = collect(data_get($service, 'networks', []));
- $use_network_mode = data_get($service, 'network_mode') !== null;
- $depends_on = collect(data_get($service, 'depends_on', []));
- $labels = collect(data_get($service, 'labels', []));
- $environment = collect(data_get($service, 'environment', []));
- $ports = collect(data_get($service, 'ports', []));
- $buildArgs = collect(data_get($service, 'build.args', []));
- $environment = $environment->merge($buildArgs);
-
- $environment = convertToKeyValueCollection($environment);
- $coolifyEnvironments = collect([]);
-
- $isDatabase = isDatabaseImage(data_get_str($service, 'image'));
- $volumesParsed = collect([]);
-
- if ($isApplication) {
- $baseName = generateApplicationContainerName(
- application: $resource,
- pull_request_id: $pullRequestId
- );
- $containerName = "$serviceName-$baseName";
- $predefinedPort = null;
- } elseif ($isService) {
- $containerName = "$serviceName-{$resource->uuid}";
-
- if ($serviceName === 'registry') {
- $tempServiceName = 'docker-registry';
- } else {
- $tempServiceName = $serviceName;
- }
- if (str(data_get($service, 'image'))->contains('glitchtip')) {
- $tempServiceName = 'glitchtip';
- }
- if ($serviceName === 'supabase-kong') {
- $tempServiceName = 'supabase';
- }
- $serviceDefinition = data_get($allServices, $tempServiceName);
- $predefinedPort = data_get($serviceDefinition, 'port');
- if ($serviceName === 'plausible') {
- $predefinedPort = '8000';
- }
-
- if ($isDatabase) {
- $applicationFound = ServiceApplication::where('name', $serviceName)->where('image', $image)->where('service_id', $resource->id)->first();
- if ($applicationFound) {
- $savedService = $applicationFound;
- $savedService = ServiceDatabase::firstOrCreate([
- 'name' => $applicationFound->name,
- 'image' => $applicationFound->image,
- 'service_id' => $applicationFound->service_id,
- ]);
- $applicationFound->delete();
- } else {
- $savedService = ServiceDatabase::firstOrCreate([
- 'name' => $serviceName,
- 'image' => $image,
- 'service_id' => $resource->id,
- ]);
- }
- } else {
- $savedService = ServiceApplication::firstOrCreate([
- 'name' => $serviceName,
- 'image' => $image,
- 'service_id' => $resource->id,
- ]);
- }
- $fileStorages = $savedService->fileStorages();
- if ($savedService->image !== $image) {
- $savedService->image = $image;
- $savedService->save();
- }
- }
-
- $originalResource = $isApplication ? $resource : $savedService;
-
- if ($volumes->count() > 0) {
- foreach ($volumes as $index => $volume) {
- $type = null;
- $source = null;
- $target = null;
- $content = null;
- $isDirectory = false;
- if (is_string($volume)) {
- $source = str($volume)->before(':');
- $target = str($volume)->after(':')->beforeLast(':');
- $foundConfig = $fileStorages->whereMountPath($target)->first();
- if (sourceIsLocal($source)) {
- $type = str('bind');
- if ($foundConfig) {
- $contentNotNull_temp = data_get($foundConfig, 'content');
- if ($contentNotNull_temp) {
- $content = $contentNotNull_temp;
- }
- $isDirectory = data_get($foundConfig, 'is_directory');
- } else {
- // By default, we cannot determine if the bind is a directory or not, so we set it to directory
- $isDirectory = true;
- }
- } else {
- $type = str('volume');
- }
- } elseif (is_array($volume)) {
- $type = data_get_str($volume, 'type');
- $source = data_get_str($volume, 'source');
- $target = data_get_str($volume, 'target');
- $content = data_get($volume, 'content');
- $isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
-
- $foundConfig = $fileStorages->whereMountPath($target)->first();
- if ($foundConfig) {
- $contentNotNull_temp = data_get($foundConfig, 'content');
- if ($contentNotNull_temp) {
- $content = $contentNotNull_temp;
- }
- $isDirectory = data_get($foundConfig, 'is_directory');
- } else {
- // if isDirectory is not set (or false) & content is also not set, we assume it is a directory
- if ((is_null($isDirectory) || ! $isDirectory) && is_null($content)) {
- $isDirectory = true;
- }
- }
- }
- if ($type->value() === 'bind') {
- if ($source->value() === '/var/run/docker.sock') {
- $volume = $source->value().':'.$target->value();
- } elseif ($source->value() === '/tmp' || $source->value() === '/tmp/') {
- $volume = $source->value().':'.$target->value();
- } else {
- if ((int) $resource->compose_parsing_version >= 4) {
- if ($isApplication) {
- $mainDirectory = str(base_configuration_dir().'/applications/'.$uuid);
- } elseif ($isService) {
- $mainDirectory = str(base_configuration_dir().'/services/'.$uuid);
- }
- } else {
- $mainDirectory = str(base_configuration_dir().'/applications/'.$uuid);
- }
- $source = replaceLocalSource($source, $mainDirectory);
- if ($isApplication && $isPullRequest) {
- $source = $source."-pr-$pullRequestId";
- }
- LocalFileVolume::updateOrCreate(
- [
- 'mount_path' => $target,
- 'resource_id' => $originalResource->id,
- 'resource_type' => get_class($originalResource),
- ],
- [
- 'fs_path' => $source,
- 'mount_path' => $target,
- 'content' => $content,
- 'is_directory' => $isDirectory,
- 'resource_id' => $originalResource->id,
- 'resource_type' => get_class($originalResource),
- ]
- );
- if (isDev()) {
- if ((int) $resource->compose_parsing_version >= 4) {
- if ($isApplication) {
- $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/'.$uuid);
- } elseif ($isService) {
- $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/services/'.$uuid);
- }
- } else {
- $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/'.$uuid);
- }
- }
- $volume = "$source:$target";
- }
- } elseif ($type->value() === 'volume') {
- if ($topLevel->get('volumes')->has($source->value())) {
- $temp = $topLevel->get('volumes')->get($source->value());
- if (data_get($temp, 'driver_opts.type') === 'cifs') {
- continue;
- }
- if (data_get($temp, 'driver_opts.type') === 'nfs') {
- continue;
- }
- }
- $slugWithoutUuid = Str::slug($source, '-');
- $name = "{$uuid}_{$slugWithoutUuid}";
-
- if ($isApplication && $isPullRequest) {
- $name = "{$name}-pr-$pullRequestId";
- }
- if (is_string($volume)) {
- $source = str($volume)->before(':');
- $target = str($volume)->after(':')->beforeLast(':');
- $source = $name;
- $volume = "$source:$target";
- } elseif (is_array($volume)) {
- data_set($volume, 'source', $name);
- }
- $topLevel->get('volumes')->put($name, [
- 'name' => $name,
- ]);
- LocalPersistentVolume::updateOrCreate(
- [
- 'name' => $name,
- 'resource_id' => $originalResource->id,
- 'resource_type' => get_class($originalResource),
- ],
- [
- 'name' => $name,
- 'mount_path' => $target,
- 'resource_id' => $originalResource->id,
- 'resource_type' => get_class($originalResource),
- ]
- );
- }
- dispatch(new ServerFilesFromServerJob($originalResource));
- $volumesParsed->put($index, $volume);
- }
- }
-
- if ($depends_on?->count() > 0) {
- if ($isApplication && $isPullRequest) {
- $newDependsOn = collect([]);
- $depends_on->each(function ($dependency, $condition) use ($pullRequestId, $newDependsOn) {
- if (is_numeric($condition)) {
- $dependency = "$dependency-pr-$pullRequestId";
-
- $newDependsOn->put($condition, $dependency);
- } else {
- $condition = "$condition-pr-$pullRequestId";
- $newDependsOn->put($condition, $dependency);
- }
- });
- $depends_on = $newDependsOn;
- }
- }
- if (! $use_network_mode) {
- if ($topLevel->get('networks')?->count() > 0) {
- foreach ($topLevel->get('networks') as $networkName => $network) {
- if ($networkName === 'default') {
- continue;
- }
- // ignore aliases
- if ($network['aliases'] ?? false) {
- continue;
- }
- $networkExists = $networks->contains(function ($value, $key) use ($networkName) {
- return $value == $networkName || $key == $networkName;
- });
- if (! $networkExists) {
- $networks->put($networkName, null);
- }
- }
- }
- $baseNetworkExists = $networks->contains(function ($value, $_) use ($baseNetwork) {
- return $value == $baseNetwork;
- });
- if (! $baseNetworkExists) {
- foreach ($baseNetwork as $network) {
- $topLevel->get('networks')->put($network, [
- 'name' => $network,
- 'external' => true,
- ]);
- }
- }
- }
-
- // Collect/create/update ports
- $collectedPorts = collect([]);
- if ($ports->count() > 0) {
- foreach ($ports as $sport) {
- if (is_string($sport) || is_numeric($sport)) {
- $collectedPorts->push($sport);
- }
- if (is_array($sport)) {
- $target = data_get($sport, 'target');
- $published = data_get($sport, 'published');
- $protocol = data_get($sport, 'protocol');
- $collectedPorts->push("$target:$published/$protocol");
- }
- }
- }
- if ($isService) {
- $originalResource->ports = $collectedPorts->implode(',');
- $originalResource->save();
- }
-
- $networks_temp = collect();
-
- if (! $use_network_mode) {
- foreach ($networks as $key => $network) {
- if (gettype($network) === 'string') {
- // networks:
- // - appwrite
- $networks_temp->put($network, null);
- } elseif (gettype($network) === 'array') {
- // networks:
- // default:
- // ipv4_address: 192.168.203.254
- $networks_temp->put($key, $network);
- }
- }
- foreach ($baseNetwork as $key => $network) {
- $networks_temp->put($network, null);
- }
-
- if ($isApplication) {
- if (data_get($resource, 'settings.connect_to_docker_network')) {
- $network = $resource->destination->network;
- $networks_temp->put($network, null);
- $topLevel->get('networks')->put($network, [
- 'name' => $network,
- 'external' => true,
- ]);
- }
- }
- }
-
- $normalEnvironments = $environment->diffKeys($allMagicEnvironments);
- $normalEnvironments = $normalEnvironments->filter(function ($value, $key) {
- return ! str($value)->startsWith('SERVICE_');
- });
-
- foreach ($normalEnvironments as $key => $value) {
- $key = str($key);
- $value = str($value);
- $originalValue = $value;
- $parsedValue = replaceVariables($value);
- if ($value->startsWith('$SERVICE_')) {
- $resource->environment_variables()->firstOrCreate([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ], [
- 'value' => $value,
- 'is_build_time' => false,
- 'is_preview' => false,
- ]);
-
- continue;
- }
- if (! $value->startsWith('$')) {
- continue;
- }
- if ($key->value() === $parsedValue->value()) {
- $value = null;
- $resource->environment_variables()->firstOrCreate([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ], [
- 'value' => $value,
- 'is_build_time' => false,
- 'is_preview' => false,
- ]);
- } else {
- if ($value->startsWith('$')) {
- $isRequired = false;
- if ($value->contains(':-')) {
- $value = replaceVariables($value);
- $key = $value->before(':');
- $value = $value->after(':-');
- } elseif ($value->contains('-')) {
- $value = replaceVariables($value);
-
- $key = $value->before('-');
- $value = $value->after('-');
- } elseif ($value->contains(':?')) {
- $value = replaceVariables($value);
-
- $key = $value->before(':');
- $value = $value->after(':?');
- $isRequired = true;
- } elseif ($value->contains('?')) {
- $value = replaceVariables($value);
-
- $key = $value->before('?');
- $value = $value->after('?');
- $isRequired = true;
- }
- if ($originalValue->value() === $value->value()) {
- // This means the variable does not have a default value, so it needs to be created in Coolify
- $parsedKeyValue = replaceVariables($value);
- $resource->environment_variables()->firstOrCreate([
- 'key' => $parsedKeyValue,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ], [
- 'is_build_time' => false,
- 'is_preview' => false,
- 'is_required' => $isRequired,
- ]);
- // Add the variable to the environment so it will be shown in the deployable compose file
- $environment[$parsedKeyValue->value()] = $resource->environment_variables()->where('key', $parsedKeyValue)->where('resourceable_type', get_class($resource))->where('resourceable_id', $resource->id)->first()->value;
-
- continue;
- }
- $resource->environment_variables()->firstOrCreate([
- 'key' => $key,
- 'resourceable_type' => get_class($resource),
- 'resourceable_id' => $resource->id,
- ], [
- 'value' => $value,
- 'is_build_time' => false,
- 'is_preview' => false,
- 'is_required' => $isRequired,
- ]);
- }
- }
- }
- if ($isApplication) {
- $branch = $originalResource->git_branch;
- if ($pullRequestId !== 0) {
- $branch = "pull/{$pullRequestId}/head";
- }
- if ($originalResource->environment_variables->where('key', 'COOLIFY_BRANCH')->isEmpty()) {
- $coolifyEnvironments->put('COOLIFY_BRANCH', "\"{$branch}\"");
- }
- }
-
- // Add COOLIFY_RESOURCE_UUID to environment
- if ($resource->environment_variables->where('key', 'COOLIFY_RESOURCE_UUID')->isEmpty()) {
- $coolifyEnvironments->put('COOLIFY_RESOURCE_UUID', "{$resource->uuid}");
- }
-
- // Add COOLIFY_CONTAINER_NAME to environment
- if ($resource->environment_variables->where('key', 'COOLIFY_CONTAINER_NAME')->isEmpty()) {
- $coolifyEnvironments->put('COOLIFY_CONTAINER_NAME', "{$containerName}");
- }
-
- if ($isApplication) {
- $domains = collect(json_decode($resource->docker_compose_domains)) ?? collect([]);
- $fqdns = data_get($domains, "$serviceName.domain");
- if ($fqdns) {
- $fqdns = str($fqdns)->explode(',');
- if ($isPullRequest) {
- $preview = $resource->previews()->find($preview_id);
- $docker_compose_domains = collect(json_decode(data_get($preview, 'docker_compose_domains')));
- if ($docker_compose_domains->count() > 0) {
- $found_fqdn = data_get($docker_compose_domains, "$serviceName.domain");
- if ($found_fqdn) {
- $fqdns = collect($found_fqdn);
- } else {
- $fqdns = collect([]);
- }
- } else {
- $fqdns = $fqdns->map(function ($fqdn) use ($pullRequestId, $resource) {
- $preview = ApplicationPreview::findPreviewByApplicationAndPullId($resource->id, $pullRequestId);
- $url = Url::fromString($fqdn);
- $template = $resource->preview_url_template;
- $host = $url->getHost();
- $schema = $url->getScheme();
- $random = new Cuid2;
- $preview_fqdn = str_replace('{{random}}', $random, $template);
- $preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
- $preview_fqdn = str_replace('{{pr_id}}', $pullRequestId, $preview_fqdn);
- $preview_fqdn = "$schema://$preview_fqdn";
- $preview->fqdn = $preview_fqdn;
- $preview->save();
-
- return $preview_fqdn;
- });
- }
- }
- }
-
- $defaultLabels = defaultLabels(
- id: $resource->id,
- name: $containerName,
- projectName: $resource->project()->name,
- resourceName: $resource->name,
- pull_request_id: $pullRequestId,
- type: 'application',
- environment: $resource->environment->name,
- );
- } elseif ($isService) {
- if ($savedService->serviceType()) {
- $fqdns = generateServiceSpecificFqdns($savedService);
- } else {
- $fqdns = collect(data_get($savedService, 'fqdns'))->filter();
- }
-
- $defaultLabels = defaultLabels(
- id: $resource->id,
- name: $containerName,
- projectName: $resource->project()->name,
- resourceName: $resource->name,
- type: 'service',
- subType: $isDatabase ? 'database' : 'application',
- subId: $savedService->id,
- subName: $savedService->human_name ?? $savedService->name,
- environment: $resource->environment->name,
- );
- }
- // Add COOLIFY_FQDN & COOLIFY_URL to environment
- if (! $isDatabase && $fqdns instanceof Collection && $fqdns->count() > 0) {
- $coolifyEnvironments->put('COOLIFY_URL', $fqdns->implode(','));
-
- $urls = $fqdns->map(function ($fqdn) {
- return str($fqdn)->replace('http://', '')->replace('https://', '');
- });
- $coolifyEnvironments->put('COOLIFY_FQDN', $urls->implode(','));
- }
- add_coolify_default_environment_variables($resource, $coolifyEnvironments, $resource->environment_variables);
-
- if ($environment->count() > 0) {
- $environment = $environment->filter(function ($value, $key) {
- return ! str($key)->startsWith('SERVICE_FQDN_');
- })->map(function ($value, $key) use ($resource) {
- // if value is empty, set it to null so if you set the environment variable in the .env file (Coolify's UI), it will used
- if (str($value)->isEmpty()) {
- if ($resource->environment_variables()->where('key', $key)->exists()) {
- $value = $resource->environment_variables()->where('key', $key)->first()->value;
- } else {
- $value = null;
- }
- }
-
- return $value;
- });
- }
- $serviceLabels = $labels->merge($defaultLabels);
- if ($serviceLabels->count() > 0) {
- if ($isApplication) {
- $isContainerLabelEscapeEnabled = data_get($resource, 'settings.is_container_label_escape_enabled');
- } else {
- $isContainerLabelEscapeEnabled = data_get($resource, 'is_container_label_escape_enabled');
- }
- if ($isContainerLabelEscapeEnabled) {
- $serviceLabels = $serviceLabels->map(function ($value, $key) {
- return escapeDollarSign($value);
- });
- }
- }
- if (! $isDatabase && $fqdns instanceof Collection && $fqdns->count() > 0) {
- if ($isApplication) {
- $shouldGenerateLabelsExactly = $resource->destination->server->settings->generate_exact_labels;
- $uuid = $resource->uuid;
- $network = data_get($resource, 'destination.network');
- if ($isPullRequest) {
- $uuid = "{$resource->uuid}-{$pullRequestId}";
- }
- if ($isPullRequest) {
- $network = "{$resource->destination->network}-{$pullRequestId}";
- }
- } else {
- $shouldGenerateLabelsExactly = $resource->server->settings->generate_exact_labels;
- $uuid = $resource->uuid;
- $network = data_get($resource, 'destination.network');
- }
- if ($shouldGenerateLabelsExactly) {
- switch ($server->proxyType()) {
- case ProxyTypes::TRAEFIK->value:
- $serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik(
- uuid: $uuid,
- domains: $fqdns,
- is_force_https_enabled: true,
- serviceLabels: $serviceLabels,
- is_gzip_enabled: $originalResource->isGzipEnabled(),
- is_stripprefix_enabled: $originalResource->isStripprefixEnabled(),
- service_name: $serviceName,
- image: $image
- ));
- break;
- case ProxyTypes::CADDY->value:
- $serviceLabels = $serviceLabels->merge(fqdnLabelsForCaddy(
- network: $network,
- uuid: $uuid,
- domains: $fqdns,
- is_force_https_enabled: true,
- serviceLabels: $serviceLabels,
- is_gzip_enabled: $originalResource->isGzipEnabled(),
- is_stripprefix_enabled: $originalResource->isStripprefixEnabled(),
- service_name: $serviceName,
- image: $image,
- predefinedPort: $predefinedPort
- ));
- break;
- }
- } else {
- $serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik(
- uuid: $uuid,
- domains: $fqdns,
- is_force_https_enabled: true,
- serviceLabels: $serviceLabels,
- is_gzip_enabled: $originalResource->isGzipEnabled(),
- is_stripprefix_enabled: $originalResource->isStripprefixEnabled(),
- service_name: $serviceName,
- image: $image
- ));
- $serviceLabels = $serviceLabels->merge(fqdnLabelsForCaddy(
- network: $network,
- uuid: $uuid,
- domains: $fqdns,
- is_force_https_enabled: true,
- serviceLabels: $serviceLabels,
- is_gzip_enabled: $originalResource->isGzipEnabled(),
- is_stripprefix_enabled: $originalResource->isStripprefixEnabled(),
- service_name: $serviceName,
- image: $image,
- predefinedPort: $predefinedPort
- ));
- }
- }
- if ($isService) {
- if (data_get($service, 'restart') === 'no' || data_get($service, 'exclude_from_hc')) {
- $savedService->update(['exclude_from_status' => true]);
- }
- }
- data_forget($service, 'volumes.*.content');
- data_forget($service, 'volumes.*.isDirectory');
- data_forget($service, 'volumes.*.is_directory');
- data_forget($service, 'exclude_from_hc');
-
- $volumesParsed = $volumesParsed->map(function ($volume) {
- data_forget($volume, 'content');
- data_forget($volume, 'is_directory');
- data_forget($volume, 'isDirectory');
-
- return $volume;
- });
-
- $payload = collect($service)->merge([
- 'container_name' => $containerName,
- 'restart' => $restart->value(),
- 'labels' => $serviceLabels,
- ]);
- if (! $use_network_mode) {
- $payload['networks'] = $networks_temp;
- }
- if ($ports->count() > 0) {
- $payload['ports'] = $ports;
- }
- if ($volumesParsed->count() > 0) {
- $payload['volumes'] = $volumesParsed;
- }
- if ($environment->count() > 0 || $coolifyEnvironments->count() > 0) {
- $payload['environment'] = $environment->merge($coolifyEnvironments);
- }
- if ($logging) {
- $payload['logging'] = $logging;
- }
- if ($depends_on->count() > 0) {
- $payload['depends_on'] = $depends_on;
- }
- if ($isApplication && $isPullRequest) {
- $serviceName = "{$serviceName}-pr-{$pullRequestId}";
- }
-
- $parsedServices->put($serviceName, $payload);
- }
- $topLevel->put('services', $parsedServices);
-
- $customOrder = ['services', 'volumes', 'networks', 'configs', 'secrets'];
-
- $topLevel = $topLevel->sortBy(function ($value, $key) use ($customOrder) {
- return array_search($key, $customOrder);
- });
-
- $resource->docker_compose = Yaml::dump(convertToArray($topLevel), 10, 2);
- data_forget($resource, 'environment_variables');
- data_forget($resource, 'environment_variables_preview');
- $resource->save();
-
- return $topLevel;
-}
-
-function generate_fluentd_configuration(): array
-{
- return [
- 'driver' => 'fluentd',
- 'options' => [
- 'fluentd-address' => 'tcp://127.0.0.1:24224',
- 'fluentd-async' => 'true',
- 'fluentd-sub-second-precision' => 'true',
- // env vars are used in the LogDrain configurations
- 'env' => 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME',
- ],
- ];
-}
-
-function isAssociativeArray($array)
-{
- if ($array instanceof Collection) {
- $array = $array->toArray();
- }
-
- if (! is_array($array)) {
- throw new \InvalidArgumentException('Input must be an array or a Collection.');
- }
-
- if ($array === []) {
- return false;
- }
-
- return array_keys($array) !== range(0, count($array) - 1);
-}
-
-/**
- * This method adds the default environment variables to the resource.
- * - COOLIFY_APP_NAME
- * - COOLIFY_PROJECT_NAME
- * - COOLIFY_SERVER_IP
- * - COOLIFY_ENVIRONMENT_NAME
- *
- * Theses variables are added in place to the $where_to_add array.
- */
-function add_coolify_default_environment_variables(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse|Application|Service $resource, Collection &$where_to_add, ?Collection $where_to_check = null)
-{
- // Currently disabled
- return;
- if ($resource instanceof Service) {
- $ip = $resource->server->ip;
- } else {
- $ip = $resource->destination->server->ip;
- }
- if (isAssociativeArray($where_to_add)) {
- $isAssociativeArray = true;
- } else {
- $isAssociativeArray = false;
- }
- if ($where_to_check != null && $where_to_check->where('key', 'COOLIFY_APP_NAME')->isEmpty()) {
- if ($isAssociativeArray) {
- $where_to_add->put('COOLIFY_APP_NAME', "\"{$resource->name}\"");
- } else {
- $where_to_add->push("COOLIFY_APP_NAME=\"{$resource->name}\"");
- }
- }
- if ($where_to_check != null && $where_to_check->where('key', 'COOLIFY_SERVER_IP')->isEmpty()) {
- if ($isAssociativeArray) {
- $where_to_add->put('COOLIFY_SERVER_IP', "\"{$ip}\"");
- } else {
- $where_to_add->push("COOLIFY_SERVER_IP=\"{$ip}\"");
- }
- }
- if ($where_to_check != null && $where_to_check->where('key', 'COOLIFY_ENVIRONMENT_NAME')->isEmpty()) {
- if ($isAssociativeArray) {
- $where_to_add->put('COOLIFY_ENVIRONMENT_NAME', "\"{$resource->environment->name}\"");
- } else {
- $where_to_add->push("COOLIFY_ENVIRONMENT_NAME=\"{$resource->environment->name}\"");
- }
- }
- if ($where_to_check != null && $where_to_check->where('key', 'COOLIFY_PROJECT_NAME')->isEmpty()) {
- if ($isAssociativeArray) {
- $where_to_add->put('COOLIFY_PROJECT_NAME', "\"{$resource->project()->name}\"");
- } else {
- $where_to_add->push("COOLIFY_PROJECT_NAME=\"{$resource->project()->name}\"");
- }
- }
-}
-
-function convertToKeyValueCollection($environment)
-{
- $convertedServiceVariables = collect([]);
- if (isAssociativeArray($environment)) {
- // Example: $environment = ['FOO' => 'bar', 'BAZ' => 'qux'];
- if ($environment instanceof Collection) {
- $changedEnvironment = collect([]);
- $environment->each(function ($value, $key) use ($changedEnvironment) {
- if (is_numeric($key)) {
- $parts = explode('=', $value, 2);
- if (count($parts) === 2) {
- $key = $parts[0];
- $realValue = $parts[1] ?? '';
- $changedEnvironment->put($key, $realValue);
- } else {
- $changedEnvironment->put($key, $value);
- }
- } else {
- $changedEnvironment->put($key, $value);
- }
- });
-
- return $changedEnvironment;
- }
- $convertedServiceVariables = $environment;
- } else {
- // Example: $environment = ['FOO=bar', 'BAZ=qux'];
- foreach ($environment as $value) {
- if (is_string($value)) {
- $parts = explode('=', $value, 2);
- $key = $parts[0];
- $realValue = $parts[1] ?? '';
- if ($key) {
- $convertedServiceVariables->put($key, $realValue);
- }
- }
- }
- }
-
- return $convertedServiceVariables;
-}
-function instanceSettings()
-{
- return InstanceSettings::get();
-}
-
-function loadConfigFromGit(string $repository, string $branch, string $base_directory, int $server_id, int $team_id)
-{
- $server = Server::find($server_id)->where('team_id', $team_id)->first();
- if (! $server) {
- return;
- }
- $uuid = new Cuid2;
- $cloneCommand = "git clone --no-checkout -b $branch $repository .";
- $workdir = rtrim($base_directory, '/');
- $fileList = collect([".$workdir/coolify.json"]);
- $commands = collect([
- "rm -rf /tmp/{$uuid}",
- "mkdir -p /tmp/{$uuid}",
- "cd /tmp/{$uuid}",
- $cloneCommand,
- 'git sparse-checkout init --cone',
- "git sparse-checkout set {$fileList->implode(' ')}",
- 'git read-tree -mu HEAD',
- "cat .$workdir/coolify.json",
- 'rm -rf /tmp/{$uuid}',
- ]);
- try {
- return instant_remote_process($commands, $server);
- } catch (\Exception) {
- // continue
- }
-}
-
-function loggy($message = null, array $context = [])
-{
- if (! isDev()) {
- return;
- }
- if (function_exists('ray') && config('app.debug')) {
- ray($message, $context);
- }
- if (is_null($message)) {
- return app('log');
- }
-
- return app('log')->debug($message, $context);
-}
-function sslipDomainWarning(string $domains)
-{
- $domains = str($domains)->trim()->explode(',');
- $showSslipHttpsWarning = false;
- $domains->each(function ($domain) use (&$showSslipHttpsWarning) {
- if (str($domain)->contains('https') && str($domain)->contains('sslip')) {
- $showSslipHttpsWarning = true;
- }
- });
-
- return $showSslipHttpsWarning;
-}
-
-function isEmailRateLimited(string $limiterKey, int $decaySeconds = 3600, ?callable $callbackOnSuccess = null): bool
-{
- if (isDev()) {
- $decaySeconds = 120;
- }
- $rateLimited = false;
- $executed = RateLimiter::attempt(
- $limiterKey,
- $maxAttempts = 0,
- function () use (&$rateLimited, &$limiterKey, $callbackOnSuccess) {
- isDev() && loggy('Rate limit not reached for '.$limiterKey);
- $rateLimited = false;
-
- if ($callbackOnSuccess) {
- $callbackOnSuccess();
- }
- },
- $decaySeconds,
- );
- if (! $executed) {
- isDev() && loggy('Rate limit reached for '.$limiterKey.'. Rate limiter will be disabled for '.$decaySeconds.' seconds.');
- $rateLimited = true;
- }
-
- return $rateLimited;
-}
-
-function defaultNginxConfiguration(): string
-{
- return 'server {
- location / {
- root /usr/share/nginx/html;
- index index.html index.htm;
- try_files $uri $uri.html $uri/index.html $uri/index.htm $uri/ =404;
- }
-
- # Handle 404 errors
- error_page 404 /404.html;
- location = /404.html {
- root /usr/share/nginx/html;
- internal;
- }
-
- # Handle server errors (50x)
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root /usr/share/nginx/html;
- internal;
- }
-}';
-}
-
-function convertGitUrl(string $gitRepository, string $deploymentType, ?GithubApp $source = null): array
-{
- $repository = $gitRepository;
- $providerInfo = [
- 'host' => null,
- 'user' => 'git',
- 'port' => 22,
- 'repository' => $gitRepository,
- ];
- $sshMatches = [];
- $matches = [];
-
- // Let's try and parse the string to detect if it's a valid SSH string or not
- preg_match('/((.*?)\:\/\/)?(.*@.*:.*)/', $gitRepository, $sshMatches);
-
- if ($deploymentType === 'deploy_key' && empty($sshMatches) && $source) {
- // If this happens, the user may have provided an HTTP URL when they needed an SSH one
- // Let's try and fix that for known Git providers
- switch ($source->getMorphClass()) {
- case \App\Models\GithubApp::class:
- $providerInfo['host'] = Url::fromString($source->html_url)->getHost();
- $providerInfo['port'] = $source->custom_port;
- $providerInfo['user'] = $source->custom_user;
- break;
- }
- if (! empty($providerInfo['host'])) {
- // Until we do not support more providers with App (like GithubApp), this will be always true, port will be 22
- if ($providerInfo['port'] === 22) {
- $repository = "{$providerInfo['user']}@{$providerInfo['host']}:{$providerInfo['repository']}";
- } else {
- $repository = "ssh://{$providerInfo['user']}@{$providerInfo['host']}:{$providerInfo['port']}/{$providerInfo['repository']}";
- }
- }
- }
-
- preg_match('/(?<=:)\d+(?=\/)/', $gitRepository, $matches);
-
- if (count($matches) === 1) {
- $providerInfo['port'] = $matches[0];
- $gitHost = str($gitRepository)->before(':');
- $gitRepo = str($gitRepository)->after('/');
- $repository = "$gitHost:$gitRepo";
- }
-
- return [
- 'repository' => $repository,
- 'port' => $providerInfo['port'],
- ];
-}
-
-function getJobStatus(?string $jobId = null)
-{
- if (blank($jobId)) {
- return 'unknown';
- }
- $jobFound = app(JobRepository::class)->getJobs([$jobId]);
- if ($jobFound->isEmpty()) {
- return 'unknown';
- }
-
- return $jobFound->first()->status;
-}
diff --git a/bootstrap/helpers/socialite.php b/bootstrap/helpers/socialite.php
deleted file mode 100644
index 16870e33d3..0000000000
--- a/bootstrap/helpers/socialite.php
+++ /dev/null
@@ -1,61 +0,0 @@
-client_id,
- $oauth_setting->client_secret,
- $oauth_setting->redirect_uri,
- ['tenant' => $oauth_setting->tenant],
- );
-
- return Socialite::driver('azure')->setConfig($azure_config);
- }
-
- if ($provider == 'authentik') {
- $authentik_config = new \SocialiteProviders\Manager\Config(
- $oauth_setting->client_id,
- $oauth_setting->client_secret,
- $oauth_setting->redirect_uri,
- ['base_url' => $oauth_setting->base_url],
- );
-
- return Socialite::driver('authentik')->setConfig($authentik_config);
- }
-
- if ($provider == 'google') {
- $google_config = new \SocialiteProviders\Manager\Config(
- $oauth_setting->client_id,
- $oauth_setting->client_secret,
- $oauth_setting->redirect_uri
- );
-
- return Socialite::driver('google')
- ->setConfig($google_config)
- ->with(['hd' => $oauth_setting->tenant]);
- }
-
- $config = [
- 'client_id' => $oauth_setting->client_id,
- 'client_secret' => $oauth_setting->client_secret,
- 'redirect' => $oauth_setting->redirect_uri,
- ];
-
- $provider_class_map = [
- 'bitbucket' => \Laravel\Socialite\Two\BitbucketProvider::class,
- 'github' => \Laravel\Socialite\Two\GithubProvider::class,
- 'gitlab' => \Laravel\Socialite\Two\GitlabProvider::class,
- 'infomaniak' => \SocialiteProviders\Infomaniak\Provider::class,
- ];
-
- return Socialite::buildProvider(
- $provider_class_map[$provider],
- $config
- );
-}
diff --git a/bootstrap/helpers/subscriptions.php b/bootstrap/helpers/subscriptions.php
deleted file mode 100644
index 510516a2f9..0000000000
--- a/bootstrap/helpers/subscriptions.php
+++ /dev/null
@@ -1,91 +0,0 @@
-subscription;
-
- if (is_null($subscription)) {
- return false;
- }
- if (isStripe()) {
- return $subscription->stripe_invoice_paid === true;
- }
-
- return false;
-}
-function isSubscriptionOnGracePeriod()
-{
- $team = currentTeam();
- if (! $team) {
- return false;
- }
- $subscription = $team?->subscription;
- if (! $subscription) {
- return false;
- }
- if (isStripe()) {
- return $subscription->stripe_cancel_at_period_end;
- }
-
- return false;
-}
-function subscriptionProvider()
-{
- return config('subscription.provider');
-}
-function isStripe()
-{
- return config('subscription.provider') === 'stripe';
-}
-function getStripeCustomerPortalSession(Team $team)
-{
- Stripe::setApiKey(config('subscription.stripe_api_key'));
- $return_url = route('subscription.show');
- $stripe_customer_id = data_get($team, 'subscription.stripe_customer_id');
- if (! $stripe_customer_id) {
- return null;
- }
-
- return \Stripe\BillingPortal\Session::create([
- 'customer' => $stripe_customer_id,
- 'return_url' => $return_url,
- ]);
-}
-function allowedPathsForUnsubscribedAccounts()
-{
- return [
- 'subscription/new',
- 'login',
- 'logout',
- 'force-password-reset',
- 'livewire/update',
- 'admin',
- ];
-}
-function allowedPathsForBoardingAccounts()
-{
- return [
- ...allowedPathsForUnsubscribedAccounts(),
- 'onboarding',
- 'livewire/update',
- ];
-}
-function allowedPathsForInvalidAccounts()
-{
- return [
- 'logout',
- 'verify',
- 'force-password-reset',
- 'livewire/update',
- ];
-}
diff --git a/bootstrap/helpers/timezone.php b/bootstrap/helpers/timezone.php
deleted file mode 100644
index 96d9ba6cf2..0000000000
--- a/bootstrap/helpers/timezone.php
+++ /dev/null
@@ -1,42 +0,0 @@
-setTimezone(new \DateTimeZone($serverTimezone));
- } catch (\Exception) {
- $dateObj->setTimezone(new \DateTimeZone('UTC'));
- }
-
- return $dateObj->format('Y-m-d H:i:s T');
-}
-
-function calculateDuration($startDate, $endDate = null)
-{
- if (! $endDate) {
- return null;
- }
-
- $start = new \DateTime($startDate);
- $end = new \DateTime($endDate);
- $interval = $start->diff($end);
-
- if ($interval->days > 0) {
- return $interval->format('%dd %Hh %Im %Ss');
- } elseif ($interval->h > 0) {
- return $interval->format('%Hh %Im %Ss');
- } else {
- return $interval->format('%Im %Ss');
- }
-}
diff --git a/bootstrap/includeHelpers.php b/bootstrap/includeHelpers.php
deleted file mode 100644
index fb6e84e997..0000000000
--- a/bootstrap/includeHelpers.php
+++ /dev/null
@@ -1,6 +0,0 @@
-
-"""
-# remove the leading and trailing s
-trim = true
-# postprocessors
-postprocessors = [
- # { pattern = '', replace = "https://github.com/orhun/git-cliff" }, # replace repository URL
-]
-# render body even when there are no releases to process
-# render_always = true
-# output file path
-# output = "test.md"
-
-[git]
-# parse the commits based on https://www.conventionalcommits.org
-conventional_commits = true
-# filter out the commits that are not conventional
-filter_unconventional = true
-# process each line of a commit as an individual commit
-split_commits = false
-# regex for preprocessing the commit messages
-commit_preprocessors = [
- # Replace issue numbers
- #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))"},
- # Check spelling of the commit with https://github.com/crate-ci/typos
- # If the spelling is incorrect, it will be automatically fixed.
- #{ pattern = '.*', replace_command = 'typos --write-changes -' },
-]
-# regex for parsing and grouping commits
-commit_parsers = [
- { message = "^feat", group = "🚀 Features" },
- { message = "^fix", group = "🐛 Bug Fixes" },
- { message = "^doc", group = "📚 Documentation" },
- { message = "^perf", group = "⚡ Performance" },
- { message = "^refactor", group = "🚜 Refactor" },
- { message = "^style", group = "🎨 Styling" },
- { message = "^test", group = "🧪 Testing" },
- { message = "^chore\\(release\\): prepare for", skip = true },
- { message = "^chore\\(deps.*\\)", skip = true },
- { message = "^chore\\(pr\\)", skip = true },
- { message = "^chore\\(pull\\)", skip = true },
- { message = "^chore|^ci", group = "⚙️ Miscellaneous Tasks" },
- { body = ".*security", group = "🛡️ Security" },
- { message = "^revert", group = "◀️ Revert" },
- { message = ".*", group = "💼 Other" },
-]
-# filter out the commits that are not matched by commit parsers
-filter_commits = false
-# sort the tags topologically
-topo_order = false
-# sort the commits inside sections by oldest/newest order
-sort_commits = "oldest"
diff --git a/composer.json b/composer.json
index e5aeb61264..88b33c4d45 100644
--- a/composer.json
+++ b/composer.json
@@ -1,129 +1,74 @@
{
- "name": "coollabsio/coolify",
- "description": "The Coolify project.",
- "license": "Apache-2.0",
+ "$schema": "https://getcomposer.org/schema.json",
+ "name": "laravel/laravel",
"type": "project",
+ "description": "The skeleton application for the Laravel framework.",
"keywords": [
- "coolify",
- "deployment",
- "docker",
- "self-hosted",
- "server"
+ "laravel",
+ "framework"
],
+ "license": "MIT",
"require": {
- "php": "^8.4",
- "3sidedcube/laravel-redoc": "^1.0",
- "danharrin/livewire-rate-limiting": "2.0.0",
- "doctrine/dbal": "^4.2",
- "guzzlehttp/guzzle": "^7.5.0",
- "laravel/fortify": "^1.16.0",
- "laravel/framework": "^11.0",
- "laravel/horizon": "^5.29.1",
- "laravel/pail": "^1.1",
- "laravel/prompts": "^0.1.18|^0.2.0|^0.3.0",
- "laravel/sanctum": "^4.0",
- "laravel/socialite": "^5.14.0",
- "laravel/tinker": "^2.8.1",
- "laravel/ui": "^4.2",
- "lcobucci/jwt": "^5.0.0",
- "league/flysystem-aws-s3-v3": "^3.0",
- "league/flysystem-sftp-v3": "^3.0",
- "livewire/livewire": "^3.5",
- "log1x/laravel-webfonts": "^1.0",
- "lorisleiva/laravel-actions": "^2.8",
- "nubs/random-name-generator": "^2.2",
- "phpseclib/phpseclib": "^3.0",
- "pion/laravel-chunk-upload": "^1.5",
- "poliander/cron": "^3.0",
- "purplepixie/phpdns": "^2.1",
- "pusher/pusher-php-server": "^7.2",
- "resend/resend-laravel": "^0.15.0",
- "sentry/sentry-laravel": "^4.6",
- "socialiteproviders/authentik": "^5.2",
- "socialiteproviders/google": "^4.1",
- "socialiteproviders/infomaniak": "^4.0",
- "socialiteproviders/microsoft-azure": "^5.1",
- "spatie/laravel-activitylog": "^4.7.3",
- "spatie/laravel-data": "^4.11",
- "spatie/laravel-ray": "^1.37",
- "spatie/laravel-schemaless-attributes": "^2.4",
- "spatie/url": "^2.2",
- "stevebauman/purify": "^6.2",
- "stripe/stripe-php": "^16.2.0",
- "symfony/yaml": "^7.1.6",
- "visus/cuid2": "^4.1.0",
- "yosymfony/toml": "^1.0",
- "zircote/swagger-php": "^5.0"
+ "php": "^8.2",
+ "laravel/framework": "^12.0",
+ "laravel/tinker": "^2.10.1"
},
"require-dev": {
- "barryvdh/laravel-debugbar": "^3.13",
- "driftingly/rector-laravel": "^2.0",
- "fakerphp/faker": "^1.21.0",
- "laravel/dusk": "^8.0",
- "laravel/pint": "^1.16",
- "laravel/telescope": "^5.2",
- "mockery/mockery": "^1.5.1",
- "nunomaduro/collision": "^8.1",
- "pestphp/pest": "^3.5",
- "phpstan/phpstan": "^2.1",
- "phpunit/phpunit": "^11.5",
- "rector/rector": "^2.0",
- "serversideup/spin": "^3.0",
- "spatie/laravel-ignition": "^2.1.0",
- "symfony/http-client": "^7.1"
+ "fakerphp/faker": "^1.23",
+ "laravel/pail": "^1.2.2",
+ "laravel/pint": "^1.13",
+ "laravel/sail": "^1.41",
+ "mockery/mockery": "^1.6",
+ "nunomaduro/collision": "^8.6",
+ "phpunit/phpunit": "^11.5.3"
},
- "minimum-stability": "stable",
- "prefer-stable": true,
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
- },
- "files": [
- "bootstrap/includeHelpers.php"
- ]
+ }
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
- "config": {
- "allow-plugins": {
- "pestphp/pest-plugin": true,
- "php-http/discovery": true
- },
- "optimize-autoloader": true,
- "preferred-install": "dist",
- "sort-packages": true
- },
- "extra": {
- "laravel": {
- "dont-discover": [
- "laravel/telescope"
- ]
- }
- },
"scripts": {
- "post-install-cmd": [
- "cp -r 'hooks/' '.git/hooks/'",
- "php -r \"copy('hooks/pre-commit', '.git/hooks/pre-commit');\"",
- "php -r \"chmod('.git/hooks/pre-commit', 0777);\""
- ],
- "post-update-cmd": [
- "@php artisan vendor:publish --tag=laravel-assets --ansi --force",
- "Illuminate\\Foundation\\ComposerScripts::postUpdate"
- ],
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
+ "post-update-cmd": [
+ "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
+ ],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
- "@php artisan key:generate --ansi"
+ "@php artisan key:generate --ansi",
+ "@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
+ "@php artisan migrate --graceful --ansi"
+ ],
+ "dev": [
+ "Composer\\Config::disableProcessTimeout",
+ "npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
]
- }
-}
+ },
+ "extra": {
+ "laravel": {
+ "dont-discover": []
+ }
+ },
+ "config": {
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "sort-packages": true,
+ "allow-plugins": {
+ "pestphp/pest-plugin": true,
+ "php-http/discovery": true
+ }
+ },
+ "minimum-stability": "stable",
+ "prefer-stable": true
+}
\ No newline at end of file
diff --git a/composer.lock b/composer.lock
index 2a3fc1ddb8..0d359facc5 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,1079 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "dcf6b2f554372a570628d7f85184df7b",
+ "content-hash": "88970a0117c062eed55fa8728fc43833",
"packages": [
- {
- "name": "3sidedcube/laravel-redoc",
- "version": "v1.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/3sidedcube/laravel-redoc.git",
- "reference": "c33a563885dcdf1e0f623df5a56c106d130261da"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/3sidedcube/laravel-redoc/zipball/c33a563885dcdf1e0f623df5a56c106d130261da",
- "reference": "c33a563885dcdf1e0f623df5a56c106d130261da",
- "shasum": ""
- },
- "require": {
- "illuminate/routing": "^8.0|^9.0|^10.0|^11.0",
- "illuminate/support": "^8.0|^9.0|^10.0|^11.0",
- "php": "^7.4|^8.0|^8.1|^8.2|^8.3"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3.3",
- "orchestra/testbench": "^6.0|^7.0|^8.0|^9.0"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "ThreeSidedCube\\LaravelRedoc\\RedocServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "ThreeSidedCube\\LaravelRedoc\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ben Sherred",
- "role": "Developer"
- }
- ],
- "description": "A lightweight package for rendering API documentation using OpenAPI and Redoc.",
- "homepage": "https://github.com/3sidedcube/laravel-redoc",
- "keywords": [
- "3sidedcube",
- "laravel-redoc"
- ],
- "support": {
- "issues": "https://github.com/3sidedcube/laravel-redoc/issues",
- "source": "https://github.com/3sidedcube/laravel-redoc/tree/v1.0.1"
- },
- "time": "2024-05-20T11:37:55+00:00"
- },
- {
- "name": "amphp/amp",
- "version": "v3.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/amp.git",
- "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/amp/zipball/7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9",
- "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "phpunit/phpunit": "^9",
- "psalm/phar": "5.23.1"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php",
- "src/Future/functions.php",
- "src/Internal/functions.php"
- ],
- "psr-4": {
- "Amp\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Bob Weinand",
- "email": "bobwei9@hotmail.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- },
- {
- "name": "Daniel Lowrey",
- "email": "rdlowrey@php.net"
- }
- ],
- "description": "A non-blocking concurrency framework for PHP applications.",
- "homepage": "https://amphp.org/amp",
- "keywords": [
- "async",
- "asynchronous",
- "awaitable",
- "concurrency",
- "event",
- "event-loop",
- "future",
- "non-blocking",
- "promise"
- ],
- "support": {
- "issues": "https://github.com/amphp/amp/issues",
- "source": "https://github.com/amphp/amp/tree/v3.1.0"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2025-01-26T16:07:39+00:00"
- },
- {
- "name": "amphp/byte-stream",
- "version": "v2.1.1",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/byte-stream.git",
- "reference": "daa00f2efdbd71565bf64ffefa89e37542addf93"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/byte-stream/zipball/daa00f2efdbd71565bf64ffefa89e37542addf93",
- "reference": "daa00f2efdbd71565bf64ffefa89e37542addf93",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/parser": "^1.1",
- "amphp/pipeline": "^1",
- "amphp/serialization": "^1",
- "amphp/sync": "^2",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2.3"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "5.22.1"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php",
- "src/Internal/functions.php"
- ],
- "psr-4": {
- "Amp\\ByteStream\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "A stream abstraction to make working with non-blocking I/O simple.",
- "homepage": "https://amphp.org/byte-stream",
- "keywords": [
- "amp",
- "amphp",
- "async",
- "io",
- "non-blocking",
- "stream"
- ],
- "support": {
- "issues": "https://github.com/amphp/byte-stream/issues",
- "source": "https://github.com/amphp/byte-stream/tree/v2.1.1"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-02-17T04:49:38+00:00"
- },
- {
- "name": "amphp/cache",
- "version": "v2.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/cache.git",
- "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/cache/zipball/46912e387e6aa94933b61ea1ead9cf7540b7797c",
- "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/serialization": "^1",
- "amphp/sync": "^2",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Amp\\Cache\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- },
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Daniel Lowrey",
- "email": "rdlowrey@php.net"
- }
- ],
- "description": "A fiber-aware cache API based on Amp and Revolt.",
- "homepage": "https://amphp.org/cache",
- "support": {
- "issues": "https://github.com/amphp/cache/issues",
- "source": "https://github.com/amphp/cache/tree/v2.0.1"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-04-19T03:38:06+00:00"
- },
- {
- "name": "amphp/dns",
- "version": "v2.4.0",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/dns.git",
- "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/dns/zipball/78eb3db5fc69bf2fc0cb503c4fcba667bc223c71",
- "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/byte-stream": "^2",
- "amphp/cache": "^2",
- "amphp/parser": "^1",
- "amphp/process": "^2",
- "daverandom/libdns": "^2.0.2",
- "ext-filter": "*",
- "ext-json": "*",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "5.20"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "Amp\\Dns\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Chris Wright",
- "email": "addr@daverandom.com"
- },
- {
- "name": "Daniel Lowrey",
- "email": "rdlowrey@php.net"
- },
- {
- "name": "Bob Weinand",
- "email": "bobwei9@hotmail.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- },
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- }
- ],
- "description": "Async DNS resolution for Amp.",
- "homepage": "https://github.com/amphp/dns",
- "keywords": [
- "amp",
- "amphp",
- "async",
- "client",
- "dns",
- "resolve"
- ],
- "support": {
- "issues": "https://github.com/amphp/dns/issues",
- "source": "https://github.com/amphp/dns/tree/v2.4.0"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2025-01-19T15:43:40+00:00"
- },
- {
- "name": "amphp/parallel",
- "version": "v2.3.1",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/parallel.git",
- "reference": "5113111de02796a782f5d90767455e7391cca190"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/parallel/zipball/5113111de02796a782f5d90767455e7391cca190",
- "reference": "5113111de02796a782f5d90767455e7391cca190",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/byte-stream": "^2",
- "amphp/cache": "^2",
- "amphp/parser": "^1",
- "amphp/pipeline": "^1",
- "amphp/process": "^2",
- "amphp/serialization": "^1",
- "amphp/socket": "^2",
- "amphp/sync": "^2",
- "php": ">=8.1",
- "revolt/event-loop": "^1"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.18"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/Context/functions.php",
- "src/Context/Internal/functions.php",
- "src/Ipc/functions.php",
- "src/Worker/functions.php"
- ],
- "psr-4": {
- "Amp\\Parallel\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- },
- {
- "name": "Stephen Coakley",
- "email": "me@stephencoakley.com"
- }
- ],
- "description": "Parallel processing component for Amp.",
- "homepage": "https://github.com/amphp/parallel",
- "keywords": [
- "async",
- "asynchronous",
- "concurrent",
- "multi-processing",
- "multi-threading"
- ],
- "support": {
- "issues": "https://github.com/amphp/parallel/issues",
- "source": "https://github.com/amphp/parallel/tree/v2.3.1"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-12-21T01:56:09+00:00"
- },
- {
- "name": "amphp/parser",
- "version": "v1.1.1",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/parser.git",
- "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/parser/zipball/3cf1f8b32a0171d4b1bed93d25617637a77cded7",
- "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7",
- "shasum": ""
- },
- "require": {
- "php": ">=7.4"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Amp\\Parser\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "A generator parser to make streaming parsers simple.",
- "homepage": "https://github.com/amphp/parser",
- "keywords": [
- "async",
- "non-blocking",
- "parser",
- "stream"
- ],
- "support": {
- "issues": "https://github.com/amphp/parser/issues",
- "source": "https://github.com/amphp/parser/tree/v1.1.1"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-03-21T19:16:53+00:00"
- },
- {
- "name": "amphp/pipeline",
- "version": "v1.2.2",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/pipeline.git",
- "reference": "97cbf289f4d8877acfe58dd90ed5a4370a43caa4"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/pipeline/zipball/97cbf289f4d8877acfe58dd90ed5a4370a43caa4",
- "reference": "97cbf289f4d8877acfe58dd90ed5a4370a43caa4",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "php": ">=8.1",
- "revolt/event-loop": "^1"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.18"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Amp\\Pipeline\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "Asynchronous iterators and operators.",
- "homepage": "https://amphp.org/pipeline",
- "keywords": [
- "amp",
- "amphp",
- "async",
- "io",
- "iterator",
- "non-blocking"
- ],
- "support": {
- "issues": "https://github.com/amphp/pipeline/issues",
- "source": "https://github.com/amphp/pipeline/tree/v1.2.2"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2025-01-19T15:42:46+00:00"
- },
- {
- "name": "amphp/process",
- "version": "v2.0.3",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/process.git",
- "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/process/zipball/52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d",
- "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/byte-stream": "^2",
- "amphp/sync": "^2",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.4"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "Amp\\Process\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Bob Weinand",
- "email": "bobwei9@hotmail.com"
- },
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "A fiber-aware process manager based on Amp and Revolt.",
- "homepage": "https://amphp.org/process",
- "support": {
- "issues": "https://github.com/amphp/process/issues",
- "source": "https://github.com/amphp/process/tree/v2.0.3"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-04-19T03:13:44+00:00"
- },
- {
- "name": "amphp/serialization",
- "version": "v1.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/serialization.git",
- "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/serialization/zipball/693e77b2fb0b266c3c7d622317f881de44ae94a1",
- "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "dev-master",
- "phpunit/phpunit": "^9 || ^8 || ^7"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "Amp\\Serialization\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "Serialization tools for IPC and data storage in PHP.",
- "homepage": "https://github.com/amphp/serialization",
- "keywords": [
- "async",
- "asynchronous",
- "serialization",
- "serialize"
- ],
- "support": {
- "issues": "https://github.com/amphp/serialization/issues",
- "source": "https://github.com/amphp/serialization/tree/master"
- },
- "time": "2020-03-25T21:39:07+00:00"
- },
- {
- "name": "amphp/socket",
- "version": "v2.3.1",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/socket.git",
- "reference": "58e0422221825b79681b72c50c47a930be7bf1e1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/socket/zipball/58e0422221825b79681b72c50c47a930be7bf1e1",
- "reference": "58e0422221825b79681b72c50c47a930be7bf1e1",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/byte-stream": "^2",
- "amphp/dns": "^2",
- "ext-openssl": "*",
- "kelunik/certificate": "^1.1",
- "league/uri": "^6.5 | ^7",
- "league/uri-interfaces": "^2.3 | ^7",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "amphp/process": "^2",
- "phpunit/phpunit": "^9",
- "psalm/phar": "5.20"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php",
- "src/Internal/functions.php",
- "src/SocketAddress/functions.php"
- ],
- "psr-4": {
- "Amp\\Socket\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Daniel Lowrey",
- "email": "rdlowrey@gmail.com"
- },
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "Non-blocking socket connection / server implementations based on Amp and Revolt.",
- "homepage": "https://github.com/amphp/socket",
- "keywords": [
- "amp",
- "async",
- "encryption",
- "non-blocking",
- "sockets",
- "tcp",
- "tls"
- ],
- "support": {
- "issues": "https://github.com/amphp/socket/issues",
- "source": "https://github.com/amphp/socket/tree/v2.3.1"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-04-21T14:33:03+00:00"
- },
- {
- "name": "amphp/sync",
- "version": "v2.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/amphp/sync.git",
- "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/amphp/sync/zipball/217097b785130d77cfcc58ff583cf26cd1770bf1",
- "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^3",
- "amphp/pipeline": "^1",
- "amphp/serialization": "^1",
- "php": ">=8.1",
- "revolt/event-loop": "^1 || ^0.2"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "amphp/phpunit-util": "^3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "5.23"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "Amp\\Sync\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- },
- {
- "name": "Stephen Coakley",
- "email": "me@stephencoakley.com"
- }
- ],
- "description": "Non-blocking synchronization primitives for PHP based on Amp and Revolt.",
- "homepage": "https://github.com/amphp/sync",
- "keywords": [
- "async",
- "asynchronous",
- "mutex",
- "semaphore",
- "synchronization"
- ],
- "support": {
- "issues": "https://github.com/amphp/sync/issues",
- "source": "https://github.com/amphp/sync/tree/v2.3.0"
- },
- "funding": [
- {
- "url": "https://github.com/amphp",
- "type": "github"
- }
- ],
- "time": "2024-08-03T19:31:26+00:00"
- },
- {
- "name": "aws/aws-crt-php",
- "version": "v1.2.7",
- "source": {
- "type": "git",
- "url": "https://github.com/awslabs/aws-crt-php.git",
- "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/d71d9906c7bb63a28295447ba12e74723bd3730e",
- "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e",
- "shasum": ""
- },
- "require": {
- "php": ">=5.5"
- },
- "require-dev": {
- "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5",
- "yoast/phpunit-polyfills": "^1.0"
- },
- "suggest": {
- "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality."
- },
- "type": "library",
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "Apache-2.0"
- ],
- "authors": [
- {
- "name": "AWS SDK Common Runtime Team",
- "email": "aws-sdk-common-runtime@amazon.com"
- }
- ],
- "description": "AWS Common Runtime for PHP",
- "homepage": "https://github.com/awslabs/aws-crt-php",
- "keywords": [
- "amazon",
- "aws",
- "crt",
- "sdk"
- ],
- "support": {
- "issues": "https://github.com/awslabs/aws-crt-php/issues",
- "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.7"
- },
- "time": "2024-10-18T22:15:13+00:00"
- },
- {
- "name": "aws/aws-sdk-php",
- "version": "3.339.19",
- "source": {
- "type": "git",
- "url": "https://github.com/aws/aws-sdk-php.git",
- "reference": "18f05efe983860ad899082e04c13f06ec9fd6e41"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/18f05efe983860ad899082e04c13f06ec9fd6e41",
- "reference": "18f05efe983860ad899082e04c13f06ec9fd6e41",
- "shasum": ""
- },
- "require": {
- "aws/aws-crt-php": "^1.2.3",
- "ext-json": "*",
- "ext-pcre": "*",
- "ext-simplexml": "*",
- "guzzlehttp/guzzle": "^7.4.5",
- "guzzlehttp/promises": "^2.0",
- "guzzlehttp/psr7": "^2.4.5",
- "mtdowling/jmespath.php": "^2.8.0",
- "php": ">=8.1",
- "psr/http-message": "^2.0"
- },
- "require-dev": {
- "andrewsville/php-token-reflection": "^1.4",
- "aws/aws-php-sns-message-validator": "~1.0",
- "behat/behat": "~3.0",
- "composer/composer": "^2.7.8",
- "dms/phpunit-arraysubset-asserts": "^0.4.0",
- "doctrine/cache": "~1.4",
- "ext-dom": "*",
- "ext-openssl": "*",
- "ext-pcntl": "*",
- "ext-sockets": "*",
- "phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5",
- "psr/cache": "^2.0 || ^3.0",
- "psr/simple-cache": "^2.0 || ^3.0",
- "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0",
- "symfony/filesystem": "^v6.4.0 || ^v7.1.0",
- "yoast/phpunit-polyfills": "^2.0"
- },
- "suggest": {
- "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
- "doctrine/cache": "To use the DoctrineCacheAdapter",
- "ext-curl": "To send requests using cURL",
- "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages",
- "ext-sockets": "To use client-side monitoring"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.0-dev"
- }
- },
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "Aws\\": "src/"
- },
- "exclude-from-classmap": [
- "src/data/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "Apache-2.0"
- ],
- "authors": [
- {
- "name": "Amazon Web Services",
- "homepage": "http://aws.amazon.com"
- }
- ],
- "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
- "homepage": "http://aws.amazon.com/sdkforphp",
- "keywords": [
- "amazon",
- "aws",
- "cloud",
- "dynamodb",
- "ec2",
- "glacier",
- "s3",
- "sdk"
- ],
- "support": {
- "forum": "https://github.com/aws/aws-sdk-php/discussions",
- "issues": "https://github.com/aws/aws-sdk-php/issues",
- "source": "https://github.com/aws/aws-sdk-php/tree/3.339.19"
- },
- "time": "2025-02-21T19:13:15+00:00"
- },
- {
- "name": "bacon/bacon-qr-code",
- "version": "v3.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/Bacon/BaconQrCode.git",
- "reference": "f9cc1f52b5a463062251d666761178dbdb6b544f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/f9cc1f52b5a463062251d666761178dbdb6b544f",
- "reference": "f9cc1f52b5a463062251d666761178dbdb6b544f",
- "shasum": ""
- },
- "require": {
- "dasprid/enum": "^1.0.3",
- "ext-iconv": "*",
- "php": "^8.1"
- },
- "require-dev": {
- "phly/keep-a-changelog": "^2.12",
- "phpunit/phpunit": "^10.5.11 || 11.0.4",
- "spatie/phpunit-snapshot-assertions": "^5.1.5",
- "squizlabs/php_codesniffer": "^3.9"
- },
- "suggest": {
- "ext-imagick": "to generate QR code images"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "BaconQrCode\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-2-Clause"
- ],
- "authors": [
- {
- "name": "Ben Scholzen 'DASPRiD'",
- "email": "mail@dasprids.de",
- "homepage": "https://dasprids.de/",
- "role": "Developer"
- }
- ],
- "description": "BaconQrCode is a QR code generator for PHP.",
- "homepage": "https://github.com/Bacon/BaconQrCode",
- "support": {
- "issues": "https://github.com/Bacon/BaconQrCode/issues",
- "source": "https://github.com/Bacon/BaconQrCode/tree/v3.0.1"
- },
- "time": "2024-10-01T13:55:55+00:00"
- },
{
"name": "brick/math",
"version": "0.12.3",
@@ -1206,154 +135,6 @@
],
"time": "2024-02-09T16:56:22+00:00"
},
- {
- "name": "danharrin/livewire-rate-limiting",
- "version": "v2.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/danharrin/livewire-rate-limiting.git",
- "reference": "0d9c1890174b3d1857dba6ce76de7c178fe20283"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/danharrin/livewire-rate-limiting/zipball/0d9c1890174b3d1857dba6ce76de7c178fe20283",
- "reference": "0d9c1890174b3d1857dba6ce76de7c178fe20283",
- "shasum": ""
- },
- "require": {
- "illuminate/support": "^9.0|^10.0|^11.0",
- "php": "^8.0"
- },
- "require-dev": {
- "livewire/livewire": "^3.0",
- "livewire/volt": "^1.3",
- "orchestra/testbench": "^7.0|^8.0|^9.0",
- "phpunit/phpunit": "^9.0|^10.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "DanHarrin\\LivewireRateLimiting\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Dan Harrin",
- "email": "dan@danharrin.com"
- }
- ],
- "description": "Apply rate limiters to Laravel Livewire actions.",
- "homepage": "https://github.com/danharrin/livewire-rate-limiting",
- "support": {
- "issues": "https://github.com/danharrin/livewire-rate-limiting/issues",
- "source": "https://github.com/danharrin/livewire-rate-limiting"
- },
- "funding": [
- {
- "url": "https://github.com/danharrin",
- "type": "github"
- }
- ],
- "time": "2024-11-24T16:57:47+00:00"
- },
- {
- "name": "dasprid/enum",
- "version": "1.0.6",
- "source": {
- "type": "git",
- "url": "https://github.com/DASPRiD/Enum.git",
- "reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/8dfd07c6d2cf31c8da90c53b83c026c7696dda90",
- "reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1 <9.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11",
- "squizlabs/php_codesniffer": "*"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "DASPRiD\\Enum\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-2-Clause"
- ],
- "authors": [
- {
- "name": "Ben Scholzen 'DASPRiD'",
- "email": "mail@dasprids.de",
- "homepage": "https://dasprids.de/",
- "role": "Developer"
- }
- ],
- "description": "PHP 7.1 enum implementation",
- "keywords": [
- "enum",
- "map"
- ],
- "support": {
- "issues": "https://github.com/DASPRiD/Enum/issues",
- "source": "https://github.com/DASPRiD/Enum/tree/1.0.6"
- },
- "time": "2024-08-09T14:30:48+00:00"
- },
- {
- "name": "daverandom/libdns",
- "version": "v2.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/DaveRandom/LibDNS.git",
- "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a",
- "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a",
- "shasum": ""
- },
- "require": {
- "ext-ctype": "*",
- "php": ">=7.1"
- },
- "suggest": {
- "ext-intl": "Required for IDN support"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "LibDNS\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "DNS protocol implementation written in pure PHP",
- "keywords": [
- "dns"
- ],
- "support": {
- "issues": "https://github.com/DaveRandom/LibDNS/issues",
- "source": "https://github.com/DaveRandom/LibDNS/tree/v2.1.0"
- },
- "time": "2024-04-12T12:12:48+00:00"
- },
{
"name": "dflydev/dot-access-data",
"version": "v3.0.3",
@@ -1429,157 +210,6 @@
},
"time": "2024-07-08T12:26:09+00:00"
},
- {
- "name": "doctrine/dbal",
- "version": "4.2.2",
- "source": {
- "type": "git",
- "url": "https://github.com/doctrine/dbal.git",
- "reference": "19a2b7deb5fe8c2df0ff817ecea305e50acb62ec"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/doctrine/dbal/zipball/19a2b7deb5fe8c2df0ff817ecea305e50acb62ec",
- "reference": "19a2b7deb5fe8c2df0ff817ecea305e50acb62ec",
- "shasum": ""
- },
- "require": {
- "doctrine/deprecations": "^0.5.3|^1",
- "php": "^8.1",
- "psr/cache": "^1|^2|^3",
- "psr/log": "^1|^2|^3"
- },
- "require-dev": {
- "doctrine/coding-standard": "12.0.0",
- "fig/log-test": "^1",
- "jetbrains/phpstorm-stubs": "2023.2",
- "phpstan/phpstan": "2.1.1",
- "phpstan/phpstan-phpunit": "2.0.3",
- "phpstan/phpstan-strict-rules": "^2",
- "phpunit/phpunit": "10.5.39",
- "slevomat/coding-standard": "8.13.1",
- "squizlabs/php_codesniffer": "3.10.2",
- "symfony/cache": "^6.3.8|^7.0",
- "symfony/console": "^5.4|^6.3|^7.0"
- },
- "suggest": {
- "symfony/console": "For helpful console commands such as SQL execution and import of files."
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Doctrine\\DBAL\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Guilherme Blanco",
- "email": "guilhermeblanco@gmail.com"
- },
- {
- "name": "Roman Borschel",
- "email": "roman@code-factory.org"
- },
- {
- "name": "Benjamin Eberlei",
- "email": "kontakt@beberlei.de"
- },
- {
- "name": "Jonathan Wage",
- "email": "jonwage@gmail.com"
- }
- ],
- "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
- "homepage": "https://www.doctrine-project.org/projects/dbal.html",
- "keywords": [
- "abstraction",
- "database",
- "db2",
- "dbal",
- "mariadb",
- "mssql",
- "mysql",
- "oci8",
- "oracle",
- "pdo",
- "pgsql",
- "postgresql",
- "queryobject",
- "sasql",
- "sql",
- "sqlite",
- "sqlserver",
- "sqlsrv"
- ],
- "support": {
- "issues": "https://github.com/doctrine/dbal/issues",
- "source": "https://github.com/doctrine/dbal/tree/4.2.2"
- },
- "funding": [
- {
- "url": "https://www.doctrine-project.org/sponsorship.html",
- "type": "custom"
- },
- {
- "url": "https://www.patreon.com/phpdoctrine",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
- "type": "tidelift"
- }
- ],
- "time": "2025-01-16T08:40:56+00:00"
- },
- {
- "name": "doctrine/deprecations",
- "version": "1.1.4",
- "source": {
- "type": "git",
- "url": "https://github.com/doctrine/deprecations.git",
- "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/doctrine/deprecations/zipball/31610dbb31faa98e6b5447b62340826f54fbc4e9",
- "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9",
- "shasum": ""
- },
- "require": {
- "php": "^7.1 || ^8.0"
- },
- "require-dev": {
- "doctrine/coding-standard": "^9 || ^12",
- "phpstan/phpstan": "1.4.10 || 2.0.3",
- "phpstan/phpstan-phpunit": "^1.0 || ^2",
- "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
- "psr/log": "^1 || ^2 || ^3"
- },
- "suggest": {
- "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Doctrine\\Deprecations\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
- "homepage": "https://www.doctrine-project.org/",
- "support": {
- "issues": "https://github.com/doctrine/deprecations/issues",
- "source": "https://github.com/doctrine/deprecations/tree/1.1.4"
- },
- "time": "2024-12-07T21:18:45+00:00"
- },
{
"name": "doctrine/inflector",
"version": "2.0.10",
@@ -1880,130 +510,6 @@
],
"time": "2024-12-27T00:36:43+00:00"
},
- {
- "name": "ezyang/htmlpurifier",
- "version": "v4.18.0",
- "source": {
- "type": "git",
- "url": "https://github.com/ezyang/htmlpurifier.git",
- "reference": "cb56001e54359df7ae76dc522d08845dc741621b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b",
- "reference": "cb56001e54359df7ae76dc522d08845dc741621b",
- "shasum": ""
- },
- "require": {
- "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
- },
- "require-dev": {
- "cerdic/css-tidy": "^1.7 || ^2.0",
- "simpletest/simpletest": "dev-master"
- },
- "suggest": {
- "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.",
- "ext-bcmath": "Used for unit conversion and imagecrash protection",
- "ext-iconv": "Converts text to and from non-UTF-8 encodings",
- "ext-tidy": "Used for pretty-printing HTML"
- },
- "type": "library",
- "autoload": {
- "files": [
- "library/HTMLPurifier.composer.php"
- ],
- "psr-0": {
- "HTMLPurifier": "library/"
- },
- "exclude-from-classmap": [
- "/library/HTMLPurifier/Language/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "LGPL-2.1-or-later"
- ],
- "authors": [
- {
- "name": "Edward Z. Yang",
- "email": "admin@htmlpurifier.org",
- "homepage": "http://ezyang.com"
- }
- ],
- "description": "Standards compliant HTML filter written in PHP",
- "homepage": "http://htmlpurifier.org/",
- "keywords": [
- "html"
- ],
- "support": {
- "issues": "https://github.com/ezyang/htmlpurifier/issues",
- "source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0"
- },
- "time": "2024-11-01T03:51:45+00:00"
- },
- {
- "name": "firebase/php-jwt",
- "version": "v6.11.0",
- "source": {
- "type": "git",
- "url": "https://github.com/firebase/php-jwt.git",
- "reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/firebase/php-jwt/zipball/8f718f4dfc9c5d5f0c994cdfd103921b43592712",
- "reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712",
- "shasum": ""
- },
- "require": {
- "php": "^8.0"
- },
- "require-dev": {
- "guzzlehttp/guzzle": "^7.4",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpunit/phpunit": "^9.5",
- "psr/cache": "^2.0||^3.0",
- "psr/http-client": "^1.0",
- "psr/http-factory": "^1.0"
- },
- "suggest": {
- "ext-sodium": "Support EdDSA (Ed25519) signatures",
- "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Firebase\\JWT\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Neuman Vong",
- "email": "neuman+pear@twilio.com",
- "role": "Developer"
- },
- {
- "name": "Anant Narayanan",
- "email": "anant@php.net",
- "role": "Developer"
- }
- ],
- "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
- "homepage": "https://github.com/firebase/php-jwt",
- "keywords": [
- "jwt",
- "php"
- ],
- "support": {
- "issues": "https://github.com/firebase/php-jwt/issues",
- "source": "https://github.com/firebase/php-jwt/tree/v6.11.0"
- },
- "time": "2025-01-23T05:11:06+00:00"
- },
{
"name": "fruitcake/php-cors",
"version": "v1.3.0",
@@ -2548,204 +1054,22 @@
],
"time": "2025-02-03T10:55:03+00:00"
},
- {
- "name": "jean85/pretty-package-versions",
- "version": "2.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/Jean85/pretty-package-versions.git",
- "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
- "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
- "shasum": ""
- },
- "require": {
- "composer-runtime-api": "^2.1.0",
- "php": "^7.4|^8.0"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3.2",
- "jean85/composer-provided-replaced-stub-package": "^1.0",
- "phpstan/phpstan": "^1.4",
- "phpunit/phpunit": "^7.5|^8.5|^9.6",
- "vimeo/psalm": "^4.3 || ^5.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Jean85\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Alessandro Lai",
- "email": "alessandro.lai85@gmail.com"
- }
- ],
- "description": "A library to get pretty versions strings of installed dependencies",
- "keywords": [
- "composer",
- "package",
- "release",
- "versions"
- ],
- "support": {
- "issues": "https://github.com/Jean85/pretty-package-versions/issues",
- "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0"
- },
- "time": "2024-11-18T16:19:46+00:00"
- },
- {
- "name": "kelunik/certificate",
- "version": "v1.1.3",
- "source": {
- "type": "git",
- "url": "https://github.com/kelunik/certificate.git",
- "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e",
- "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e",
- "shasum": ""
- },
- "require": {
- "ext-openssl": "*",
- "php": ">=7.0"
- },
- "require-dev": {
- "amphp/php-cs-fixer-config": "^2",
- "phpunit/phpunit": "^6 | 7 | ^8 | ^9"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Kelunik\\Certificate\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "Access certificate details and transform between different formats.",
- "keywords": [
- "DER",
- "certificate",
- "certificates",
- "openssl",
- "pem",
- "x509"
- ],
- "support": {
- "issues": "https://github.com/kelunik/certificate/issues",
- "source": "https://github.com/kelunik/certificate/tree/v1.1.3"
- },
- "time": "2023-02-03T21:26:53+00:00"
- },
- {
- "name": "laravel/fortify",
- "version": "v1.25.4",
- "source": {
- "type": "git",
- "url": "https://github.com/laravel/fortify.git",
- "reference": "f185600e2d3a861834ad00ee3b7863f26ac25d3f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/laravel/fortify/zipball/f185600e2d3a861834ad00ee3b7863f26ac25d3f",
- "reference": "f185600e2d3a861834ad00ee3b7863f26ac25d3f",
- "shasum": ""
- },
- "require": {
- "bacon/bacon-qr-code": "^3.0",
- "ext-json": "*",
- "illuminate/support": "^10.0|^11.0|^12.0",
- "php": "^8.1",
- "pragmarx/google2fa": "^8.0",
- "symfony/console": "^6.0|^7.0"
- },
- "require-dev": {
- "mockery/mockery": "^1.0",
- "orchestra/testbench": "^8.16|^9.0|^10.0",
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^10.4|^11.3"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Laravel\\Fortify\\FortifyServiceProvider"
- ]
- },
- "branch-alias": {
- "dev-master": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Laravel\\Fortify\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Taylor Otwell",
- "email": "taylor@laravel.com"
- }
- ],
- "description": "Backend controllers and scaffolding for Laravel authentication.",
- "keywords": [
- "auth",
- "laravel"
- ],
- "support": {
- "issues": "https://github.com/laravel/fortify/issues",
- "source": "https://github.com/laravel/fortify"
- },
- "time": "2025-01-26T19:34:46+00:00"
- },
{
"name": "laravel/framework",
- "version": "v11.44.1",
+ "version": "v12.2.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
- "reference": "0883d4175f4e2b5c299e7087ad3c74f2ce195c6d"
+ "reference": "2fb06941bc69ea92f28b2888535ab144ee006889"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/framework/zipball/0883d4175f4e2b5c299e7087ad3c74f2ce195c6d",
- "reference": "0883d4175f4e2b5c299e7087ad3c74f2ce195c6d",
+ "url": "https://api.github.com/repos/laravel/framework/zipball/2fb06941bc69ea92f28b2888535ab144ee006889",
+ "reference": "2fb06941bc69ea92f28b2888535ab144ee006889",
"shasum": ""
},
"require": {
- "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12",
+ "brick/math": "^0.11|^0.12",
"composer-runtime-api": "^2.2",
"doctrine/inflector": "^2.0.5",
"dragonmantank/cron-expression": "^3.4",
@@ -2760,32 +1084,32 @@
"fruitcake/php-cors": "^1.3",
"guzzlehttp/guzzle": "^7.8.2",
"guzzlehttp/uri-template": "^1.0",
- "laravel/prompts": "^0.1.18|^0.2.0|^0.3.0",
+ "laravel/prompts": "^0.3.0",
"laravel/serializable-closure": "^1.3|^2.0",
"league/commonmark": "^2.6",
"league/flysystem": "^3.25.1",
"league/flysystem-local": "^3.25.1",
"league/uri": "^7.5.1",
"monolog/monolog": "^3.0",
- "nesbot/carbon": "^2.72.6|^3.8.4",
+ "nesbot/carbon": "^3.8.4",
"nunomaduro/termwind": "^2.0",
"php": "^8.2",
"psr/container": "^1.1.1|^2.0.1",
"psr/log": "^1.0|^2.0|^3.0",
"psr/simple-cache": "^1.0|^2.0|^3.0",
"ramsey/uuid": "^4.7",
- "symfony/console": "^7.0.3",
- "symfony/error-handler": "^7.0.3",
- "symfony/finder": "^7.0.3",
+ "symfony/console": "^7.2.0",
+ "symfony/error-handler": "^7.2.0",
+ "symfony/finder": "^7.2.0",
"symfony/http-foundation": "^7.2.0",
- "symfony/http-kernel": "^7.0.3",
- "symfony/mailer": "^7.0.3",
- "symfony/mime": "^7.0.3",
+ "symfony/http-kernel": "^7.2.0",
+ "symfony/mailer": "^7.2.0",
+ "symfony/mime": "^7.2.0",
"symfony/polyfill-php83": "^1.31",
- "symfony/process": "^7.0.3",
- "symfony/routing": "^7.0.3",
- "symfony/uid": "^7.0.3",
- "symfony/var-dumper": "^7.0.3",
+ "symfony/process": "^7.2.0",
+ "symfony/routing": "^7.2.0",
+ "symfony/uid": "^7.2.0",
+ "symfony/var-dumper": "^7.2.0",
"tijsverkoyen/css-to-inline-styles": "^2.2.5",
"vlucas/phpdotenv": "^5.6.1",
"voku/portable-ascii": "^2.0.2"
@@ -2849,17 +1173,17 @@
"league/flysystem-read-only": "^3.25.1",
"league/flysystem-sftp-v3": "^3.25.1",
"mockery/mockery": "^1.6.10",
- "orchestra/testbench-core": "^9.11.2",
+ "orchestra/testbench-core": "^10.0.0",
"pda/pheanstalk": "^5.0.6",
"php-http/discovery": "^1.15",
"phpstan/phpstan": "^2.0",
- "phpunit/phpunit": "^10.5.35|^11.3.6|^12.0.1",
+ "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1",
"predis/predis": "^2.3",
"resend/resend-php": "^0.10.0",
- "symfony/cache": "^7.0.3",
- "symfony/http-client": "^7.0.3",
- "symfony/psr-http-message-bridge": "^7.0.3",
- "symfony/translation": "^7.0.3"
+ "symfony/cache": "^7.2.0",
+ "symfony/http-client": "^7.2.0",
+ "symfony/psr-http-message-bridge": "^7.2.0",
+ "symfony/translation": "^7.2.0"
},
"suggest": {
"ably/ably-php": "Required to use the Ably broadcast driver (^1.0).",
@@ -2885,22 +1209,22 @@
"mockery/mockery": "Required to use mocking (^1.6).",
"pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).",
"php-http/discovery": "Required to use PSR-7 bridging features (^1.15).",
- "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.3.6|^12.0.1).",
+ "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.5.3|^12.0.1).",
"predis/predis": "Required to use the predis connector (^2.3).",
"psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).",
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).",
"resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).",
- "symfony/cache": "Required to PSR-6 cache bridge (^7.0).",
- "symfony/filesystem": "Required to enable support for relative symbolic links (^7.0).",
- "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.0).",
- "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.0).",
- "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.0).",
- "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.0)."
+ "symfony/cache": "Required to PSR-6 cache bridge (^7.2).",
+ "symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).",
+ "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.2).",
+ "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.2).",
+ "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.2).",
+ "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.2)."
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "11.x-dev"
+ "dev-master": "12.x-dev"
}
},
"autoload": {
@@ -2943,165 +1267,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-03-05T15:34:10+00:00"
- },
- {
- "name": "laravel/horizon",
- "version": "v5.30.3",
- "source": {
- "type": "git",
- "url": "https://github.com/laravel/horizon.git",
- "reference": "7b9ee870bf0e425b956fd0433f616f98fe951f72"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/laravel/horizon/zipball/7b9ee870bf0e425b956fd0433f616f98fe951f72",
- "reference": "7b9ee870bf0e425b956fd0433f616f98fe951f72",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "ext-pcntl": "*",
- "ext-posix": "*",
- "illuminate/contracts": "^9.21|^10.0|^11.0|^12.0",
- "illuminate/queue": "^9.21|^10.0|^11.0|^12.0",
- "illuminate/support": "^9.21|^10.0|^11.0|^12.0",
- "nesbot/carbon": "^2.17|^3.0",
- "php": "^8.0",
- "ramsey/uuid": "^4.0",
- "symfony/console": "^6.0|^7.0",
- "symfony/error-handler": "^6.0|^7.0",
- "symfony/polyfill-php83": "^1.28",
- "symfony/process": "^6.0|^7.0"
- },
- "require-dev": {
- "mockery/mockery": "^1.0",
- "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^9.0|^10.4|^11.5",
- "predis/predis": "^1.1|^2.0"
- },
- "suggest": {
- "ext-redis": "Required to use the Redis PHP driver.",
- "predis/predis": "Required when not using the Redis PHP driver (^1.1|^2.0)."
- },
- "type": "library",
- "extra": {
- "laravel": {
- "aliases": {
- "Horizon": "Laravel\\Horizon\\Horizon"
- },
- "providers": [
- "Laravel\\Horizon\\HorizonServiceProvider"
- ]
- },
- "branch-alias": {
- "dev-master": "5.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Laravel\\Horizon\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Taylor Otwell",
- "email": "taylor@laravel.com"
- }
- ],
- "description": "Dashboard and code-driven configuration for Laravel queues.",
- "keywords": [
- "laravel",
- "queue"
- ],
- "support": {
- "issues": "https://github.com/laravel/horizon/issues",
- "source": "https://github.com/laravel/horizon/tree/v5.30.3"
- },
- "time": "2025-02-11T13:52:50+00:00"
- },
- {
- "name": "laravel/pail",
- "version": "v1.2.2",
- "source": {
- "type": "git",
- "url": "https://github.com/laravel/pail.git",
- "reference": "f31f4980f52be17c4667f3eafe034e6826787db2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/laravel/pail/zipball/f31f4980f52be17c4667f3eafe034e6826787db2",
- "reference": "f31f4980f52be17c4667f3eafe034e6826787db2",
- "shasum": ""
- },
- "require": {
- "ext-mbstring": "*",
- "illuminate/console": "^10.24|^11.0|^12.0",
- "illuminate/contracts": "^10.24|^11.0|^12.0",
- "illuminate/log": "^10.24|^11.0|^12.0",
- "illuminate/process": "^10.24|^11.0|^12.0",
- "illuminate/support": "^10.24|^11.0|^12.0",
- "nunomaduro/termwind": "^1.15|^2.0",
- "php": "^8.2",
- "symfony/console": "^6.0|^7.0"
- },
- "require-dev": {
- "laravel/framework": "^10.24|^11.0|^12.0",
- "laravel/pint": "^1.13",
- "orchestra/testbench-core": "^8.13|^9.0|^10.0",
- "pestphp/pest": "^2.20|^3.0",
- "pestphp/pest-plugin-type-coverage": "^2.3|^3.0",
- "phpstan/phpstan": "^1.10",
- "symfony/var-dumper": "^6.3|^7.0"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Laravel\\Pail\\PailServiceProvider"
- ]
- },
- "branch-alias": {
- "dev-main": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Laravel\\Pail\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Taylor Otwell",
- "email": "taylor@laravel.com"
- },
- {
- "name": "Nuno Maduro",
- "email": "enunomaduro@gmail.com"
- }
- ],
- "description": "Easily delve into your Laravel application's log files directly from the command line.",
- "homepage": "https://github.com/laravel/pail",
- "keywords": [
- "laravel",
- "logs",
- "php",
- "tail"
- ],
- "support": {
- "issues": "https://github.com/laravel/pail/issues",
- "source": "https://github.com/laravel/pail"
- },
- "time": "2025-01-28T15:15:15+00:00"
+ "time": "2025-03-12T14:38:20+00:00"
},
{
"name": "laravel/prompts",
@@ -3162,70 +1328,6 @@
},
"time": "2025-02-11T13:34:40+00:00"
},
- {
- "name": "laravel/sanctum",
- "version": "v4.0.8",
- "source": {
- "type": "git",
- "url": "https://github.com/laravel/sanctum.git",
- "reference": "ec1dd9ddb2ab370f79dfe724a101856e0963f43c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/laravel/sanctum/zipball/ec1dd9ddb2ab370f79dfe724a101856e0963f43c",
- "reference": "ec1dd9ddb2ab370f79dfe724a101856e0963f43c",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "illuminate/console": "^11.0|^12.0",
- "illuminate/contracts": "^11.0|^12.0",
- "illuminate/database": "^11.0|^12.0",
- "illuminate/support": "^11.0|^12.0",
- "php": "^8.2",
- "symfony/console": "^7.0"
- },
- "require-dev": {
- "mockery/mockery": "^1.6",
- "orchestra/testbench": "^9.0|^10.0",
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^11.3"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Laravel\\Sanctum\\SanctumServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "Laravel\\Sanctum\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Taylor Otwell",
- "email": "taylor@laravel.com"
- }
- ],
- "description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.",
- "keywords": [
- "auth",
- "laravel",
- "sanctum"
- ],
- "support": {
- "issues": "https://github.com/laravel/sanctum/issues",
- "source": "https://github.com/laravel/sanctum"
- },
- "time": "2025-01-26T19:34:36+00:00"
- },
{
"name": "laravel/serializable-closure",
"version": "v2.0.3",
@@ -3287,78 +1389,6 @@
},
"time": "2025-02-11T15:03:05+00:00"
},
- {
- "name": "laravel/socialite",
- "version": "v5.18.0",
- "source": {
- "type": "git",
- "url": "https://github.com/laravel/socialite.git",
- "reference": "7809dc71250e074cd42970f0f803f2cddc04c5de"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/laravel/socialite/zipball/7809dc71250e074cd42970f0f803f2cddc04c5de",
- "reference": "7809dc71250e074cd42970f0f803f2cddc04c5de",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "firebase/php-jwt": "^6.4",
- "guzzlehttp/guzzle": "^6.0|^7.0",
- "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
- "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
- "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
- "league/oauth1-client": "^1.11",
- "php": "^7.2|^8.0",
- "phpseclib/phpseclib": "^3.0"
- },
- "require-dev": {
- "mockery/mockery": "^1.0",
- "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0|^9.0|^10.0",
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^8.0|^9.3|^10.4|^11.5"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "aliases": {
- "Socialite": "Laravel\\Socialite\\Facades\\Socialite"
- },
- "providers": [
- "Laravel\\Socialite\\SocialiteServiceProvider"
- ]
- },
- "branch-alias": {
- "dev-master": "5.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Laravel\\Socialite\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Taylor Otwell",
- "email": "taylor@laravel.com"
- }
- ],
- "description": "Laravel wrapper around OAuth 1 & OAuth 2 libraries.",
- "homepage": "https://laravel.com",
- "keywords": [
- "laravel",
- "oauth"
- ],
- "support": {
- "issues": "https://github.com/laravel/socialite/issues",
- "source": "https://github.com/laravel/socialite"
- },
- "time": "2025-02-11T13:38:19+00:00"
- },
{
"name": "laravel/tinker",
"version": "v2.10.1",
@@ -3425,142 +1455,6 @@
},
"time": "2025-01-27T14:24:01+00:00"
},
- {
- "name": "laravel/ui",
- "version": "v4.6.1",
- "source": {
- "type": "git",
- "url": "https://github.com/laravel/ui.git",
- "reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/laravel/ui/zipball/7d6ffa38d79f19c9b3e70a751a9af845e8f41d88",
- "reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88",
- "shasum": ""
- },
- "require": {
- "illuminate/console": "^9.21|^10.0|^11.0|^12.0",
- "illuminate/filesystem": "^9.21|^10.0|^11.0|^12.0",
- "illuminate/support": "^9.21|^10.0|^11.0|^12.0",
- "illuminate/validation": "^9.21|^10.0|^11.0|^12.0",
- "php": "^8.0",
- "symfony/console": "^6.0|^7.0"
- },
- "require-dev": {
- "orchestra/testbench": "^7.35|^8.15|^9.0|^10.0",
- "phpunit/phpunit": "^9.3|^10.4|^11.5"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Laravel\\Ui\\UiServiceProvider"
- ]
- },
- "branch-alias": {
- "dev-master": "4.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Laravel\\Ui\\": "src/",
- "Illuminate\\Foundation\\Auth\\": "auth-backend/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Taylor Otwell",
- "email": "taylor@laravel.com"
- }
- ],
- "description": "Laravel UI utilities and presets.",
- "keywords": [
- "laravel",
- "ui"
- ],
- "support": {
- "source": "https://github.com/laravel/ui/tree/v4.6.1"
- },
- "time": "2025-01-28T15:15:29+00:00"
- },
- {
- "name": "lcobucci/jwt",
- "version": "5.5.0",
- "source": {
- "type": "git",
- "url": "https://github.com/lcobucci/jwt.git",
- "reference": "a835af59b030d3f2967725697cf88300f579088e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/lcobucci/jwt/zipball/a835af59b030d3f2967725697cf88300f579088e",
- "reference": "a835af59b030d3f2967725697cf88300f579088e",
- "shasum": ""
- },
- "require": {
- "ext-openssl": "*",
- "ext-sodium": "*",
- "php": "~8.2.0 || ~8.3.0 || ~8.4.0",
- "psr/clock": "^1.0"
- },
- "require-dev": {
- "infection/infection": "^0.29",
- "lcobucci/clock": "^3.2",
- "lcobucci/coding-standard": "^11.0",
- "phpbench/phpbench": "^1.2",
- "phpstan/extension-installer": "^1.2",
- "phpstan/phpstan": "^1.10.7",
- "phpstan/phpstan-deprecation-rules": "^1.1.3",
- "phpstan/phpstan-phpunit": "^1.3.10",
- "phpstan/phpstan-strict-rules": "^1.5.0",
- "phpunit/phpunit": "^11.1"
- },
- "suggest": {
- "lcobucci/clock": ">= 3.2"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Lcobucci\\JWT\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Luís Cobucci",
- "email": "lcobucci@gmail.com",
- "role": "Developer"
- }
- ],
- "description": "A simple library to work with JSON Web Token and JSON Web Signature",
- "keywords": [
- "JWS",
- "jwt"
- ],
- "support": {
- "issues": "https://github.com/lcobucci/jwt/issues",
- "source": "https://github.com/lcobucci/jwt/tree/5.5.0"
- },
- "funding": [
- {
- "url": "https://github.com/lcobucci",
- "type": "github"
- },
- {
- "url": "https://www.patreon.com/lcobucci",
- "type": "patreon"
- }
- ],
- "time": "2025-01-26T21:29:45+00:00"
- },
{
"name": "league/commonmark",
"version": "2.6.1",
@@ -3833,61 +1727,6 @@
},
"time": "2024-10-08T08:58:34+00:00"
},
- {
- "name": "league/flysystem-aws-s3-v3",
- "version": "3.29.0",
- "source": {
- "type": "git",
- "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
- "reference": "c6ff6d4606e48249b63f269eba7fabdb584e76a9"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/c6ff6d4606e48249b63f269eba7fabdb584e76a9",
- "reference": "c6ff6d4606e48249b63f269eba7fabdb584e76a9",
- "shasum": ""
- },
- "require": {
- "aws/aws-sdk-php": "^3.295.10",
- "league/flysystem": "^3.10.0",
- "league/mime-type-detection": "^1.0.0",
- "php": "^8.0.2"
- },
- "conflict": {
- "guzzlehttp/guzzle": "<7.0",
- "guzzlehttp/ringphp": "<1.1.1"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "League\\Flysystem\\AwsS3V3\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Frank de Jonge",
- "email": "info@frankdejonge.nl"
- }
- ],
- "description": "AWS S3 filesystem adapter for Flysystem.",
- "keywords": [
- "Flysystem",
- "aws",
- "file",
- "files",
- "filesystem",
- "s3",
- "storage"
- ],
- "support": {
- "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.29.0"
- },
- "time": "2024-08-17T13:10:48+00:00"
- },
{
"name": "league/flysystem-local",
"version": "3.29.0",
@@ -3937,55 +1776,6 @@
},
"time": "2024-08-09T21:24:39+00:00"
},
- {
- "name": "league/flysystem-sftp-v3",
- "version": "3.29.0",
- "source": {
- "type": "git",
- "url": "https://github.com/thephpleague/flysystem-sftp-v3.git",
- "reference": "ce9b209e2fbe33122c755ffc18eb4d5bd256f252"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem-sftp-v3/zipball/ce9b209e2fbe33122c755ffc18eb4d5bd256f252",
- "reference": "ce9b209e2fbe33122c755ffc18eb4d5bd256f252",
- "shasum": ""
- },
- "require": {
- "league/flysystem": "^3.0.14",
- "league/mime-type-detection": "^1.0.0",
- "php": "^8.0.2",
- "phpseclib/phpseclib": "^3.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "League\\Flysystem\\PhpseclibV3\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Frank de Jonge",
- "email": "info@frankdejonge.nl"
- }
- ],
- "description": "SFTP filesystem adapter for Flysystem.",
- "keywords": [
- "Flysystem",
- "file",
- "files",
- "filesystem",
- "sftp"
- ],
- "support": {
- "source": "https://github.com/thephpleague/flysystem-sftp-v3/tree/3.29.0"
- },
- "time": "2024-08-14T19:35:54+00:00"
- },
{
"name": "league/mime-type-detection",
"version": "1.16.0",
@@ -4042,82 +1832,6 @@
],
"time": "2024-09-21T08:32:55+00:00"
},
- {
- "name": "league/oauth1-client",
- "version": "v1.11.0",
- "source": {
- "type": "git",
- "url": "https://github.com/thephpleague/oauth1-client.git",
- "reference": "f9c94b088837eb1aae1ad7c4f23eb65cc6993055"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/f9c94b088837eb1aae1ad7c4f23eb65cc6993055",
- "reference": "f9c94b088837eb1aae1ad7c4f23eb65cc6993055",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "ext-openssl": "*",
- "guzzlehttp/guzzle": "^6.0|^7.0",
- "guzzlehttp/psr7": "^1.7|^2.0",
- "php": ">=7.1||>=8.0"
- },
- "require-dev": {
- "ext-simplexml": "*",
- "friendsofphp/php-cs-fixer": "^2.17",
- "mockery/mockery": "^1.3.3",
- "phpstan/phpstan": "^0.12.42",
- "phpunit/phpunit": "^7.5||9.5"
- },
- "suggest": {
- "ext-simplexml": "For decoding XML-based responses."
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0-dev",
- "dev-develop": "2.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "League\\OAuth1\\Client\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ben Corlett",
- "email": "bencorlett@me.com",
- "homepage": "http://www.webcomm.com.au",
- "role": "Developer"
- }
- ],
- "description": "OAuth 1.0 Client Library",
- "keywords": [
- "Authentication",
- "SSO",
- "authorization",
- "bitbucket",
- "identity",
- "idp",
- "oauth",
- "oauth1",
- "single sign on",
- "trello",
- "tumblr",
- "twitter"
- ],
- "support": {
- "issues": "https://github.com/thephpleague/oauth1-client/issues",
- "source": "https://github.com/thephpleague/oauth1-client/tree/v1.11.0"
- },
- "time": "2024-12-10T19:59:05+00:00"
- },
{
"name": "league/uri",
"version": "7.5.1",
@@ -4292,292 +2006,6 @@
],
"time": "2024-12-08T08:18:47+00:00"
},
- {
- "name": "livewire/livewire",
- "version": "v3.5.20",
- "source": {
- "type": "git",
- "url": "https://github.com/livewire/livewire.git",
- "reference": "509f2258c51741f6d06deb65d4437654520694e6"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/livewire/livewire/zipball/509f2258c51741f6d06deb65d4437654520694e6",
- "reference": "509f2258c51741f6d06deb65d4437654520694e6",
- "shasum": ""
- },
- "require": {
- "illuminate/database": "^10.0|^11.0|^12.0",
- "illuminate/routing": "^10.0|^11.0|^12.0",
- "illuminate/support": "^10.0|^11.0|^12.0",
- "illuminate/validation": "^10.0|^11.0|^12.0",
- "laravel/prompts": "^0.1.24|^0.2|^0.3",
- "league/mime-type-detection": "^1.9",
- "php": "^8.1",
- "symfony/console": "^6.0|^7.0",
- "symfony/http-kernel": "^6.2|^7.0"
- },
- "require-dev": {
- "calebporzio/sushi": "^2.1",
- "laravel/framework": "^10.15.0|^11.0|^12.0",
- "mockery/mockery": "^1.3.1",
- "orchestra/testbench": "^8.21.0|^9.0|^10.0",
- "orchestra/testbench-dusk": "^8.24|^9.1|^10.0",
- "phpunit/phpunit": "^10.4|^11.5",
- "psy/psysh": "^0.11.22|^0.12"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "aliases": {
- "Livewire": "Livewire\\Livewire"
- },
- "providers": [
- "Livewire\\LivewireServiceProvider"
- ]
- }
- },
- "autoload": {
- "files": [
- "src/helpers.php"
- ],
- "psr-4": {
- "Livewire\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Caleb Porzio",
- "email": "calebporzio@gmail.com"
- }
- ],
- "description": "A front-end framework for Laravel.",
- "support": {
- "issues": "https://github.com/livewire/livewire/issues",
- "source": "https://github.com/livewire/livewire/tree/v3.5.20"
- },
- "funding": [
- {
- "url": "https://github.com/livewire",
- "type": "github"
- }
- ],
- "time": "2025-02-13T21:05:24+00:00"
- },
- {
- "name": "log1x/laravel-webfonts",
- "version": "v1.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/Log1x/laravel-webfonts.git",
- "reference": "128a20af26f02db84df21abc6524e5a069cf20a4"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Log1x/laravel-webfonts/zipball/128a20af26f02db84df21abc6524e5a069cf20a4",
- "reference": "128a20af26f02db84df21abc6524e5a069cf20a4",
- "shasum": ""
- },
- "require": {
- "guzzlehttp/guzzle": "^7.8",
- "laravel/prompts": "^0.1|^0.2|^0.3",
- "php": ">=8.1"
- },
- "require-dev": {
- "illuminate/console": "^10.0|^11.0",
- "illuminate/http": "^10.0|^11.0",
- "illuminate/support": "^10.0|^11.0",
- "laravel/pint": "^1.13"
- },
- "type": "package",
- "extra": {
- "laravel": {
- "providers": [
- "Log1x\\LaravelWebfonts\\WebfontsServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "Log1x\\LaravelWebfonts\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Brandon Nifong",
- "email": "brandon@tendency.me",
- "homepage": "https://github.com/log1x"
- }
- ],
- "description": "Download, install, and preload over 1500 Google fonts locally in your Laravel project",
- "support": {
- "issues": "https://github.com/Log1x/laravel-webfonts/issues",
- "source": "https://github.com/Log1x/laravel-webfonts/tree/v1.0.2"
- },
- "funding": [
- {
- "url": "https://github.com/Log1x",
- "type": "github"
- }
- ],
- "time": "2024-11-12T19:00:31+00:00"
- },
- {
- "name": "lorisleiva/laravel-actions",
- "version": "v2.8.6",
- "source": {
- "type": "git",
- "url": "https://github.com/lorisleiva/laravel-actions.git",
- "reference": "4647523599bee13cfd6b9bc9acdaf4503d4801ce"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/lorisleiva/laravel-actions/zipball/4647523599bee13cfd6b9bc9acdaf4503d4801ce",
- "reference": "4647523599bee13cfd6b9bc9acdaf4503d4801ce",
- "shasum": ""
- },
- "require": {
- "illuminate/contracts": "^10.0|^11.0",
- "lorisleiva/lody": "^0.5",
- "php": "^8.1"
- },
- "require-dev": {
- "orchestra/testbench": "^8.0|^9.0",
- "pestphp/pest": "^1.23|^2.34",
- "phpunit/phpunit": "^9.6|^10.0"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "aliases": {
- "Action": "Lorisleiva\\Actions\\Facades\\Actions"
- },
- "providers": [
- "Lorisleiva\\Actions\\ActionServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "Lorisleiva\\Actions\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Loris Leiva",
- "email": "loris.leiva@gmail.com",
- "homepage": "https://lorisleiva.com",
- "role": "Developer"
- }
- ],
- "description": "Laravel components that take care of one specific task",
- "homepage": "https://github.com/lorisleiva/laravel-actions",
- "keywords": [
- "action",
- "command",
- "component",
- "controller",
- "job",
- "laravel",
- "listener",
- "object"
- ],
- "support": {
- "issues": "https://github.com/lorisleiva/laravel-actions/issues",
- "source": "https://github.com/lorisleiva/laravel-actions/tree/v2.8.6"
- },
- "funding": [
- {
- "url": "https://github.com/sponsors/lorisleiva",
- "type": "github"
- }
- ],
- "time": "2025-02-04T08:36:29+00:00"
- },
- {
- "name": "lorisleiva/lody",
- "version": "v0.5.0",
- "source": {
- "type": "git",
- "url": "https://github.com/lorisleiva/lody.git",
- "reference": "c2f51b070e99f3a240d66cf68ef1f232036917fe"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/lorisleiva/lody/zipball/c2f51b070e99f3a240d66cf68ef1f232036917fe",
- "reference": "c2f51b070e99f3a240d66cf68ef1f232036917fe",
- "shasum": ""
- },
- "require": {
- "illuminate/contracts": "^9.0|^10.0|^11.0",
- "php": "^8.0"
- },
- "require-dev": {
- "orchestra/testbench": "^9.0",
- "pestphp/pest": "^1.20|^2.34",
- "phpunit/phpunit": "^9.5.10|^10.5"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "aliases": {
- "Lody": "Lorisleiva\\Lody\\Lody"
- },
- "providers": [
- "Lorisleiva\\Lody\\LodyServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "Lorisleiva\\Lody\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Loris Leiva",
- "email": "loris.leiva@gmail.com",
- "homepage": "https://lorisleiva.com",
- "role": "Developer"
- }
- ],
- "description": "Load files and classes as lazy collections in Laravel.",
- "homepage": "https://github.com/lorisleiva/lody",
- "keywords": [
- "classes",
- "collection",
- "files",
- "laravel",
- "load"
- ],
- "support": {
- "issues": "https://github.com/lorisleiva/lody/issues",
- "source": "https://github.com/lorisleiva/lody/tree/v0.5.0"
- },
- "funding": [
- {
- "url": "https://github.com/sponsors/lorisleiva",
- "type": "github"
- }
- ],
- "time": "2024-03-13T12:08:59+00:00"
- },
{
"name": "monolog/monolog",
"version": "3.8.1",
@@ -4681,72 +2109,6 @@
],
"time": "2024-12-05T17:15:07+00:00"
},
- {
- "name": "mtdowling/jmespath.php",
- "version": "2.8.0",
- "source": {
- "type": "git",
- "url": "https://github.com/jmespath/jmespath.php.git",
- "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc",
- "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc",
- "shasum": ""
- },
- "require": {
- "php": "^7.2.5 || ^8.0",
- "symfony/polyfill-mbstring": "^1.17"
- },
- "require-dev": {
- "composer/xdebug-handler": "^3.0.3",
- "phpunit/phpunit": "^8.5.33"
- },
- "bin": [
- "bin/jp.php"
- ],
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.8-dev"
- }
- },
- "autoload": {
- "files": [
- "src/JmesPath.php"
- ],
- "psr-4": {
- "JmesPath\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Graham Campbell",
- "email": "hello@gjcampbell.co.uk",
- "homepage": "https://github.com/GrahamCampbell"
- },
- {
- "name": "Michael Dowling",
- "email": "mtdowling@gmail.com",
- "homepage": "https://github.com/mtdowling"
- }
- ],
- "description": "Declaratively specify how to extract elements from a JSON document",
- "keywords": [
- "json",
- "jsonpath"
- ],
- "support": {
- "issues": "https://github.com/jmespath/jmespath.php/issues",
- "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0"
- },
- "time": "2024-09-04T18:46:31+00:00"
- },
{
"name": "nesbot/carbon",
"version": "3.8.6",
@@ -5059,59 +2421,6 @@
},
"time": "2024-12-30T11:07:19+00:00"
},
- {
- "name": "nubs/random-name-generator",
- "version": "v2.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/nubs/random-name-generator.git",
- "reference": "50abf24519badc5795a43c831f1d2a1faa45cb77"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/nubs/random-name-generator/zipball/50abf24519badc5795a43c831f1d2a1faa45cb77",
- "reference": "50abf24519badc5795a43c831f1d2a1faa45cb77",
- "shasum": ""
- },
- "require": {
- "php": "~5.6 || ~7.0 || ~8.0"
- },
- "require-dev": {
- "cinam/randomizer": ">=1.1.1,<2.0",
- "php-coveralls/php-coveralls": "~2.4",
- "phpunit/phpunit": "^5.0 || ^6.5 || ^7.0 || ^9.0",
- "squizlabs/php_codesniffer": "~2.3"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Nubs\\RandomNameGenerator\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Spencer Rinehart",
- "email": "anubis@overthemonkey.com",
- "role": "Developer"
- }
- ],
- "description": "A library to create interesting, sometimes entertaining, random names.",
- "keywords": [
- "alliteration",
- "generator",
- "random",
- "video game"
- ],
- "support": {
- "issues": "https://github.com/nubs/random-name-generator/issues",
- "source": "https://github.com/nubs/random-name-generator/tree/v2.2.0"
- },
- "time": "2021-01-12T13:46:08+00:00"
- },
{
"name": "nunomaduro/termwind",
"version": "v2.3.0",
@@ -5199,662 +2508,6 @@
],
"time": "2024-11-21T10:39:51+00:00"
},
- {
- "name": "nyholm/psr7",
- "version": "1.8.2",
- "source": {
- "type": "git",
- "url": "https://github.com/Nyholm/psr7.git",
- "reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Nyholm/psr7/zipball/a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
- "reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2",
- "psr/http-factory": "^1.0",
- "psr/http-message": "^1.1 || ^2.0"
- },
- "provide": {
- "php-http/message-factory-implementation": "1.0",
- "psr/http-factory-implementation": "1.0",
- "psr/http-message-implementation": "1.0"
- },
- "require-dev": {
- "http-interop/http-factory-tests": "^0.9",
- "php-http/message-factory": "^1.0",
- "php-http/psr7-integration-tests": "^1.0",
- "phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
- "symfony/error-handler": "^4.4"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.8-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Nyholm\\Psr7\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Tobias Nyholm",
- "email": "tobias.nyholm@gmail.com"
- },
- {
- "name": "Martijn van der Ven",
- "email": "martijn@vanderven.se"
- }
- ],
- "description": "A fast PHP7 implementation of PSR-7",
- "homepage": "https://tnyholm.se",
- "keywords": [
- "psr-17",
- "psr-7"
- ],
- "support": {
- "issues": "https://github.com/Nyholm/psr7/issues",
- "source": "https://github.com/Nyholm/psr7/tree/1.8.2"
- },
- "funding": [
- {
- "url": "https://github.com/Zegnat",
- "type": "github"
- },
- {
- "url": "https://github.com/nyholm",
- "type": "github"
- }
- ],
- "time": "2024-09-09T07:06:30+00:00"
- },
- {
- "name": "paragonie/constant_time_encoding",
- "version": "v3.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/paragonie/constant_time_encoding.git",
- "reference": "df1e7fde177501eee2037dd159cf04f5f301a512"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512",
- "reference": "df1e7fde177501eee2037dd159cf04f5f301a512",
- "shasum": ""
- },
- "require": {
- "php": "^8"
- },
- "require-dev": {
- "phpunit/phpunit": "^9",
- "vimeo/psalm": "^4|^5"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "ParagonIE\\ConstantTime\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Paragon Initiative Enterprises",
- "email": "security@paragonie.com",
- "homepage": "https://paragonie.com",
- "role": "Maintainer"
- },
- {
- "name": "Steve 'Sc00bz' Thomas",
- "email": "steve@tobtu.com",
- "homepage": "https://www.tobtu.com",
- "role": "Original Developer"
- }
- ],
- "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
- "keywords": [
- "base16",
- "base32",
- "base32_decode",
- "base32_encode",
- "base64",
- "base64_decode",
- "base64_encode",
- "bin2hex",
- "encoding",
- "hex",
- "hex2bin",
- "rfc4648"
- ],
- "support": {
- "email": "info@paragonie.com",
- "issues": "https://github.com/paragonie/constant_time_encoding/issues",
- "source": "https://github.com/paragonie/constant_time_encoding"
- },
- "time": "2024-05-08T12:36:18+00:00"
- },
- {
- "name": "paragonie/random_compat",
- "version": "v9.99.100",
- "source": {
- "type": "git",
- "url": "https://github.com/paragonie/random_compat.git",
- "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
- "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
- "shasum": ""
- },
- "require": {
- "php": ">= 7"
- },
- "require-dev": {
- "phpunit/phpunit": "4.*|5.*",
- "vimeo/psalm": "^1"
- },
- "suggest": {
- "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
- },
- "type": "library",
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Paragon Initiative Enterprises",
- "email": "security@paragonie.com",
- "homepage": "https://paragonie.com"
- }
- ],
- "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
- "keywords": [
- "csprng",
- "polyfill",
- "pseudorandom",
- "random"
- ],
- "support": {
- "email": "info@paragonie.com",
- "issues": "https://github.com/paragonie/random_compat/issues",
- "source": "https://github.com/paragonie/random_compat"
- },
- "time": "2020-10-15T08:29:30+00:00"
- },
- {
- "name": "paragonie/sodium_compat",
- "version": "v2.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/paragonie/sodium_compat.git",
- "reference": "a673d5f310477027cead2e2f2b6db5d8368157cb"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/a673d5f310477027cead2e2f2b6db5d8368157cb",
- "reference": "a673d5f310477027cead2e2f2b6db5d8368157cb",
- "shasum": ""
- },
- "require": {
- "php": "^8.1",
- "php-64bit": "*"
- },
- "require-dev": {
- "phpunit/phpunit": "^7|^8|^9",
- "vimeo/psalm": "^4|^5"
- },
- "suggest": {
- "ext-sodium": "Better performance, password hashing (Argon2i), secure memory management (memzero), and better security."
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0.x-dev"
- }
- },
- "autoload": {
- "files": [
- "autoload.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "ISC"
- ],
- "authors": [
- {
- "name": "Paragon Initiative Enterprises",
- "email": "security@paragonie.com"
- },
- {
- "name": "Frank Denis",
- "email": "jedisct1@pureftpd.org"
- }
- ],
- "description": "Pure PHP implementation of libsodium; uses the PHP extension if it exists",
- "keywords": [
- "Authentication",
- "BLAKE2b",
- "ChaCha20",
- "ChaCha20-Poly1305",
- "Chapoly",
- "Curve25519",
- "Ed25519",
- "EdDSA",
- "Edwards-curve Digital Signature Algorithm",
- "Elliptic Curve Diffie-Hellman",
- "Poly1305",
- "Pure-PHP cryptography",
- "RFC 7748",
- "RFC 8032",
- "Salpoly",
- "Salsa20",
- "X25519",
- "XChaCha20-Poly1305",
- "XSalsa20-Poly1305",
- "Xchacha20",
- "Xsalsa20",
- "aead",
- "cryptography",
- "ecdh",
- "elliptic curve",
- "elliptic curve cryptography",
- "encryption",
- "libsodium",
- "php",
- "public-key cryptography",
- "secret-key cryptography",
- "side-channel resistant"
- ],
- "support": {
- "issues": "https://github.com/paragonie/sodium_compat/issues",
- "source": "https://github.com/paragonie/sodium_compat/tree/v2.1.0"
- },
- "time": "2024-09-04T12:51:01+00:00"
- },
- {
- "name": "php-di/invoker",
- "version": "2.3.6",
- "source": {
- "type": "git",
- "url": "https://github.com/PHP-DI/Invoker.git",
- "reference": "59f15608528d8a8838d69b422a919fd6b16aa576"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/59f15608528d8a8838d69b422a919fd6b16aa576",
- "reference": "59f15608528d8a8838d69b422a919fd6b16aa576",
- "shasum": ""
- },
- "require": {
- "php": ">=7.3",
- "psr/container": "^1.0|^2.0"
- },
- "require-dev": {
- "athletic/athletic": "~0.1.8",
- "mnapoli/hard-mode": "~0.3.0",
- "phpunit/phpunit": "^9.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Invoker\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Generic and extensible callable invoker",
- "homepage": "https://github.com/PHP-DI/Invoker",
- "keywords": [
- "callable",
- "dependency",
- "dependency-injection",
- "injection",
- "invoke",
- "invoker"
- ],
- "support": {
- "issues": "https://github.com/PHP-DI/Invoker/issues",
- "source": "https://github.com/PHP-DI/Invoker/tree/2.3.6"
- },
- "funding": [
- {
- "url": "https://github.com/mnapoli",
- "type": "github"
- }
- ],
- "time": "2025-01-17T12:49:27+00:00"
- },
- {
- "name": "php-di/php-di",
- "version": "7.0.8",
- "source": {
- "type": "git",
- "url": "https://github.com/PHP-DI/PHP-DI.git",
- "reference": "98ddc81f8f768a2ad39e4cbe737285eaeabe577a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/98ddc81f8f768a2ad39e4cbe737285eaeabe577a",
- "reference": "98ddc81f8f768a2ad39e4cbe737285eaeabe577a",
- "shasum": ""
- },
- "require": {
- "laravel/serializable-closure": "^1.0 || ^2.0",
- "php": ">=8.0",
- "php-di/invoker": "^2.0",
- "psr/container": "^1.1 || ^2.0"
- },
- "provide": {
- "psr/container-implementation": "^1.0"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3",
- "friendsofphp/proxy-manager-lts": "^1",
- "mnapoli/phpunit-easymock": "^1.3",
- "phpunit/phpunit": "^9.6",
- "vimeo/psalm": "^4.6"
- },
- "suggest": {
- "friendsofphp/proxy-manager-lts": "Install it if you want to use lazy injection (version ^1)"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "DI\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "The dependency injection container for humans",
- "homepage": "https://php-di.org/",
- "keywords": [
- "PSR-11",
- "container",
- "container-interop",
- "dependency injection",
- "di",
- "ioc",
- "psr11"
- ],
- "support": {
- "issues": "https://github.com/PHP-DI/PHP-DI/issues",
- "source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.8"
- },
- "funding": [
- {
- "url": "https://github.com/mnapoli",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/php-di/php-di",
- "type": "tidelift"
- }
- ],
- "time": "2025-01-28T21:02:46+00:00"
- },
- {
- "name": "phpdocumentor/reflection",
- "version": "6.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/phpDocumentor/Reflection.git",
- "reference": "bb4dea805a645553d6d989b23dad9f8041f39502"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/Reflection/zipball/bb4dea805a645553d6d989b23dad9f8041f39502",
- "reference": "bb4dea805a645553d6d989b23dad9f8041f39502",
- "shasum": ""
- },
- "require": {
- "nikic/php-parser": "~4.18 || ^5.0",
- "php": "8.1.*|8.2.*|8.3.*|8.4.*",
- "phpdocumentor/reflection-common": "^2.1",
- "phpdocumentor/reflection-docblock": "^5",
- "phpdocumentor/type-resolver": "^1.2",
- "symfony/polyfill-php80": "^1.28",
- "webmozart/assert": "^1.7"
- },
- "require-dev": {
- "dealerdirect/phpcodesniffer-composer-installer": "^1.0",
- "doctrine/coding-standard": "^12.0",
- "mikey179/vfsstream": "~1.2",
- "mockery/mockery": "~1.6.0",
- "phpspec/prophecy-phpunit": "^2.0",
- "phpstan/extension-installer": "^1.1",
- "phpstan/phpstan": "^1.8",
- "phpstan/phpstan-webmozart-assert": "^1.2",
- "phpunit/phpunit": "^10.0",
- "psalm/phar": "^5.24",
- "rector/rector": "^1.0.0",
- "squizlabs/php_codesniffer": "^3.8"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-5.x": "5.3.x-dev",
- "dev-6.x": "6.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "phpDocumentor\\": "src/phpDocumentor"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Reflection library to do Static Analysis for PHP Projects",
- "homepage": "http://www.phpdoc.org",
- "keywords": [
- "phpDocumentor",
- "phpdoc",
- "reflection",
- "static analysis"
- ],
- "support": {
- "issues": "https://github.com/phpDocumentor/Reflection/issues",
- "source": "https://github.com/phpDocumentor/Reflection/tree/6.1.0"
- },
- "time": "2024-11-22T15:11:54+00:00"
- },
- {
- "name": "phpdocumentor/reflection-common",
- "version": "2.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
- "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
- "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
- "shasum": ""
- },
- "require": {
- "php": "^7.2 || ^8.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-2.x": "2.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jaap van Otterdijk",
- "email": "opensource@ijaap.nl"
- }
- ],
- "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
- "homepage": "http://www.phpdoc.org",
- "keywords": [
- "FQSEN",
- "phpDocumentor",
- "phpdoc",
- "reflection",
- "static analysis"
- ],
- "support": {
- "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
- "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
- },
- "time": "2020-06-27T09:03:43+00:00"
- },
- {
- "name": "phpdocumentor/reflection-docblock",
- "version": "5.6.1",
- "source": {
- "type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8",
- "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8",
- "shasum": ""
- },
- "require": {
- "doctrine/deprecations": "^1.1",
- "ext-filter": "*",
- "php": "^7.4 || ^8.0",
- "phpdocumentor/reflection-common": "^2.2",
- "phpdocumentor/type-resolver": "^1.7",
- "phpstan/phpdoc-parser": "^1.7|^2.0",
- "webmozart/assert": "^1.9.1"
- },
- "require-dev": {
- "mockery/mockery": "~1.3.5 || ~1.6.0",
- "phpstan/extension-installer": "^1.1",
- "phpstan/phpstan": "^1.8",
- "phpstan/phpstan-mockery": "^1.1",
- "phpstan/phpstan-webmozart-assert": "^1.2",
- "phpunit/phpunit": "^9.5",
- "psalm/phar": "^5.26"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Mike van Riel",
- "email": "me@mikevanriel.com"
- },
- {
- "name": "Jaap van Otterdijk",
- "email": "opensource@ijaap.nl"
- }
- ],
- "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
- "support": {
- "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
- "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.1"
- },
- "time": "2024-12-07T09:39:29+00:00"
- },
- {
- "name": "phpdocumentor/type-resolver",
- "version": "1.10.0",
- "source": {
- "type": "git",
- "url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a",
- "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a",
- "shasum": ""
- },
- "require": {
- "doctrine/deprecations": "^1.0",
- "php": "^7.3 || ^8.0",
- "phpdocumentor/reflection-common": "^2.0",
- "phpstan/phpdoc-parser": "^1.18|^2.0"
- },
- "require-dev": {
- "ext-tokenizer": "*",
- "phpbench/phpbench": "^1.2",
- "phpstan/extension-installer": "^1.1",
- "phpstan/phpstan": "^1.8",
- "phpstan/phpstan-phpunit": "^1.1",
- "phpunit/phpunit": "^9.5",
- "rector/rector": "^0.13.9",
- "vimeo/psalm": "^4.25"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-1.x": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Mike van Riel",
- "email": "me@mikevanriel.com"
- }
- ],
- "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
- "support": {
- "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
- "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0"
- },
- "time": "2024-11-09T15:12:26+00:00"
- },
{
"name": "phpoption/phpoption",
"version": "1.9.3",
@@ -5930,374 +2583,6 @@
],
"time": "2024-07-20T21:41:07+00:00"
},
- {
- "name": "phpseclib/phpseclib",
- "version": "3.0.43",
- "source": {
- "type": "git",
- "url": "https://github.com/phpseclib/phpseclib.git",
- "reference": "709ec107af3cb2f385b9617be72af8cf62441d02"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/709ec107af3cb2f385b9617be72af8cf62441d02",
- "reference": "709ec107af3cb2f385b9617be72af8cf62441d02",
- "shasum": ""
- },
- "require": {
- "paragonie/constant_time_encoding": "^1|^2|^3",
- "paragonie/random_compat": "^1.4|^2.0|^9.99.99",
- "php": ">=5.6.1"
- },
- "require-dev": {
- "phpunit/phpunit": "*"
- },
- "suggest": {
- "ext-dom": "Install the DOM extension to load XML formatted public keys.",
- "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
- "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
- "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
- "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
- },
- "type": "library",
- "autoload": {
- "files": [
- "phpseclib/bootstrap.php"
- ],
- "psr-4": {
- "phpseclib3\\": "phpseclib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jim Wigginton",
- "email": "terrafrost@php.net",
- "role": "Lead Developer"
- },
- {
- "name": "Patrick Monnerat",
- "email": "pm@datasphere.ch",
- "role": "Developer"
- },
- {
- "name": "Andreas Fischer",
- "email": "bantu@phpbb.com",
- "role": "Developer"
- },
- {
- "name": "Hans-Jürgen Petrich",
- "email": "petrich@tronic-media.com",
- "role": "Developer"
- },
- {
- "name": "Graham Campbell",
- "email": "graham@alt-three.com",
- "role": "Developer"
- }
- ],
- "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
- "homepage": "http://phpseclib.sourceforge.net",
- "keywords": [
- "BigInteger",
- "aes",
- "asn.1",
- "asn1",
- "blowfish",
- "crypto",
- "cryptography",
- "encryption",
- "rsa",
- "security",
- "sftp",
- "signature",
- "signing",
- "ssh",
- "twofish",
- "x.509",
- "x509"
- ],
- "support": {
- "issues": "https://github.com/phpseclib/phpseclib/issues",
- "source": "https://github.com/phpseclib/phpseclib/tree/3.0.43"
- },
- "funding": [
- {
- "url": "https://github.com/terrafrost",
- "type": "github"
- },
- {
- "url": "https://www.patreon.com/phpseclib",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
- "type": "tidelift"
- }
- ],
- "time": "2024-12-14T21:12:59+00:00"
- },
- {
- "name": "phpstan/phpdoc-parser",
- "version": "2.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/phpstan/phpdoc-parser.git",
- "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9b30d6fd026b2c132b3985ce6b23bec09ab3aa68",
- "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68",
- "shasum": ""
- },
- "require": {
- "php": "^7.4 || ^8.0"
- },
- "require-dev": {
- "doctrine/annotations": "^2.0",
- "nikic/php-parser": "^5.3.0",
- "php-parallel-lint/php-parallel-lint": "^1.2",
- "phpstan/extension-installer": "^1.0",
- "phpstan/phpstan": "^2.0",
- "phpstan/phpstan-phpunit": "^2.0",
- "phpstan/phpstan-strict-rules": "^2.0",
- "phpunit/phpunit": "^9.6",
- "symfony/process": "^5.2"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "PHPStan\\PhpDocParser\\": [
- "src/"
- ]
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "PHPDoc parser with support for nullable, intersection and generic types",
- "support": {
- "issues": "https://github.com/phpstan/phpdoc-parser/issues",
- "source": "https://github.com/phpstan/phpdoc-parser/tree/2.1.0"
- },
- "time": "2025-02-19T13:28:12+00:00"
- },
- {
- "name": "pion/laravel-chunk-upload",
- "version": "v1.5.4",
- "source": {
- "type": "git",
- "url": "https://github.com/pionl/laravel-chunk-upload.git",
- "reference": "cfbc4292ddcace51308a4f2f446d310aa04e6133"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/pionl/laravel-chunk-upload/zipball/cfbc4292ddcace51308a4f2f446d310aa04e6133",
- "reference": "cfbc4292ddcace51308a4f2f446d310aa04e6133",
- "shasum": ""
- },
- "require": {
- "illuminate/console": "5.2 - 5.8 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0",
- "illuminate/filesystem": "5.2 - 5.8 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0",
- "illuminate/http": "5.2 - 5.8 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0",
- "illuminate/support": "5.2 - 5.8 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^2.16.0 | ^3.52.0",
- "mockery/mockery": "^1.1.0 | ^1.3.0 | ^1.6.0",
- "overtrue/phplint": "^1.1 | ^2.0 | ^9.1",
- "phpunit/phpunit": "5.7 | 6.0 | 7.0 | 7.5 | 8.4 | ^8.5 | ^9.3 | ^10.0 | ^11.0"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Pion\\Laravel\\ChunkUpload\\Providers\\ChunkUploadServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "Pion\\Laravel\\ChunkUpload\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Martin Kluska",
- "email": "martin@kluska.cz"
- }
- ],
- "description": "Service for chunked upload with several js providers",
- "support": {
- "issues": "https://github.com/pionl/laravel-chunk-upload/issues",
- "source": "https://github.com/pionl/laravel-chunk-upload/tree/v1.5.4"
- },
- "funding": [
- {
- "url": "https://revolut.me/martinpv7n",
- "type": "custom"
- },
- {
- "url": "https://github.com/pionl",
- "type": "github"
- }
- ],
- "time": "2024-03-25T15:50:07+00:00"
- },
- {
- "name": "poliander/cron",
- "version": "3.2.1",
- "source": {
- "type": "git",
- "url": "https://github.com/poliander/cron.git",
- "reference": "68baf899189d0a68611b9575fc62642144877d80"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/poliander/cron/zipball/68baf899189d0a68611b9575fc62642144877d80",
- "reference": "68baf899189d0a68611b9575fc62642144877d80",
- "shasum": ""
- },
- "require": {
- "php": "8.2.* || 8.3.* || 8.4.*"
- },
- "require-dev": {
- "phpunit/phpunit": "~11.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Poliander\\Cron\\": "src/Cron/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "GPL-3.0-or-later"
- ],
- "authors": [
- {
- "name": "René Pollesch",
- "role": "Developer"
- }
- ],
- "description": "Standard (V7) compliant crontab expression parser/validator with support for time zones",
- "homepage": "https://github.com/poliander/cron",
- "support": {
- "issues": "https://github.com/poliander/cron/issues",
- "source": "https://github.com/poliander/cron/tree/3.2.1"
- },
- "time": "2024-12-21T05:57:05+00:00"
- },
- {
- "name": "pragmarx/google2fa",
- "version": "v8.0.3",
- "source": {
- "type": "git",
- "url": "https://github.com/antonioribeiro/google2fa.git",
- "reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad",
- "reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad",
- "shasum": ""
- },
- "require": {
- "paragonie/constant_time_encoding": "^1.0|^2.0|^3.0",
- "php": "^7.1|^8.0"
- },
- "require-dev": {
- "phpstan/phpstan": "^1.9",
- "phpunit/phpunit": "^7.5.15|^8.5|^9.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "PragmaRX\\Google2FA\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Antonio Carlos Ribeiro",
- "email": "acr@antoniocarlosribeiro.com",
- "role": "Creator & Designer"
- }
- ],
- "description": "A One Time Password Authentication package, compatible with Google Authenticator.",
- "keywords": [
- "2fa",
- "Authentication",
- "Two Factor Authentication",
- "google2fa"
- ],
- "support": {
- "issues": "https://github.com/antonioribeiro/google2fa/issues",
- "source": "https://github.com/antonioribeiro/google2fa/tree/v8.0.3"
- },
- "time": "2024-09-05T11:56:40+00:00"
- },
- {
- "name": "psr/cache",
- "version": "3.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/cache.git",
- "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
- "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
- "shasum": ""
- },
- "require": {
- "php": ">=8.0.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Cache\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common interface for caching libraries",
- "keywords": [
- "cache",
- "psr",
- "psr-6"
- ],
- "support": {
- "source": "https://github.com/php-fig/cache/tree/3.0.0"
- },
- "time": "2021-02-03T23:26:27+00:00"
- },
{
"name": "psr/clock",
"version": "1.0.0",
@@ -6712,16 +2997,16 @@
},
{
"name": "psy/psysh",
- "version": "v0.12.7",
+ "version": "v0.12.8",
"source": {
"type": "git",
"url": "https://github.com/bobthecow/psysh.git",
- "reference": "d73fa3c74918ef4522bb8a3bf9cab39161c4b57c"
+ "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/bobthecow/psysh/zipball/d73fa3c74918ef4522bb8a3bf9cab39161c4b57c",
- "reference": "d73fa3c74918ef4522bb8a3bf9cab39161c4b57c",
+ "url": "https://api.github.com/repos/bobthecow/psysh/zipball/85057ceedee50c49d4f6ecaff73ee96adb3b3625",
+ "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625",
"shasum": ""
},
"require": {
@@ -6785,118 +3070,9 @@
],
"support": {
"issues": "https://github.com/bobthecow/psysh/issues",
- "source": "https://github.com/bobthecow/psysh/tree/v0.12.7"
+ "source": "https://github.com/bobthecow/psysh/tree/v0.12.8"
},
- "time": "2024-12-10T01:58:33+00:00"
- },
- {
- "name": "purplepixie/phpdns",
- "version": "2.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/purplepixie/phpdns.git",
- "reference": "2b77de5bb218bc4e5d9c4a4a12bd18fe80a6ab4d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/purplepixie/phpdns/zipball/2b77de5bb218bc4e5d9c4a4a12bd18fe80a6ab4d",
- "reference": "2b77de5bb218bc4e5d9c4a4a12bd18fe80a6ab4d",
- "shasum": ""
- },
- "require": {
- "php": ">=7.4"
- },
- "require-dev": {
- "phpunit/phpunit": "^9.5"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0-dev"
- }
- },
- "autoload": {
- "psr-0": {
- "PurplePixie": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "GPL-3.0-only"
- ],
- "authors": [
- {
- "name": "David Cutting",
- "email": "dcutting@purplepixie.org"
- }
- ],
- "description": "PHP DNS Direct Query Module",
- "support": {
- "issues": "https://github.com/purplepixie/phpdns/issues",
- "source": "https://github.com/purplepixie/phpdns/tree/2.2.0"
- },
- "time": "2024-09-26T14:39:58+00:00"
- },
- {
- "name": "pusher/pusher-php-server",
- "version": "7.2.7",
- "source": {
- "type": "git",
- "url": "https://github.com/pusher/pusher-http-php.git",
- "reference": "148b0b5100d000ed57195acdf548a2b1b38ee3f7"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/pusher/pusher-http-php/zipball/148b0b5100d000ed57195acdf548a2b1b38ee3f7",
- "reference": "148b0b5100d000ed57195acdf548a2b1b38ee3f7",
- "shasum": ""
- },
- "require": {
- "ext-curl": "*",
- "ext-json": "*",
- "guzzlehttp/guzzle": "^7.2",
- "paragonie/sodium_compat": "^1.6|^2.0",
- "php": "^7.3|^8.0",
- "psr/log": "^1.0|^2.0|^3.0"
- },
- "require-dev": {
- "overtrue/phplint": "^2.3",
- "phpunit/phpunit": "^9.3"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Pusher\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Library for interacting with the Pusher REST API",
- "keywords": [
- "events",
- "messaging",
- "php-pusher-server",
- "publish",
- "push",
- "pusher",
- "real time",
- "real-time",
- "realtime",
- "rest",
- "trigger"
- ],
- "support": {
- "issues": "https://github.com/pusher/pusher-http-php/issues",
- "source": "https://github.com/pusher/pusher-http-php/tree/7.2.7"
- },
- "time": "2025-01-06T10:56:20+00:00"
+ "time": "2025-03-16T03:05:19+00:00"
},
{
"name": "ralouphie/getallheaders",
@@ -7110,1510 +3286,6 @@
],
"time": "2024-04-27T21:32:50+00:00"
},
- {
- "name": "resend/resend-laravel",
- "version": "v0.15.0",
- "source": {
- "type": "git",
- "url": "https://github.com/resend/resend-laravel.git",
- "reference": "af914817abc6abaa4522b5cfb177f3519493fd6e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/resend/resend-laravel/zipball/af914817abc6abaa4522b5cfb177f3519493fd6e",
- "reference": "af914817abc6abaa4522b5cfb177f3519493fd6e",
- "shasum": ""
- },
- "require": {
- "illuminate/http": "^10.0|^11.0",
- "illuminate/support": "^10.0|^11.0",
- "php": "^8.1",
- "resend/resend-php": "^0.14.0",
- "symfony/mailer": "^6.2|^7.0"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3.14",
- "mockery/mockery": "^1.5",
- "orchestra/testbench": "^8.17|^9.0",
- "pestphp/pest": "^2.0"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Resend\\Laravel\\ResendServiceProvider"
- ]
- },
- "branch-alias": {
- "dev-main": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Resend\\Laravel\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Resend and contributors",
- "homepage": "https://github.com/resend/resend-laravel/contributors"
- }
- ],
- "description": "Resend for Laravel",
- "homepage": "https://resend.com/",
- "keywords": [
- "api",
- "client",
- "laravel",
- "php",
- "resend",
- "sdk"
- ],
- "support": {
- "issues": "https://github.com/resend/resend-laravel/issues",
- "source": "https://github.com/resend/resend-laravel/tree/v0.15.0"
- },
- "time": "2024-11-04T18:34:08+00:00"
- },
- {
- "name": "resend/resend-php",
- "version": "v0.14.0",
- "source": {
- "type": "git",
- "url": "https://github.com/resend/resend-php.git",
- "reference": "d7900752bb9839421d40d9e66362bffb3ec07aac"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/resend/resend-php/zipball/d7900752bb9839421d40d9e66362bffb3ec07aac",
- "reference": "d7900752bb9839421d40d9e66362bffb3ec07aac",
- "shasum": ""
- },
- "require": {
- "guzzlehttp/guzzle": "^7.5",
- "php": "^8.1.0"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3.13",
- "mockery/mockery": "^1.6",
- "pestphp/pest": "^2.0"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/Resend.php"
- ],
- "psr-4": {
- "Resend\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Resend and contributors",
- "homepage": "https://github.com/resend/resend-php/contributors"
- }
- ],
- "description": "Resend PHP library.",
- "homepage": "https://resend.com/",
- "keywords": [
- "api",
- "client",
- "php",
- "resend",
- "sdk"
- ],
- "support": {
- "issues": "https://github.com/resend/resend-php/issues",
- "source": "https://github.com/resend/resend-php/tree/v0.14.0"
- },
- "time": "2024-11-01T02:00:44+00:00"
- },
- {
- "name": "revolt/event-loop",
- "version": "v1.0.7",
- "source": {
- "type": "git",
- "url": "https://github.com/revoltphp/event-loop.git",
- "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3",
- "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "ext-json": "*",
- "jetbrains/phpstorm-stubs": "^2019.3",
- "phpunit/phpunit": "^9",
- "psalm/phar": "^5.15"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Revolt\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Aaron Piotrowski",
- "email": "aaron@trowski.com"
- },
- {
- "name": "Cees-Jan Kiewiet",
- "email": "ceesjank@gmail.com"
- },
- {
- "name": "Christian Lück",
- "email": "christian@clue.engineering"
- },
- {
- "name": "Niklas Keller",
- "email": "me@kelunik.com"
- }
- ],
- "description": "Rock-solid event loop for concurrent PHP applications.",
- "keywords": [
- "async",
- "asynchronous",
- "concurrency",
- "event",
- "event-loop",
- "non-blocking",
- "scheduler"
- ],
- "support": {
- "issues": "https://github.com/revoltphp/event-loop/issues",
- "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7"
- },
- "time": "2025-01-25T19:27:39+00:00"
- },
- {
- "name": "sentry/sentry",
- "version": "4.10.0",
- "source": {
- "type": "git",
- "url": "https://github.com/getsentry/sentry-php.git",
- "reference": "2af937d47d8aadb8dab0b1d7b9557e495dd12856"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/2af937d47d8aadb8dab0b1d7b9557e495dd12856",
- "reference": "2af937d47d8aadb8dab0b1d7b9557e495dd12856",
- "shasum": ""
- },
- "require": {
- "ext-curl": "*",
- "ext-json": "*",
- "ext-mbstring": "*",
- "guzzlehttp/psr7": "^1.8.4|^2.1.1",
- "jean85/pretty-package-versions": "^1.5|^2.0.4",
- "php": "^7.2|^8.0",
- "psr/log": "^1.0|^2.0|^3.0",
- "symfony/options-resolver": "^4.4.30|^5.0.11|^6.0|^7.0"
- },
- "conflict": {
- "raven/raven": "*"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3.4",
- "guzzlehttp/promises": "^2.0.3",
- "guzzlehttp/psr7": "^1.8.4|^2.1.1",
- "monolog/monolog": "^1.6|^2.0|^3.0",
- "phpbench/phpbench": "^1.0",
- "phpstan/phpstan": "^1.3",
- "phpunit/phpunit": "^8.5|^9.6",
- "symfony/phpunit-bridge": "^5.2|^6.0|^7.0",
- "vimeo/psalm": "^4.17"
- },
- "suggest": {
- "monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler."
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/functions.php"
- ],
- "psr-4": {
- "Sentry\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Sentry",
- "email": "accounts@sentry.io"
- }
- ],
- "description": "PHP SDK for Sentry (http://sentry.io)",
- "homepage": "http://sentry.io",
- "keywords": [
- "crash-reporting",
- "crash-reports",
- "error-handler",
- "error-monitoring",
- "log",
- "logging",
- "profiling",
- "sentry",
- "tracing"
- ],
- "support": {
- "issues": "https://github.com/getsentry/sentry-php/issues",
- "source": "https://github.com/getsentry/sentry-php/tree/4.10.0"
- },
- "funding": [
- {
- "url": "https://sentry.io/",
- "type": "custom"
- },
- {
- "url": "https://sentry.io/pricing/",
- "type": "custom"
- }
- ],
- "time": "2024-11-06T07:44:19+00:00"
- },
- {
- "name": "sentry/sentry-laravel",
- "version": "4.13.0",
- "source": {
- "type": "git",
- "url": "https://github.com/getsentry/sentry-laravel.git",
- "reference": "d232ac494258e0d50a77c575a5af5f1a426d3f87"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/d232ac494258e0d50a77c575a5af5f1a426d3f87",
- "reference": "d232ac494258e0d50a77c575a5af5f1a426d3f87",
- "shasum": ""
- },
- "require": {
- "illuminate/support": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0 | ^12.0",
- "nyholm/psr7": "^1.0",
- "php": "^7.2 | ^8.0",
- "sentry/sentry": "^4.10",
- "symfony/psr-http-message-bridge": "^1.0 | ^2.0 | ^6.0 | ^7.0"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3.11",
- "guzzlehttp/guzzle": "^7.2",
- "laravel/folio": "^1.1",
- "laravel/framework": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0 | ^12.0",
- "livewire/livewire": "^2.0 | ^3.0",
- "mockery/mockery": "^1.3",
- "orchestra/testbench": "^4.7 | ^5.1 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0",
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^8.4 | ^9.3 | ^10.4 | ^11.5"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "aliases": {
- "Sentry": "Sentry\\Laravel\\Facade"
- },
- "providers": [
- "Sentry\\Laravel\\ServiceProvider",
- "Sentry\\Laravel\\Tracing\\ServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-0": {
- "Sentry\\Laravel\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Sentry",
- "email": "accounts@sentry.io"
- }
- ],
- "description": "Laravel SDK for Sentry (https://sentry.io)",
- "homepage": "https://sentry.io",
- "keywords": [
- "crash-reporting",
- "crash-reports",
- "error-handler",
- "error-monitoring",
- "laravel",
- "log",
- "logging",
- "profiling",
- "sentry",
- "tracing"
- ],
- "support": {
- "issues": "https://github.com/getsentry/sentry-laravel/issues",
- "source": "https://github.com/getsentry/sentry-laravel/tree/4.13.0"
- },
- "funding": [
- {
- "url": "https://sentry.io/",
- "type": "custom"
- },
- {
- "url": "https://sentry.io/pricing/",
- "type": "custom"
- }
- ],
- "time": "2025-02-18T10:09:29+00:00"
- },
- {
- "name": "socialiteproviders/authentik",
- "version": "5.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/SocialiteProviders/Authentik.git",
- "reference": "4cf129cf04728a38e0531c54454464b162f0fa66"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/SocialiteProviders/Authentik/zipball/4cf129cf04728a38e0531c54454464b162f0fa66",
- "reference": "4cf129cf04728a38e0531c54454464b162f0fa66",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "php": "^8.0",
- "socialiteproviders/manager": "^4.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "SocialiteProviders\\Authentik\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "rf152",
- "email": "git@rf152.co.uk"
- }
- ],
- "description": "Authentik OAuth2 Provider for Laravel Socialite",
- "keywords": [
- "authentik",
- "laravel",
- "oauth",
- "provider",
- "socialite"
- ],
- "support": {
- "docs": "https://socialiteproviders.com/authentik",
- "issues": "https://github.com/socialiteproviders/providers/issues",
- "source": "https://github.com/socialiteproviders/providers"
- },
- "time": "2023-11-07T22:21:16+00:00"
- },
- {
- "name": "socialiteproviders/google",
- "version": "4.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/SocialiteProviders/Google-Plus.git",
- "reference": "1cb8f6fb2c0dd0fc8b34e95f69865663fdf0b401"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/SocialiteProviders/Google-Plus/zipball/1cb8f6fb2c0dd0fc8b34e95f69865663fdf0b401",
- "reference": "1cb8f6fb2c0dd0fc8b34e95f69865663fdf0b401",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "php": "^7.2 || ^8.0",
- "socialiteproviders/manager": "~4.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "SocialiteProviders\\Google\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "xstoop",
- "email": "myenglishnameisx@gmail.com"
- }
- ],
- "description": "Google OAuth2 Provider for Laravel Socialite",
- "support": {
- "source": "https://github.com/SocialiteProviders/Google-Plus/tree/4.1.0"
- },
- "time": "2020-12-01T23:10:59+00:00"
- },
- {
- "name": "socialiteproviders/infomaniak",
- "version": "4.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/SocialiteProviders/Infomaniak.git",
- "reference": "9796ad686204443bfdf3ff19a6c409e8771667e1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/SocialiteProviders/Infomaniak/zipball/9796ad686204443bfdf3ff19a6c409e8771667e1",
- "reference": "9796ad686204443bfdf3ff19a6c409e8771667e1",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "php": "^8.0",
- "socialiteproviders/manager": "^4.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "SocialiteProviders\\Infomaniak\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Leopold Jacquot",
- "email": "leopold.jacquot@infomaniak.com"
- }
- ],
- "description": "Infomaniak OAuth2 Provider for Laravel Socialite",
- "keywords": [
- "infomaniak",
- "laravel",
- "oauth",
- "oauth2",
- "provider",
- "socialite"
- ],
- "support": {
- "docs": "https://socialiteproviders.com/qq",
- "issues": "https://github.com/socialiteproviders/providers/issues",
- "source": "https://github.com/socialiteproviders/providers"
- },
- "time": "2024-11-20T05:42:36+00:00"
- },
- {
- "name": "socialiteproviders/manager",
- "version": "v4.8.0",
- "source": {
- "type": "git",
- "url": "https://github.com/SocialiteProviders/Manager.git",
- "reference": "e93acc38f8464cc775a2b8bf09df311d1fdfefcb"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/SocialiteProviders/Manager/zipball/e93acc38f8464cc775a2b8bf09df311d1fdfefcb",
- "reference": "e93acc38f8464cc775a2b8bf09df311d1fdfefcb",
- "shasum": ""
- },
- "require": {
- "illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0",
- "laravel/socialite": "^5.5",
- "php": "^8.1"
- },
- "require-dev": {
- "mockery/mockery": "^1.2",
- "phpunit/phpunit": "^9.0"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "SocialiteProviders\\Manager\\ServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "SocialiteProviders\\Manager\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Andy Wendt",
- "email": "andy@awendt.com"
- },
- {
- "name": "Anton Komarev",
- "email": "a.komarev@cybercog.su"
- },
- {
- "name": "Miguel Piedrafita",
- "email": "soy@miguelpiedrafita.com"
- },
- {
- "name": "atymic",
- "email": "atymicq@gmail.com",
- "homepage": "https://atymic.dev"
- }
- ],
- "description": "Easily add new or override built-in providers in Laravel Socialite.",
- "homepage": "https://socialiteproviders.com",
- "keywords": [
- "laravel",
- "manager",
- "oauth",
- "providers",
- "socialite"
- ],
- "support": {
- "issues": "https://github.com/socialiteproviders/manager/issues",
- "source": "https://github.com/socialiteproviders/manager"
- },
- "time": "2025-01-03T09:40:37+00:00"
- },
- {
- "name": "socialiteproviders/microsoft-azure",
- "version": "5.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/SocialiteProviders/Microsoft-Azure.git",
- "reference": "453d62c9d7e3b3b76e94c913fb46e68a33347b16"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/SocialiteProviders/Microsoft-Azure/zipball/453d62c9d7e3b3b76e94c913fb46e68a33347b16",
- "reference": "453d62c9d7e3b3b76e94c913fb46e68a33347b16",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "php": "^8.0",
- "socialiteproviders/manager": "^4.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "SocialiteProviders\\Azure\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Chris Hemmings",
- "email": "chris@hemmin.gs"
- }
- ],
- "description": "Microsoft Azure OAuth2 Provider for Laravel Socialite",
- "keywords": [
- "azure",
- "laravel",
- "microsoft",
- "oauth",
- "provider",
- "socialite"
- ],
- "support": {
- "docs": "https://socialiteproviders.com/microsoft-azure",
- "issues": "https://github.com/socialiteproviders/providers/issues",
- "source": "https://github.com/socialiteproviders/providers"
- },
- "time": "2024-03-15T03:02:10+00:00"
- },
- {
- "name": "spatie/backtrace",
- "version": "1.7.1",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/backtrace.git",
- "reference": "0f2477c520e3729de58e061b8192f161c99f770b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/backtrace/zipball/0f2477c520e3729de58e061b8192f161c99f770b",
- "reference": "0f2477c520e3729de58e061b8192f161c99f770b",
- "shasum": ""
- },
- "require": {
- "php": "^7.3 || ^8.0"
- },
- "require-dev": {
- "ext-json": "*",
- "laravel/serializable-closure": "^1.3 || ^2.0",
- "phpunit/phpunit": "^9.3 || ^11.4.3",
- "spatie/phpunit-snapshot-assertions": "^4.2 || ^5.1.6",
- "symfony/var-dumper": "^5.1 || ^6.0 || ^7.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Spatie\\Backtrace\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Freek Van de Herten",
- "email": "freek@spatie.be",
- "homepage": "https://spatie.be",
- "role": "Developer"
- }
- ],
- "description": "A better backtrace",
- "homepage": "https://github.com/spatie/backtrace",
- "keywords": [
- "Backtrace",
- "spatie"
- ],
- "support": {
- "source": "https://github.com/spatie/backtrace/tree/1.7.1"
- },
- "funding": [
- {
- "url": "https://github.com/sponsors/spatie",
- "type": "github"
- },
- {
- "url": "https://spatie.be/open-source/support-us",
- "type": "other"
- }
- ],
- "time": "2024-12-02T13:28:15+00:00"
- },
- {
- "name": "spatie/laravel-activitylog",
- "version": "4.10.1",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/laravel-activitylog.git",
- "reference": "466f30f7245fe3a6e328ad5e6812bd43b4bddea5"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/laravel-activitylog/zipball/466f30f7245fe3a6e328ad5e6812bd43b4bddea5",
- "reference": "466f30f7245fe3a6e328ad5e6812bd43b4bddea5",
- "shasum": ""
- },
- "require": {
- "illuminate/config": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
- "illuminate/database": "^8.69 || ^9.27 || ^10.0 || ^11.0 || ^12.0",
- "illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
- "php": "^8.1",
- "spatie/laravel-package-tools": "^1.6.3"
- },
- "require-dev": {
- "ext-json": "*",
- "orchestra/testbench": "^6.23 || ^7.0 || ^8.0 || ^9.0 || ^10.0",
- "pestphp/pest": "^1.20 || ^2.0 || ^3.0"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Spatie\\Activitylog\\ActivitylogServiceProvider"
- ]
- }
- },
- "autoload": {
- "files": [
- "src/helpers.php"
- ],
- "psr-4": {
- "Spatie\\Activitylog\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Freek Van der Herten",
- "email": "freek@spatie.be",
- "homepage": "https://spatie.be",
- "role": "Developer"
- },
- {
- "name": "Sebastian De Deyne",
- "email": "sebastian@spatie.be",
- "homepage": "https://spatie.be",
- "role": "Developer"
- },
- {
- "name": "Tom Witkowski",
- "email": "dev.gummibeer@gmail.com",
- "homepage": "https://gummibeer.de",
- "role": "Developer"
- }
- ],
- "description": "A very simple activity logger to monitor the users of your website or application",
- "homepage": "https://github.com/spatie/activitylog",
- "keywords": [
- "activity",
- "laravel",
- "log",
- "spatie",
- "user"
- ],
- "support": {
- "issues": "https://github.com/spatie/laravel-activitylog/issues",
- "source": "https://github.com/spatie/laravel-activitylog/tree/4.10.1"
- },
- "funding": [
- {
- "url": "https://spatie.be/open-source/support-us",
- "type": "custom"
- },
- {
- "url": "https://github.com/spatie",
- "type": "github"
- }
- ],
- "time": "2025-02-10T15:38:25+00:00"
- },
- {
- "name": "spatie/laravel-data",
- "version": "4.13.1",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/laravel-data.git",
- "reference": "14252330397cf84647cc086324ea1a30dbe5f7cc"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/laravel-data/zipball/14252330397cf84647cc086324ea1a30dbe5f7cc",
- "reference": "14252330397cf84647cc086324ea1a30dbe5f7cc",
- "shasum": ""
- },
- "require": {
- "illuminate/contracts": "^10.0|^11.0|^12.0",
- "php": "^8.1",
- "phpdocumentor/reflection": "^6.0",
- "spatie/laravel-package-tools": "^1.9.0",
- "spatie/php-structure-discoverer": "^2.0"
- },
- "require-dev": {
- "fakerphp/faker": "^1.14",
- "friendsofphp/php-cs-fixer": "^3.0",
- "livewire/livewire": "^3.0",
- "mockery/mockery": "^1.6",
- "nesbot/carbon": "^2.63|^3.0",
- "orchestra/testbench": "^8.0|^9.0|^10.0",
- "pestphp/pest": "^2.31|^3.0",
- "pestphp/pest-plugin-laravel": "^2.0|^3.0",
- "pestphp/pest-plugin-livewire": "^2.1|^3.0",
- "phpbench/phpbench": "^1.2",
- "phpstan/extension-installer": "^1.1",
- "phpunit/phpunit": "^10.0|^11.0|^12.0",
- "spatie/invade": "^1.0",
- "spatie/laravel-typescript-transformer": "^2.5",
- "spatie/pest-plugin-snapshots": "^2.1",
- "spatie/test-time": "^1.2"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Spatie\\LaravelData\\LaravelDataServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "Spatie\\LaravelData\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ruben Van Assche",
- "email": "ruben@spatie.be",
- "role": "Developer"
- }
- ],
- "description": "Create unified resources and data transfer objects",
- "homepage": "https://github.com/spatie/laravel-data",
- "keywords": [
- "laravel",
- "laravel-data",
- "spatie"
- ],
- "support": {
- "issues": "https://github.com/spatie/laravel-data/issues",
- "source": "https://github.com/spatie/laravel-data/tree/4.13.1"
- },
- "funding": [
- {
- "url": "https://github.com/spatie",
- "type": "github"
- }
- ],
- "time": "2025-02-14T14:29:16+00:00"
- },
- {
- "name": "spatie/laravel-package-tools",
- "version": "1.19.0",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/laravel-package-tools.git",
- "reference": "1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa",
- "reference": "1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa",
- "shasum": ""
- },
- "require": {
- "illuminate/contracts": "^9.28|^10.0|^11.0|^12.0",
- "php": "^8.0"
- },
- "require-dev": {
- "mockery/mockery": "^1.5",
- "orchestra/testbench": "^7.7|^8.0|^9.0|^10.0",
- "pestphp/pest": "^1.23|^2.1|^3.1",
- "phpunit/phpunit": "^9.5.24|^10.5|^11.5",
- "spatie/pest-plugin-test-time": "^1.1|^2.2"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Spatie\\LaravelPackageTools\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Freek Van der Herten",
- "email": "freek@spatie.be",
- "role": "Developer"
- }
- ],
- "description": "Tools for creating Laravel packages",
- "homepage": "https://github.com/spatie/laravel-package-tools",
- "keywords": [
- "laravel-package-tools",
- "spatie"
- ],
- "support": {
- "issues": "https://github.com/spatie/laravel-package-tools/issues",
- "source": "https://github.com/spatie/laravel-package-tools/tree/1.19.0"
- },
- "funding": [
- {
- "url": "https://github.com/spatie",
- "type": "github"
- }
- ],
- "time": "2025-02-06T14:58:20+00:00"
- },
- {
- "name": "spatie/laravel-ray",
- "version": "1.39.1",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/laravel-ray.git",
- "reference": "0d890fa2cd2c0b6175cf54c56b9321d81047571d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/0d890fa2cd2c0b6175cf54c56b9321d81047571d",
- "reference": "0d890fa2cd2c0b6175cf54c56b9321d81047571d",
- "shasum": ""
- },
- "require": {
- "composer-runtime-api": "^2.2",
- "ext-json": "*",
- "illuminate/contracts": "^7.20 || ^8.19 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
- "illuminate/database": "^7.20 || ^8.19 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
- "illuminate/queue": "^7.20 || ^8.19 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
- "illuminate/support": "^7.20 || ^8.19 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
- "php": "^7.4 || ^8.0",
- "spatie/backtrace": "^1.7.1",
- "spatie/ray": "^1.41.3",
- "symfony/stopwatch": "4.2 || ^5.1 || ^6.0 || ^7.0",
- "zbateson/mail-mime-parser": "^1.3.1 || ^2.0 || ^3.0"
- },
- "require-dev": {
- "guzzlehttp/guzzle": "^7.3",
- "laravel/framework": "^7.20 || ^8.19 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
- "orchestra/testbench-core": "^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0",
- "pestphp/pest": "^1.22 || ^2.0 || ^3.0",
- "phpstan/phpstan": "^1.10.57 || ^2.0.2",
- "phpunit/phpunit": "^9.3 || ^10.1 || ^11.0.10",
- "rector/rector": "^0.19.2 || ^1.0.1 || ^2.0.0",
- "spatie/pest-plugin-snapshots": "^1.1 || ^2.0",
- "symfony/var-dumper": "^4.2 || ^5.1 || ^6.0 || ^7.0.3"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Spatie\\LaravelRay\\RayServiceProvider"
- ]
- },
- "branch-alias": {
- "dev-main": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Spatie\\LaravelRay\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Freek Van der Herten",
- "email": "freek@spatie.be",
- "homepage": "https://spatie.be",
- "role": "Developer"
- }
- ],
- "description": "Easily debug Laravel apps",
- "homepage": "https://github.com/spatie/laravel-ray",
- "keywords": [
- "laravel-ray",
- "spatie"
- ],
- "support": {
- "issues": "https://github.com/spatie/laravel-ray/issues",
- "source": "https://github.com/spatie/laravel-ray/tree/1.39.1"
- },
- "funding": [
- {
- "url": "https://github.com/sponsors/spatie",
- "type": "github"
- },
- {
- "url": "https://spatie.be/open-source/support-us",
- "type": "other"
- }
- ],
- "time": "2025-02-05T08:16:15+00:00"
- },
- {
- "name": "spatie/laravel-schemaless-attributes",
- "version": "2.5.1",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/laravel-schemaless-attributes.git",
- "reference": "3561875fb6886ae55e5378f20ba5ac87f20b265a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/laravel-schemaless-attributes/zipball/3561875fb6886ae55e5378f20ba5ac87f20b265a",
- "reference": "3561875fb6886ae55e5378f20ba5ac87f20b265a",
- "shasum": ""
- },
- "require": {
- "illuminate/contracts": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
- "illuminate/database": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
- "illuminate/support": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
- "php": "^8.0",
- "spatie/laravel-package-tools": "^1.4.3"
- },
- "require-dev": {
- "brianium/paratest": "^6.2|^7.4",
- "mockery/mockery": "^1.4",
- "nunomaduro/collision": "^5.3|^6.0|^8.0",
- "orchestra/testbench": "^6.15|^7.0|^8.0|^9.0|^10.0",
- "pestphp/pest-plugin-laravel": "^1.3|^2.1|^3.1",
- "phpunit/phpunit": "^9.6|^10.5|^11.5|^12.0"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Spatie\\SchemalessAttributes\\SchemalessAttributesServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "Spatie\\SchemalessAttributes\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Freek Van der Herten",
- "email": "freek@spatie.be",
- "homepage": "https://spatie.be",
- "role": "Developer"
- }
- ],
- "description": "Add schemaless attributes to Eloquent models",
- "homepage": "https://github.com/spatie/laravel-schemaless-attributes",
- "keywords": [
- "laravel-schemaless-attributes",
- "spatie"
- ],
- "support": {
- "issues": "https://github.com/spatie/laravel-schemaless-attributes/issues",
- "source": "https://github.com/spatie/laravel-schemaless-attributes/tree/2.5.1"
- },
- "funding": [
- {
- "url": "https://spatie.be/open-source/support-us",
- "type": "custom"
- },
- {
- "url": "https://github.com/spatie",
- "type": "github"
- }
- ],
- "time": "2025-02-10T09:28:22+00:00"
- },
- {
- "name": "spatie/macroable",
- "version": "2.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/macroable.git",
- "reference": "ec2c320f932e730607aff8052c44183cf3ecb072"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/macroable/zipball/ec2c320f932e730607aff8052c44183cf3ecb072",
- "reference": "ec2c320f932e730607aff8052c44183cf3ecb072",
- "shasum": ""
- },
- "require": {
- "php": "^8.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^8.0|^9.3"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Spatie\\Macroable\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Freek Van der Herten",
- "email": "freek@spatie.be",
- "homepage": "https://spatie.be",
- "role": "Developer"
- }
- ],
- "description": "A trait to dynamically add methods to a class",
- "homepage": "https://github.com/spatie/macroable",
- "keywords": [
- "macroable",
- "spatie"
- ],
- "support": {
- "issues": "https://github.com/spatie/macroable/issues",
- "source": "https://github.com/spatie/macroable/tree/2.0.0"
- },
- "time": "2021-03-26T22:39:02+00:00"
- },
- {
- "name": "spatie/php-structure-discoverer",
- "version": "2.3.1",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/php-structure-discoverer.git",
- "reference": "42f4d731d3dd4b3b85732e05a8c1928fcfa2f4bc"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/php-structure-discoverer/zipball/42f4d731d3dd4b3b85732e05a8c1928fcfa2f4bc",
- "reference": "42f4d731d3dd4b3b85732e05a8c1928fcfa2f4bc",
- "shasum": ""
- },
- "require": {
- "amphp/amp": "^v3.0",
- "amphp/parallel": "^2.2",
- "illuminate/collections": "^10.0|^11.0|^12.0",
- "php": "^8.1",
- "spatie/laravel-package-tools": "^1.4.3",
- "symfony/finder": "^6.0|^7.0"
- },
- "require-dev": {
- "illuminate/console": "^10.0|^11.0|^12.0",
- "laravel/pint": "^1.0",
- "nunomaduro/collision": "^7.0|^8.0",
- "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
- "pestphp/pest": "^2.0|^3.0",
- "pestphp/pest-plugin-laravel": "^2.0|^3.0",
- "phpstan/extension-installer": "^1.1",
- "phpstan/phpstan-deprecation-rules": "^1.0",
- "phpstan/phpstan-phpunit": "^1.0",
- "phpunit/phpunit": "^9.5|^10.0|^11.5.3",
- "spatie/laravel-ray": "^1.26"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Spatie\\StructureDiscoverer\\StructureDiscovererServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "Spatie\\StructureDiscoverer\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ruben Van Assche",
- "email": "ruben@spatie.be",
- "role": "Developer"
- }
- ],
- "description": "Automatically discover structures within your PHP application",
- "homepage": "https://github.com/spatie/php-structure-discoverer",
- "keywords": [
- "discover",
- "laravel",
- "php",
- "php-structure-discoverer"
- ],
- "support": {
- "issues": "https://github.com/spatie/php-structure-discoverer/issues",
- "source": "https://github.com/spatie/php-structure-discoverer/tree/2.3.1"
- },
- "funding": [
- {
- "url": "https://github.com/LaravelAutoDiscoverer",
- "type": "github"
- }
- ],
- "time": "2025-02-14T10:18:38+00:00"
- },
- {
- "name": "spatie/ray",
- "version": "1.41.5",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/ray.git",
- "reference": "9d078f04ffa32ad543a20716844ec343fdd7d856"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/ray/zipball/9d078f04ffa32ad543a20716844ec343fdd7d856",
- "reference": "9d078f04ffa32ad543a20716844ec343fdd7d856",
- "shasum": ""
- },
- "require": {
- "ext-curl": "*",
- "ext-json": "*",
- "php": "^7.4 || ^8.0",
- "ramsey/uuid": "^3.0 || ^4.1",
- "spatie/backtrace": "^1.7.1",
- "spatie/macroable": "^1.0 || ^2.0",
- "symfony/stopwatch": "^4.2 || ^5.1 || ^6.0 || ^7.0",
- "symfony/var-dumper": "^4.2 || ^5.1 || ^6.0 || ^7.0.3"
- },
- "require-dev": {
- "illuminate/support": "^7.20 || ^8.18 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
- "nesbot/carbon": "^2.63 || ^3.8.4",
- "pestphp/pest": "^1.22",
- "phpstan/phpstan": "^1.10.57 || ^2.0.3",
- "phpunit/phpunit": "^9.5",
- "rector/rector": "^0.19.2 || ^1.0.1 || ^2.0.0",
- "spatie/phpunit-snapshot-assertions": "^4.2",
- "spatie/test-time": "^1.2"
- },
- "bin": [
- "bin/remove-ray.sh"
- ],
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.x-dev"
- }
- },
- "autoload": {
- "files": [
- "src/helpers.php"
- ],
- "psr-4": {
- "Spatie\\Ray\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Freek Van der Herten",
- "email": "freek@spatie.be",
- "homepage": "https://spatie.be",
- "role": "Developer"
- }
- ],
- "description": "Debug with Ray to fix problems faster",
- "homepage": "https://github.com/spatie/ray",
- "keywords": [
- "ray",
- "spatie"
- ],
- "support": {
- "issues": "https://github.com/spatie/ray/issues",
- "source": "https://github.com/spatie/ray/tree/1.41.5"
- },
- "funding": [
- {
- "url": "https://github.com/sponsors/spatie",
- "type": "github"
- },
- {
- "url": "https://spatie.be/open-source/support-us",
- "type": "other"
- }
- ],
- "time": "2025-02-14T12:51:43+00:00"
- },
- {
- "name": "spatie/url",
- "version": "2.4.0",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/url.git",
- "reference": "93a51db743cdec22b081c64593e193887c9cd395"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/url/zipball/93a51db743cdec22b081c64593e193887c9cd395",
- "reference": "93a51db743cdec22b081c64593e193887c9cd395",
- "shasum": ""
- },
- "require": {
- "php": "^8.0",
- "psr/http-message": "^1.0 || ^2.0",
- "spatie/macroable": "^1.0 || ^2.0"
- },
- "require-dev": {
- "pestphp/pest": "^1.21"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Spatie\\Url\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Sebastian De Deyne",
- "email": "sebastian@spatie.be",
- "homepage": "https://spatie.be",
- "role": "Developer"
- }
- ],
- "description": "Parse, build and manipulate URL's",
- "homepage": "https://github.com/spatie/url",
- "keywords": [
- "spatie",
- "url"
- ],
- "support": {
- "issues": "https://github.com/spatie/url/issues",
- "source": "https://github.com/spatie/url/tree/2.4.0"
- },
- "funding": [
- {
- "url": "https://spatie.be/open-source/support-us",
- "type": "custom"
- },
- {
- "url": "https://github.com/spatie",
- "type": "github"
- }
- ],
- "time": "2024-03-08T11:35:19+00:00"
- },
- {
- "name": "stevebauman/purify",
- "version": "v6.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/stevebauman/purify.git",
- "reference": "2e5e6e1bfe072189b6056c6ad4a8c68ba57f3ba1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/stevebauman/purify/zipball/2e5e6e1bfe072189b6056c6ad4a8c68ba57f3ba1",
- "reference": "2e5e6e1bfe072189b6056c6ad4a8c68ba57f3ba1",
- "shasum": ""
- },
- "require": {
- "ezyang/htmlpurifier": "^4.17",
- "illuminate/contracts": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
- "illuminate/support": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
- "php": ">=7.4"
- },
- "require-dev": {
- "orchestra/testbench": "^5.0|^6.0|^7.0|^8.0|^9.0|^10.0",
- "phpunit/phpunit": "^8.0|^9.0|^10.0|^11.5.3"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "aliases": {
- "Purify": "Stevebauman\\Purify\\Facades\\Purify"
- },
- "providers": [
- "Stevebauman\\Purify\\PurifyServiceProvider"
- ]
- }
- },
- "autoload": {
- "psr-4": {
- "Stevebauman\\Purify\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Steve Bauman",
- "email": "steven_bauman@outlook.com"
- }
- ],
- "description": "An HTML Purifier / Sanitizer for Laravel",
- "keywords": [
- "Purifier",
- "clean",
- "cleaner",
- "html",
- "laravel",
- "purification",
- "purify"
- ],
- "support": {
- "issues": "https://github.com/stevebauman/purify/issues",
- "source": "https://github.com/stevebauman/purify/tree/v6.3.0"
- },
- "time": "2025-02-18T23:08:15+00:00"
- },
- {
- "name": "stripe/stripe-php",
- "version": "v16.5.1",
- "source": {
- "type": "git",
- "url": "https://github.com/stripe/stripe-php.git",
- "reference": "05c7c3a8a15b1bc396f09d17c88539c0db3d3255"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/stripe/stripe-php/zipball/05c7c3a8a15b1bc396f09d17c88539c0db3d3255",
- "reference": "05c7c3a8a15b1bc396f09d17c88539c0db3d3255",
- "shasum": ""
- },
- "require": {
- "ext-curl": "*",
- "ext-json": "*",
- "ext-mbstring": "*",
- "php": ">=5.6.0"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "3.5.0",
- "phpstan/phpstan": "^1.2",
- "phpunit/phpunit": "^5.7 || ^9.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Stripe\\": "lib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Stripe and contributors",
- "homepage": "https://github.com/stripe/stripe-php/contributors"
- }
- ],
- "description": "Stripe PHP Library",
- "homepage": "https://stripe.com/",
- "keywords": [
- "api",
- "payment processing",
- "stripe"
- ],
- "support": {
- "issues": "https://github.com/stripe/stripe-php/issues",
- "source": "https://github.com/stripe/stripe-php/tree/v16.5.1"
- },
- "time": "2025-02-07T21:24:29+00:00"
- },
{
"name": "symfony/clock",
"version": "v7.2.0",
@@ -9564,73 +4236,6 @@
],
"time": "2025-02-19T08:51:20+00:00"
},
- {
- "name": "symfony/options-resolver",
- "version": "v7.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/options-resolver.git",
- "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50",
- "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50",
- "shasum": ""
- },
- "require": {
- "php": ">=8.2",
- "symfony/deprecation-contracts": "^2.5|^3"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\OptionsResolver\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides an improved replacement for the array_replace PHP function",
- "homepage": "https://symfony.com",
- "keywords": [
- "config",
- "configuration",
- "options"
- ],
- "support": {
- "source": "https://github.com/symfony/options-resolver/tree/v7.2.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-11-20T11:17:29+00:00"
- },
{
"name": "symfony/polyfill-ctype",
"version": "v1.31.0",
@@ -9710,86 +4315,6 @@
],
"time": "2024-09-09T11:45:10+00:00"
},
- {
- "name": "symfony/polyfill-iconv",
- "version": "v1.31.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-iconv.git",
- "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/48becf00c920479ca2e910c22a5a39e5d47ca956",
- "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "provide": {
- "ext-iconv": "*"
- },
- "suggest": {
- "ext-iconv": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Iconv\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for the Iconv extension",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "iconv",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-iconv/tree/v1.31.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-09T11:45:10+00:00"
- },
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.31.0",
@@ -10408,89 +4933,6 @@
],
"time": "2025-02-05T08:33:46+00:00"
},
- {
- "name": "symfony/psr-http-message-bridge",
- "version": "v7.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/psr-http-message-bridge.git",
- "reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/03f2f72319e7acaf2a9f6fcbe30ef17eec51594f",
- "reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f",
- "shasum": ""
- },
- "require": {
- "php": ">=8.2",
- "psr/http-message": "^1.0|^2.0",
- "symfony/http-foundation": "^6.4|^7.0"
- },
- "conflict": {
- "php-http/discovery": "<1.15",
- "symfony/http-kernel": "<6.4"
- },
- "require-dev": {
- "nyholm/psr7": "^1.1",
- "php-http/discovery": "^1.15",
- "psr/log": "^1.1.4|^2|^3",
- "symfony/browser-kit": "^6.4|^7.0",
- "symfony/config": "^6.4|^7.0",
- "symfony/event-dispatcher": "^6.4|^7.0",
- "symfony/framework-bundle": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0"
- },
- "type": "symfony-bridge",
- "autoload": {
- "psr-4": {
- "Symfony\\Bridge\\PsrHttpMessage\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "PSR HTTP message bridge",
- "homepage": "https://symfony.com",
- "keywords": [
- "http",
- "http-message",
- "psr-17",
- "psr-7"
- ],
- "support": {
- "source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.2.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-26T08:57:56+00:00"
- },
{
"name": "symfony/routing",
"version": "v7.2.3",
@@ -10655,68 +5097,6 @@
],
"time": "2024-09-25T14:20:29+00:00"
},
- {
- "name": "symfony/stopwatch",
- "version": "v7.2.2",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/stopwatch.git",
- "reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/stopwatch/zipball/e46690d5b9d7164a6d061cab1e8d46141b9f49df",
- "reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df",
- "shasum": ""
- },
- "require": {
- "php": ">=8.2",
- "symfony/service-contracts": "^2.5|^3"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Stopwatch\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides a way to profile code",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/stopwatch/tree/v7.2.2"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-12-18T14:28:33+00:00"
- },
{
"name": "symfony/string",
"version": "v7.2.0",
@@ -11134,78 +5514,6 @@
],
"time": "2025-01-17T11:39:41+00:00"
},
- {
- "name": "symfony/yaml",
- "version": "v7.2.3",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/yaml.git",
- "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/ac238f173df0c9c1120f862d0f599e17535a87ec",
- "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec",
- "shasum": ""
- },
- "require": {
- "php": ">=8.2",
- "symfony/deprecation-contracts": "^2.5|^3.0",
- "symfony/polyfill-ctype": "^1.8"
- },
- "conflict": {
- "symfony/console": "<6.4"
- },
- "require-dev": {
- "symfony/console": "^6.4|^7.0"
- },
- "bin": [
- "Resources/bin/yaml-lint"
- ],
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Yaml\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Loads and dumps YAML files",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/yaml/tree/v7.2.3"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-01-07T12:55:42+00:00"
- },
{
"name": "tijsverkoyen/css-to-inline-styles",
"version": "v2.3.0",
@@ -11261,64 +5569,6 @@
},
"time": "2024-12-21T16:25:41+00:00"
},
- {
- "name": "visus/cuid2",
- "version": "4.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/visus-io/php-cuid2.git",
- "reference": "17c9b3098d556bb2556a084c948211333cc19c79"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/visus-io/php-cuid2/zipball/17c9b3098d556bb2556a084c948211333cc19c79",
- "reference": "17c9b3098d556bb2556a084c948211333cc19c79",
- "shasum": ""
- },
- "require": {
- "php": "^8.1"
- },
- "require-dev": {
- "ergebnis/composer-normalize": "^2.29",
- "ext-ctype": "*",
- "phpstan/phpstan": "^1.9",
- "phpunit/phpunit": "^10.0",
- "squizlabs/php_codesniffer": "^3.7",
- "vimeo/psalm": "^5.4"
- },
- "suggest": {
- "ext-gmp": "*"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/compat.php"
- ],
- "psr-4": {
- "Visus\\Cuid2\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Alan Brault",
- "email": "alan.brault@visus.io"
- }
- ],
- "description": "A PHP library for generating collision-resistant ids (CUIDs).",
- "keywords": [
- "cuid",
- "identifier"
- ],
- "support": {
- "issues": "https://github.com/visus-io/php-cuid2/issues",
- "source": "https://github.com/visus-io/php-cuid2/tree/4.1.0"
- },
- "time": "2024-05-14T13:23:35+00:00"
- },
{
"name": "vlucas/phpdotenv",
"version": "v5.6.1",
@@ -11534,629 +5784,9 @@
"source": "https://github.com/webmozarts/assert/tree/1.11.0"
},
"time": "2022-06-03T18:03:27+00:00"
- },
- {
- "name": "yosymfony/parser-utils",
- "version": "v2.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/yosymfony/parser-utils.git",
- "reference": "00bec9a12722b21f2baf7f9db35f127e90c162c9"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/yosymfony/parser-utils/zipball/00bec9a12722b21f2baf7f9db35f127e90c162c9",
- "reference": "00bec9a12722b21f2baf7f9db35f127e90c162c9",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^6"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Yosymfony\\ParserUtils\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Victor Puertas",
- "email": "vpgugr@gmail.com",
- "homepage": "http://yosymfony.com"
- }
- ],
- "description": "Parser utilities",
- "homepage": "http://github.com/yosymfony/toml",
- "keywords": [
- "lexer",
- "parser"
- ],
- "support": {
- "issues": "https://github.com/yosymfony/parser-utils/issues",
- "source": "https://github.com/yosymfony/parser-utils/tree/master"
- },
- "time": "2018-06-29T15:31:11+00:00"
- },
- {
- "name": "yosymfony/toml",
- "version": "v1.0.4",
- "source": {
- "type": "git",
- "url": "https://github.com/yosymfony/toml.git",
- "reference": "bdab92ad920d0e36810a3a3e4a998d23f3498f8e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/yosymfony/toml/zipball/bdab92ad920d0e36810a3a3e4a998d23f3498f8e",
- "reference": "bdab92ad920d0e36810a3a3e4a998d23f3498f8e",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1",
- "yosymfony/parser-utils": "^2.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^7.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Yosymfony\\Toml\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Victor Puertas",
- "email": "vpgugr@gmail.com",
- "homepage": "http://yosymfony.com"
- }
- ],
- "description": "A PHP parser for TOML compatible with specification 0.4.0",
- "homepage": "http://github.com/yosymfony/toml",
- "keywords": [
- "mojombo",
- "parser",
- "toml"
- ],
- "support": {
- "issues": "https://github.com/yosymfony/toml/issues",
- "source": "https://github.com/yosymfony/toml/tree/master"
- },
- "time": "2018-08-08T15:08:14+00:00"
- },
- {
- "name": "zbateson/mail-mime-parser",
- "version": "3.0.3",
- "source": {
- "type": "git",
- "url": "https://github.com/zbateson/mail-mime-parser.git",
- "reference": "e0d4423fe27850c9dd301190767dbc421acc2f19"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/zbateson/mail-mime-parser/zipball/e0d4423fe27850c9dd301190767dbc421acc2f19",
- "reference": "e0d4423fe27850c9dd301190767dbc421acc2f19",
- "shasum": ""
- },
- "require": {
- "guzzlehttp/psr7": "^2.5",
- "php": ">=8.0",
- "php-di/php-di": "^6.0|^7.0",
- "psr/log": "^1|^2|^3",
- "zbateson/mb-wrapper": "^2.0",
- "zbateson/stream-decorators": "^2.1"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "*",
- "monolog/monolog": "^2|^3",
- "phpstan/phpstan": "*",
- "phpunit/phpunit": "^9.6"
- },
- "suggest": {
- "ext-iconv": "For best support/performance",
- "ext-mbstring": "For best support/performance"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "ZBateson\\MailMimeParser\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-2-Clause"
- ],
- "authors": [
- {
- "name": "Zaahid Bateson"
- },
- {
- "name": "Contributors",
- "homepage": "https://github.com/zbateson/mail-mime-parser/graphs/contributors"
- }
- ],
- "description": "MIME email message parser",
- "homepage": "https://mail-mime-parser.org",
- "keywords": [
- "MimeMailParser",
- "email",
- "mail",
- "mailparse",
- "mime",
- "mimeparse",
- "parser",
- "php-imap"
- ],
- "support": {
- "docs": "https://mail-mime-parser.org/#usage-guide",
- "issues": "https://github.com/zbateson/mail-mime-parser/issues",
- "source": "https://github.com/zbateson/mail-mime-parser"
- },
- "funding": [
- {
- "url": "https://github.com/zbateson",
- "type": "github"
- }
- ],
- "time": "2024-08-10T18:44:09+00:00"
- },
- {
- "name": "zbateson/mb-wrapper",
- "version": "2.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/zbateson/mb-wrapper.git",
- "reference": "50a14c0c9537f978a61cde9fdc192a0267cc9cff"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/zbateson/mb-wrapper/zipball/50a14c0c9537f978a61cde9fdc192a0267cc9cff",
- "reference": "50a14c0c9537f978a61cde9fdc192a0267cc9cff",
- "shasum": ""
- },
- "require": {
- "php": ">=8.0",
- "symfony/polyfill-iconv": "^1.9",
- "symfony/polyfill-mbstring": "^1.9"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "*",
- "phpstan/phpstan": "*",
- "phpunit/phpunit": "^9.6|^10.0"
- },
- "suggest": {
- "ext-iconv": "For best support/performance",
- "ext-mbstring": "For best support/performance"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "ZBateson\\MbWrapper\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-2-Clause"
- ],
- "authors": [
- {
- "name": "Zaahid Bateson"
- }
- ],
- "description": "Wrapper for mbstring with fallback to iconv for encoding conversion and string manipulation",
- "keywords": [
- "charset",
- "encoding",
- "http",
- "iconv",
- "mail",
- "mb",
- "mb_convert_encoding",
- "mbstring",
- "mime",
- "multibyte",
- "string"
- ],
- "support": {
- "issues": "https://github.com/zbateson/mb-wrapper/issues",
- "source": "https://github.com/zbateson/mb-wrapper/tree/2.0.1"
- },
- "funding": [
- {
- "url": "https://github.com/zbateson",
- "type": "github"
- }
- ],
- "time": "2024-12-20T22:05:33+00:00"
- },
- {
- "name": "zbateson/stream-decorators",
- "version": "2.1.1",
- "source": {
- "type": "git",
- "url": "https://github.com/zbateson/stream-decorators.git",
- "reference": "32a2a62fb0f26313395c996ebd658d33c3f9c4e5"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/32a2a62fb0f26313395c996ebd658d33c3f9c4e5",
- "reference": "32a2a62fb0f26313395c996ebd658d33c3f9c4e5",
- "shasum": ""
- },
- "require": {
- "guzzlehttp/psr7": "^2.5",
- "php": ">=8.0",
- "zbateson/mb-wrapper": "^2.0"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "*",
- "phpstan/phpstan": "*",
- "phpunit/phpunit": "^9.6|^10.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "ZBateson\\StreamDecorators\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-2-Clause"
- ],
- "authors": [
- {
- "name": "Zaahid Bateson"
- }
- ],
- "description": "PHP psr7 stream decorators for mime message part streams",
- "keywords": [
- "base64",
- "charset",
- "decorators",
- "mail",
- "mime",
- "psr7",
- "quoted-printable",
- "stream",
- "uuencode"
- ],
- "support": {
- "issues": "https://github.com/zbateson/stream-decorators/issues",
- "source": "https://github.com/zbateson/stream-decorators/tree/2.1.1"
- },
- "funding": [
- {
- "url": "https://github.com/zbateson",
- "type": "github"
- }
- ],
- "time": "2024-04-29T21:42:39+00:00"
- },
- {
- "name": "zircote/swagger-php",
- "version": "5.0.5",
- "source": {
- "type": "git",
- "url": "https://github.com/zircote/swagger-php.git",
- "reference": "2eb4005840058d8844a0bcc14403932331331068"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/zircote/swagger-php/zipball/2eb4005840058d8844a0bcc14403932331331068",
- "reference": "2eb4005840058d8844a0bcc14403932331331068",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "nikic/php-parser": "^4.19 || ^5.0",
- "php": ">=7.4",
- "psr/log": "^1.1 || ^2.0 || ^3.0",
- "symfony/deprecation-contracts": "^2 || ^3",
- "symfony/finder": "^5.0 || ^6.0 || ^7.0",
- "symfony/yaml": "^5.0 || ^6.0 || ^7.0"
- },
- "conflict": {
- "symfony/process": ">=6, <6.4.14"
- },
- "require-dev": {
- "composer/package-versions-deprecated": "^1.11",
- "doctrine/annotations": "^2.0",
- "friendsofphp/php-cs-fixer": "^3.62.0",
- "phpstan/phpstan": "^1.6 || ^2.0",
- "phpunit/phpunit": "^9.0",
- "rector/rector": "^1.0 || ^2.0",
- "vimeo/psalm": "^4.30 || ^5.0"
- },
- "suggest": {
- "doctrine/annotations": "^2.0"
- },
- "bin": [
- "bin/openapi"
- ],
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "OpenApi\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "Apache-2.0"
- ],
- "authors": [
- {
- "name": "Robert Allen",
- "email": "zircote@gmail.com"
- },
- {
- "name": "Bob Fanger",
- "email": "bfanger@gmail.com",
- "homepage": "https://bfanger.nl"
- },
- {
- "name": "Martin Rademacher",
- "email": "mano@radebatz.net",
- "homepage": "https://radebatz.net"
- }
- ],
- "description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations",
- "homepage": "https://github.com/zircote/swagger-php/",
- "keywords": [
- "api",
- "json",
- "rest",
- "service discovery"
- ],
- "support": {
- "issues": "https://github.com/zircote/swagger-php/issues",
- "source": "https://github.com/zircote/swagger-php/tree/5.0.5"
- },
- "time": "2025-02-24T00:48:00+00:00"
}
],
"packages-dev": [
- {
- "name": "barryvdh/laravel-debugbar",
- "version": "v3.15.1",
- "source": {
- "type": "git",
- "url": "https://github.com/barryvdh/laravel-debugbar.git",
- "reference": "62b222166a9505926d54fadf7663bb4a26ed9014"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/62b222166a9505926d54fadf7663bb4a26ed9014",
- "reference": "62b222166a9505926d54fadf7663bb4a26ed9014",
- "shasum": ""
- },
- "require": {
- "illuminate/routing": "^9|^10|^11|^12",
- "illuminate/session": "^9|^10|^11|^12",
- "illuminate/support": "^9|^10|^11|^12",
- "php": "^8.1",
- "php-debugbar/php-debugbar": "~2.1.1",
- "symfony/finder": "^6|^7"
- },
- "conflict": {
- "maximebf/debugbar": "*"
- },
- "require-dev": {
- "mockery/mockery": "^1.3.3",
- "orchestra/testbench-dusk": "^7|^8|^9|^10",
- "phpunit/phpunit": "^9.5.10|^10|^11",
- "squizlabs/php_codesniffer": "^3.5"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "aliases": {
- "Debugbar": "Barryvdh\\Debugbar\\Facades\\Debugbar"
- },
- "providers": [
- "Barryvdh\\Debugbar\\ServiceProvider"
- ]
- },
- "branch-alias": {
- "dev-master": "3.15-dev"
- }
- },
- "autoload": {
- "files": [
- "src/helpers.php"
- ],
- "psr-4": {
- "Barryvdh\\Debugbar\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Barry vd. Heuvel",
- "email": "barryvdh@gmail.com"
- }
- ],
- "description": "PHP Debugbar integration for Laravel",
- "keywords": [
- "debug",
- "debugbar",
- "dev",
- "laravel",
- "profiler",
- "webprofiler"
- ],
- "support": {
- "issues": "https://github.com/barryvdh/laravel-debugbar/issues",
- "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.15.1"
- },
- "funding": [
- {
- "url": "https://fruitcake.nl",
- "type": "custom"
- },
- {
- "url": "https://github.com/barryvdh",
- "type": "github"
- }
- ],
- "time": "2025-02-24T10:48:28+00:00"
- },
- {
- "name": "brianium/paratest",
- "version": "v7.7.0",
- "source": {
- "type": "git",
- "url": "https://github.com/paratestphp/paratest.git",
- "reference": "4fb3f73bc5a4c3146bac2850af7dc72435a32daf"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/paratestphp/paratest/zipball/4fb3f73bc5a4c3146bac2850af7dc72435a32daf",
- "reference": "4fb3f73bc5a4c3146bac2850af7dc72435a32daf",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "ext-pcre": "*",
- "ext-reflection": "*",
- "ext-simplexml": "*",
- "fidry/cpu-core-counter": "^1.2.0",
- "jean85/pretty-package-versions": "^2.1.0",
- "php": "~8.2.0 || ~8.3.0 || ~8.4.0",
- "phpunit/php-code-coverage": "^11.0.8",
- "phpunit/php-file-iterator": "^5.1.0",
- "phpunit/php-timer": "^7.0.1",
- "phpunit/phpunit": "^11.5.1",
- "sebastian/environment": "^7.2.0",
- "symfony/console": "^6.4.14 || ^7.2.1",
- "symfony/process": "^6.4.14 || ^7.2.0"
- },
- "require-dev": {
- "doctrine/coding-standard": "^12.0.0",
- "ext-pcov": "*",
- "ext-posix": "*",
- "phpstan/phpstan": "^2.0.3",
- "phpstan/phpstan-deprecation-rules": "^2.0.1",
- "phpstan/phpstan-phpunit": "^2.0.1",
- "phpstan/phpstan-strict-rules": "^2",
- "squizlabs/php_codesniffer": "^3.11.1",
- "symfony/filesystem": "^6.4.13 || ^7.2.0"
- },
- "bin": [
- "bin/paratest",
- "bin/paratest_for_phpstorm"
- ],
- "type": "library",
- "autoload": {
- "psr-4": {
- "ParaTest\\": [
- "src/"
- ]
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Brian Scaturro",
- "email": "scaturrob@gmail.com",
- "role": "Developer"
- },
- {
- "name": "Filippo Tessarotto",
- "email": "zoeslam@gmail.com",
- "role": "Developer"
- }
- ],
- "description": "Parallel testing for PHP",
- "homepage": "https://github.com/paratestphp/paratest",
- "keywords": [
- "concurrent",
- "parallel",
- "phpunit",
- "testing"
- ],
- "support": {
- "issues": "https://github.com/paratestphp/paratest/issues",
- "source": "https://github.com/paratestphp/paratest/tree/v7.7.0"
- },
- "funding": [
- {
- "url": "https://github.com/sponsors/Slamdunk",
- "type": "github"
- },
- {
- "url": "https://paypal.me/filippotessarotto",
- "type": "paypal"
- }
- ],
- "time": "2024-12-11T14:50:44+00:00"
- },
- {
- "name": "driftingly/rector-laravel",
- "version": "2.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/driftingly/rector-laravel.git",
- "reference": "f0e3a9e2c92ff760730d1af34fbdc43f51f3b868"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/driftingly/rector-laravel/zipball/f0e3a9e2c92ff760730d1af34fbdc43f51f3b868",
- "reference": "f0e3a9e2c92ff760730d1af34fbdc43f51f3b868",
- "shasum": ""
- },
- "require": {
- "php": "^7.2 || ^8.0",
- "rector/rector": "^2.0"
- },
- "type": "rector-extension",
- "autoload": {
- "psr-4": {
- "RectorLaravel\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Rector upgrades rules for Laravel Framework",
- "support": {
- "issues": "https://github.com/driftingly/rector-laravel/issues",
- "source": "https://github.com/driftingly/rector-laravel/tree/2.0.2"
- },
- "time": "2025-01-17T18:07:03+00:00"
- },
{
"name": "fakerphp/faker",
"version": "v1.24.1",
@@ -12220,79 +5850,18 @@
},
"time": "2024-11-21T13:46:39+00:00"
},
- {
- "name": "fidry/cpu-core-counter",
- "version": "1.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/theofidry/cpu-core-counter.git",
- "reference": "8520451a140d3f46ac33042715115e290cf5785f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f",
- "reference": "8520451a140d3f46ac33042715115e290cf5785f",
- "shasum": ""
- },
- "require": {
- "php": "^7.2 || ^8.0"
- },
- "require-dev": {
- "fidry/makefile": "^0.2.0",
- "fidry/php-cs-fixer-config": "^1.1.2",
- "phpstan/extension-installer": "^1.2.0",
- "phpstan/phpstan": "^1.9.2",
- "phpstan/phpstan-deprecation-rules": "^1.0.0",
- "phpstan/phpstan-phpunit": "^1.2.2",
- "phpstan/phpstan-strict-rules": "^1.4.4",
- "phpunit/phpunit": "^8.5.31 || ^9.5.26",
- "webmozarts/strict-phpunit": "^7.5"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Fidry\\CpuCoreCounter\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Théo FIDRY",
- "email": "theo.fidry@gmail.com"
- }
- ],
- "description": "Tiny utility to get the number of CPU cores.",
- "keywords": [
- "CPU",
- "core"
- ],
- "support": {
- "issues": "https://github.com/theofidry/cpu-core-counter/issues",
- "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0"
- },
- "funding": [
- {
- "url": "https://github.com/theofidry",
- "type": "github"
- }
- ],
- "time": "2024-08-06T10:04:20+00:00"
- },
{
"name": "filp/whoops",
- "version": "2.17.0",
+ "version": "2.18.0",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
- "reference": "075bc0c26631110584175de6523ab3f1652eb28e"
+ "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/filp/whoops/zipball/075bc0c26631110584175de6523ab3f1652eb28e",
- "reference": "075bc0c26631110584175de6523ab3f1652eb28e",
+ "url": "https://api.github.com/repos/filp/whoops/zipball/a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
+ "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
"shasum": ""
},
"require": {
@@ -12342,7 +5911,7 @@
],
"support": {
"issues": "https://github.com/filp/whoops/issues",
- "source": "https://github.com/filp/whoops/tree/2.17.0"
+ "source": "https://github.com/filp/whoops/tree/2.18.0"
},
"funding": [
{
@@ -12350,7 +5919,7 @@
"type": "github"
}
],
- "time": "2025-01-25T12:00:00+00:00"
+ "time": "2025-03-15T12:00:00+00:00"
},
{
"name": "hamcrest/hamcrest-php",
@@ -12404,55 +5973,53 @@
"time": "2020-07-09T08:09:16+00:00"
},
{
- "name": "laravel/dusk",
- "version": "v8.3.1",
+ "name": "laravel/pail",
+ "version": "v1.2.2",
"source": {
"type": "git",
- "url": "https://github.com/laravel/dusk.git",
- "reference": "541ca2d2004ae4ed04446b9e712b68180fca158c"
+ "url": "https://github.com/laravel/pail.git",
+ "reference": "f31f4980f52be17c4667f3eafe034e6826787db2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/dusk/zipball/541ca2d2004ae4ed04446b9e712b68180fca158c",
- "reference": "541ca2d2004ae4ed04446b9e712b68180fca158c",
+ "url": "https://api.github.com/repos/laravel/pail/zipball/f31f4980f52be17c4667f3eafe034e6826787db2",
+ "reference": "f31f4980f52be17c4667f3eafe034e6826787db2",
"shasum": ""
},
"require": {
- "ext-json": "*",
- "ext-zip": "*",
- "guzzlehttp/guzzle": "^7.5",
- "illuminate/console": "^10.0|^11.0|^12.0",
- "illuminate/support": "^10.0|^11.0|^12.0",
- "php": "^8.1",
- "php-webdriver/webdriver": "^1.15.2",
- "symfony/console": "^6.2|^7.0",
- "symfony/finder": "^6.2|^7.0",
- "symfony/process": "^6.2|^7.0",
- "vlucas/phpdotenv": "^5.2"
+ "ext-mbstring": "*",
+ "illuminate/console": "^10.24|^11.0|^12.0",
+ "illuminate/contracts": "^10.24|^11.0|^12.0",
+ "illuminate/log": "^10.24|^11.0|^12.0",
+ "illuminate/process": "^10.24|^11.0|^12.0",
+ "illuminate/support": "^10.24|^11.0|^12.0",
+ "nunomaduro/termwind": "^1.15|^2.0",
+ "php": "^8.2",
+ "symfony/console": "^6.0|^7.0"
},
"require-dev": {
- "laravel/framework": "^10.0|^11.0|^12.0",
- "mockery/mockery": "^1.6",
- "orchestra/testbench-core": "^8.19|^9.0|^10.0",
+ "laravel/framework": "^10.24|^11.0|^12.0",
+ "laravel/pint": "^1.13",
+ "orchestra/testbench-core": "^8.13|^9.0|^10.0",
+ "pestphp/pest": "^2.20|^3.0",
+ "pestphp/pest-plugin-type-coverage": "^2.3|^3.0",
"phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^10.1|^11.0|^12.0.1",
- "psy/psysh": "^0.11.12|^0.12",
- "symfony/yaml": "^6.2|^7.0"
- },
- "suggest": {
- "ext-pcntl": "Used to gracefully terminate Dusk when tests are running."
+ "symfony/var-dumper": "^6.3|^7.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
- "Laravel\\Dusk\\DuskServiceProvider"
+ "Laravel\\Pail\\PailServiceProvider"
]
+ },
+ "branch-alias": {
+ "dev-main": "1.x-dev"
}
},
"autoload": {
"psr-4": {
- "Laravel\\Dusk\\": "src/"
+ "Laravel\\Pail\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -12463,32 +6030,38 @@
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
+ },
+ {
+ "name": "Nuno Maduro",
+ "email": "enunomaduro@gmail.com"
}
],
- "description": "Laravel Dusk provides simple end-to-end testing and browser automation.",
+ "description": "Easily delve into your Laravel application's log files directly from the command line.",
+ "homepage": "https://github.com/laravel/pail",
"keywords": [
"laravel",
- "testing",
- "webdriver"
+ "logs",
+ "php",
+ "tail"
],
"support": {
- "issues": "https://github.com/laravel/dusk/issues",
- "source": "https://github.com/laravel/dusk/tree/v8.3.1"
+ "issues": "https://github.com/laravel/pail/issues",
+ "source": "https://github.com/laravel/pail"
},
- "time": "2025-02-12T16:14:51+00:00"
+ "time": "2025-01-28T15:15:15+00:00"
},
{
"name": "laravel/pint",
- "version": "v1.21.0",
+ "version": "v1.21.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "531fa0871fbde719c51b12afa3a443b8f4e4b425"
+ "reference": "370772e7d9e9da087678a0edf2b11b6960e40558"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/531fa0871fbde719c51b12afa3a443b8f4e4b425",
- "reference": "531fa0871fbde719c51b12afa3a443b8f4e4b425",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/370772e7d9e9da087678a0edf2b11b6960e40558",
+ "reference": "370772e7d9e9da087678a0edf2b11b6960e40558",
"shasum": ""
},
"require": {
@@ -12499,9 +6072,9 @@
"php": "^8.2.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.68.5",
- "illuminate/view": "^11.42.0",
- "larastan/larastan": "^3.0.4",
+ "friendsofphp/php-cs-fixer": "^3.72.0",
+ "illuminate/view": "^11.44.2",
+ "larastan/larastan": "^3.2.0",
"laravel-zero/framework": "^11.36.1",
"mockery/mockery": "^1.6.12",
"nunomaduro/termwind": "^2.3",
@@ -12541,49 +6114,48 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2025-02-18T03:18:57+00:00"
+ "time": "2025-03-14T22:31:42+00:00"
},
{
- "name": "laravel/telescope",
- "version": "v5.5.0",
+ "name": "laravel/sail",
+ "version": "v1.41.0",
"source": {
"type": "git",
- "url": "https://github.com/laravel/telescope.git",
- "reference": "2594b20b946155ba767002d8af971e33e1095637"
+ "url": "https://github.com/laravel/sail.git",
+ "reference": "fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/telescope/zipball/2594b20b946155ba767002d8af971e33e1095637",
- "reference": "2594b20b946155ba767002d8af971e33e1095637",
+ "url": "https://api.github.com/repos/laravel/sail/zipball/fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec",
+ "reference": "fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec",
"shasum": ""
},
"require": {
- "ext-json": "*",
- "laravel/framework": "^8.37|^9.0|^10.0|^11.0|^12.0",
+ "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0",
+ "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0",
+ "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0",
"php": "^8.0",
- "symfony/console": "^5.3|^6.0|^7.0",
- "symfony/var-dumper": "^5.0|^6.0|^7.0"
+ "symfony/console": "^6.0|^7.0",
+ "symfony/yaml": "^6.0|^7.0"
},
"require-dev": {
- "ext-gd": "*",
- "guzzlehttp/guzzle": "^6.0|^7.0",
- "laravel/octane": "^1.4|^2.0|dev-develop",
- "orchestra/testbench": "^6.40|^7.37|^8.17|^9.0|^10.0",
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^9.0|^10.5|^11.5"
+ "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
+ "phpstan/phpstan": "^1.10"
},
+ "bin": [
+ "bin/sail"
+ ],
"type": "library",
"extra": {
"laravel": {
"providers": [
- "Laravel\\Telescope\\TelescopeServiceProvider"
+ "Laravel\\Sail\\SailServiceProvider"
]
}
},
"autoload": {
"psr-4": {
- "Laravel\\Telescope\\": "src/",
- "Laravel\\Telescope\\Database\\Factories\\": "database/factories/"
+ "Laravel\\Sail\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -12594,23 +6166,18 @@
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
- },
- {
- "name": "Mohamed Said",
- "email": "mohamed@laravel.com"
}
],
- "description": "An elegant debug assistant for the Laravel framework.",
+ "description": "Docker files for running a basic Laravel application.",
"keywords": [
- "debugging",
- "laravel",
- "monitoring"
+ "docker",
+ "laravel"
],
"support": {
- "issues": "https://github.com/laravel/telescope/issues",
- "source": "https://github.com/laravel/telescope/tree/v5.5.0"
+ "issues": "https://github.com/laravel/sail/issues",
+ "source": "https://github.com/laravel/sail"
},
- "time": "2025-02-11T15:01:27+00:00"
+ "time": "2025-01-24T15:45:36+00:00"
},
{
"name": "mockery/mockery",
@@ -12757,20 +6324,20 @@
},
{
"name": "nunomaduro/collision",
- "version": "v8.6.1",
+ "version": "v8.7.0",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/collision.git",
- "reference": "86f003c132143d5a2ab214e19933946409e0cae7"
+ "reference": "586cb8181a257a2152b6a855ca8d9598878a1a26"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nunomaduro/collision/zipball/86f003c132143d5a2ab214e19933946409e0cae7",
- "reference": "86f003c132143d5a2ab214e19933946409e0cae7",
+ "url": "https://api.github.com/repos/nunomaduro/collision/zipball/586cb8181a257a2152b6a855ca8d9598878a1a26",
+ "reference": "586cb8181a257a2152b6a855ca8d9598878a1a26",
"shasum": ""
},
"require": {
- "filp/whoops": "^2.16.0",
+ "filp/whoops": "^2.17.0",
"nunomaduro/termwind": "^2.3.0",
"php": "^8.2.0",
"symfony/console": "^7.2.1"
@@ -12780,14 +6347,14 @@
"phpunit/phpunit": "<11.5.3 || >=12.0.0"
},
"require-dev": {
- "larastan/larastan": "^2.9.12",
- "laravel/framework": "^11.39.1",
- "laravel/pint": "^1.20.0",
- "laravel/sail": "^1.40.0",
- "laravel/sanctum": "^4.0.7",
- "laravel/tinker": "^2.10.0",
- "orchestra/testbench-core": "^9.9.2",
- "pestphp/pest": "^3.7.3",
+ "larastan/larastan": "^2.10.0",
+ "laravel/framework": "^11.44.2",
+ "laravel/pint": "^1.21.2",
+ "laravel/sail": "^1.41.0",
+ "laravel/sanctum": "^4.0.8",
+ "laravel/tinker": "^2.10.1",
+ "orchestra/testbench-core": "^9.12.0",
+ "pestphp/pest": "^3.7.4",
"sebastian/environment": "^6.1.0 || ^7.2.0"
},
"type": "library",
@@ -12851,331 +6418,7 @@
"type": "patreon"
}
],
- "time": "2025-01-23T13:41:43+00:00"
- },
- {
- "name": "pestphp/pest",
- "version": "v3.7.4",
- "source": {
- "type": "git",
- "url": "https://github.com/pestphp/pest.git",
- "reference": "4a987d3d5c4e3ba36c76fecbf56113baac2d1b2b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/pestphp/pest/zipball/4a987d3d5c4e3ba36c76fecbf56113baac2d1b2b",
- "reference": "4a987d3d5c4e3ba36c76fecbf56113baac2d1b2b",
- "shasum": ""
- },
- "require": {
- "brianium/paratest": "^7.7.0",
- "nunomaduro/collision": "^8.6.1",
- "nunomaduro/termwind": "^2.3.0",
- "pestphp/pest-plugin": "^3.0.0",
- "pestphp/pest-plugin-arch": "^3.0.0",
- "pestphp/pest-plugin-mutate": "^3.0.5",
- "php": "^8.2.0",
- "phpunit/phpunit": "^11.5.3"
- },
- "conflict": {
- "filp/whoops": "<2.16.0",
- "phpunit/phpunit": ">11.5.3",
- "sebastian/exporter": "<6.0.0",
- "webmozart/assert": "<1.11.0"
- },
- "require-dev": {
- "pestphp/pest-dev-tools": "^3.3.0",
- "pestphp/pest-plugin-type-coverage": "^3.2.3",
- "symfony/process": "^7.2.0"
- },
- "bin": [
- "bin/pest"
- ],
- "type": "library",
- "extra": {
- "pest": {
- "plugins": [
- "Pest\\Mutate\\Plugins\\Mutate",
- "Pest\\Plugins\\Configuration",
- "Pest\\Plugins\\Bail",
- "Pest\\Plugins\\Cache",
- "Pest\\Plugins\\Coverage",
- "Pest\\Plugins\\Init",
- "Pest\\Plugins\\Environment",
- "Pest\\Plugins\\Help",
- "Pest\\Plugins\\Memory",
- "Pest\\Plugins\\Only",
- "Pest\\Plugins\\Printer",
- "Pest\\Plugins\\ProcessIsolation",
- "Pest\\Plugins\\Profile",
- "Pest\\Plugins\\Retry",
- "Pest\\Plugins\\Snapshot",
- "Pest\\Plugins\\Verbose",
- "Pest\\Plugins\\Version",
- "Pest\\Plugins\\Parallel"
- ]
- },
- "phpstan": {
- "includes": [
- "extension.neon"
- ]
- }
- },
- "autoload": {
- "files": [
- "src/Functions.php",
- "src/Pest.php"
- ],
- "psr-4": {
- "Pest\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nuno Maduro",
- "email": "enunomaduro@gmail.com"
- }
- ],
- "description": "The elegant PHP Testing Framework.",
- "keywords": [
- "framework",
- "pest",
- "php",
- "test",
- "testing",
- "unit"
- ],
- "support": {
- "issues": "https://github.com/pestphp/pest/issues",
- "source": "https://github.com/pestphp/pest/tree/v3.7.4"
- },
- "funding": [
- {
- "url": "https://www.paypal.com/paypalme/enunomaduro",
- "type": "custom"
- },
- {
- "url": "https://github.com/nunomaduro",
- "type": "github"
- }
- ],
- "time": "2025-01-23T14:03:29+00:00"
- },
- {
- "name": "pestphp/pest-plugin",
- "version": "v3.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/pestphp/pest-plugin.git",
- "reference": "e79b26c65bc11c41093b10150c1341cc5cdbea83"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/pestphp/pest-plugin/zipball/e79b26c65bc11c41093b10150c1341cc5cdbea83",
- "reference": "e79b26c65bc11c41093b10150c1341cc5cdbea83",
- "shasum": ""
- },
- "require": {
- "composer-plugin-api": "^2.0.0",
- "composer-runtime-api": "^2.2.2",
- "php": "^8.2"
- },
- "conflict": {
- "pestphp/pest": "<3.0.0"
- },
- "require-dev": {
- "composer/composer": "^2.7.9",
- "pestphp/pest": "^3.0.0",
- "pestphp/pest-dev-tools": "^3.0.0"
- },
- "type": "composer-plugin",
- "extra": {
- "class": "Pest\\Plugin\\Manager"
- },
- "autoload": {
- "psr-4": {
- "Pest\\Plugin\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "The Pest plugin manager",
- "keywords": [
- "framework",
- "manager",
- "pest",
- "php",
- "plugin",
- "test",
- "testing",
- "unit"
- ],
- "support": {
- "source": "https://github.com/pestphp/pest-plugin/tree/v3.0.0"
- },
- "funding": [
- {
- "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L",
- "type": "custom"
- },
- {
- "url": "https://github.com/nunomaduro",
- "type": "github"
- },
- {
- "url": "https://www.patreon.com/nunomaduro",
- "type": "patreon"
- }
- ],
- "time": "2024-09-08T23:21:41+00:00"
- },
- {
- "name": "pestphp/pest-plugin-arch",
- "version": "v3.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/pestphp/pest-plugin-arch.git",
- "reference": "0a27e55a270cfe73d8cb70551b91002ee2cb64b0"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/pestphp/pest-plugin-arch/zipball/0a27e55a270cfe73d8cb70551b91002ee2cb64b0",
- "reference": "0a27e55a270cfe73d8cb70551b91002ee2cb64b0",
- "shasum": ""
- },
- "require": {
- "pestphp/pest-plugin": "^3.0.0",
- "php": "^8.2",
- "ta-tikoma/phpunit-architecture-test": "^0.8.4"
- },
- "require-dev": {
- "pestphp/pest": "^3.0.0",
- "pestphp/pest-dev-tools": "^3.0.0"
- },
- "type": "library",
- "extra": {
- "pest": {
- "plugins": [
- "Pest\\Arch\\Plugin"
- ]
- }
- },
- "autoload": {
- "files": [
- "src/Autoload.php"
- ],
- "psr-4": {
- "Pest\\Arch\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "The Arch plugin for Pest PHP.",
- "keywords": [
- "arch",
- "architecture",
- "framework",
- "pest",
- "php",
- "plugin",
- "test",
- "testing",
- "unit"
- ],
- "support": {
- "source": "https://github.com/pestphp/pest-plugin-arch/tree/v3.0.0"
- },
- "funding": [
- {
- "url": "https://www.paypal.com/paypalme/enunomaduro",
- "type": "custom"
- },
- {
- "url": "https://github.com/nunomaduro",
- "type": "github"
- }
- ],
- "time": "2024-09-08T23:23:55+00:00"
- },
- {
- "name": "pestphp/pest-plugin-mutate",
- "version": "v3.0.5",
- "source": {
- "type": "git",
- "url": "https://github.com/pestphp/pest-plugin-mutate.git",
- "reference": "e10dbdc98c9e2f3890095b4fe2144f63a5717e08"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/pestphp/pest-plugin-mutate/zipball/e10dbdc98c9e2f3890095b4fe2144f63a5717e08",
- "reference": "e10dbdc98c9e2f3890095b4fe2144f63a5717e08",
- "shasum": ""
- },
- "require": {
- "nikic/php-parser": "^5.2.0",
- "pestphp/pest-plugin": "^3.0.0",
- "php": "^8.2",
- "psr/simple-cache": "^3.0.0"
- },
- "require-dev": {
- "pestphp/pest": "^3.0.8",
- "pestphp/pest-dev-tools": "^3.0.0",
- "pestphp/pest-plugin-type-coverage": "^3.0.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Pest\\Mutate\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Sandro Gehri",
- "email": "sandrogehri@gmail.com"
- }
- ],
- "description": "Mutates your code to find untested cases",
- "keywords": [
- "framework",
- "mutate",
- "mutation",
- "pest",
- "php",
- "plugin",
- "test",
- "testing",
- "unit"
- ],
- "support": {
- "source": "https://github.com/pestphp/pest-plugin-mutate/tree/v3.0.5"
- },
- "funding": [
- {
- "url": "https://www.paypal.com/paypalme/enunomaduro",
- "type": "custom"
- },
- {
- "url": "https://github.com/gehrisandro",
- "type": "github"
- },
- {
- "url": "https://github.com/nunomaduro",
- "type": "github"
- }
- ],
- "time": "2024-09-22T07:54:40+00:00"
+ "time": "2025-03-14T22:37:40+00:00"
},
{
"name": "phar-io/manifest",
@@ -13295,219 +6538,25 @@
},
"time": "2022-02-21T01:04:05+00:00"
},
- {
- "name": "php-debugbar/php-debugbar",
- "version": "v2.1.6",
- "source": {
- "type": "git",
- "url": "https://github.com/php-debugbar/php-debugbar.git",
- "reference": "16fa68da5617220594aa5e33fa9de415f94784a0"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/16fa68da5617220594aa5e33fa9de415f94784a0",
- "reference": "16fa68da5617220594aa5e33fa9de415f94784a0",
- "shasum": ""
- },
- "require": {
- "php": "^8",
- "psr/log": "^1|^2|^3",
- "symfony/var-dumper": "^4|^5|^6|^7"
- },
- "require-dev": {
- "dbrekelmans/bdi": "^1",
- "phpunit/phpunit": "^8|^9",
- "symfony/panther": "^1|^2.1",
- "twig/twig": "^1.38|^2.7|^3.0"
- },
- "suggest": {
- "kriswallsmith/assetic": "The best way to manage assets",
- "monolog/monolog": "Log using Monolog",
- "predis/predis": "Redis storage"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "DebugBar\\": "src/DebugBar/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Maxime Bouroumeau-Fuseau",
- "email": "maxime.bouroumeau@gmail.com",
- "homepage": "http://maximebf.com"
- },
- {
- "name": "Barry vd. Heuvel",
- "email": "barryvdh@gmail.com"
- }
- ],
- "description": "Debug bar in the browser for php application",
- "homepage": "https://github.com/php-debugbar/php-debugbar",
- "keywords": [
- "debug",
- "debug bar",
- "debugbar",
- "dev"
- ],
- "support": {
- "issues": "https://github.com/php-debugbar/php-debugbar/issues",
- "source": "https://github.com/php-debugbar/php-debugbar/tree/v2.1.6"
- },
- "time": "2025-02-21T17:47:03+00:00"
- },
- {
- "name": "php-webdriver/webdriver",
- "version": "1.15.2",
- "source": {
- "type": "git",
- "url": "https://github.com/php-webdriver/php-webdriver.git",
- "reference": "998e499b786805568deaf8cbf06f4044f05d91bf"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/998e499b786805568deaf8cbf06f4044f05d91bf",
- "reference": "998e499b786805568deaf8cbf06f4044f05d91bf",
- "shasum": ""
- },
- "require": {
- "ext-curl": "*",
- "ext-json": "*",
- "ext-zip": "*",
- "php": "^7.3 || ^8.0",
- "symfony/polyfill-mbstring": "^1.12",
- "symfony/process": "^5.0 || ^6.0 || ^7.0"
- },
- "replace": {
- "facebook/webdriver": "*"
- },
- "require-dev": {
- "ergebnis/composer-normalize": "^2.20.0",
- "ondram/ci-detector": "^4.0",
- "php-coveralls/php-coveralls": "^2.4",
- "php-mock/php-mock-phpunit": "^2.0",
- "php-parallel-lint/php-parallel-lint": "^1.2",
- "phpunit/phpunit": "^9.3",
- "squizlabs/php_codesniffer": "^3.5",
- "symfony/var-dumper": "^5.0 || ^6.0 || ^7.0"
- },
- "suggest": {
- "ext-SimpleXML": "For Firefox profile creation"
- },
- "type": "library",
- "autoload": {
- "files": [
- "lib/Exception/TimeoutException.php"
- ],
- "psr-4": {
- "Facebook\\WebDriver\\": "lib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.",
- "homepage": "https://github.com/php-webdriver/php-webdriver",
- "keywords": [
- "Chromedriver",
- "geckodriver",
- "php",
- "selenium",
- "webdriver"
- ],
- "support": {
- "issues": "https://github.com/php-webdriver/php-webdriver/issues",
- "source": "https://github.com/php-webdriver/php-webdriver/tree/1.15.2"
- },
- "time": "2024-11-21T15:12:59+00:00"
- },
- {
- "name": "phpstan/phpstan",
- "version": "2.1.6",
- "source": {
- "type": "git",
- "url": "https://github.com/phpstan/phpstan.git",
- "reference": "6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c",
- "reference": "6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c",
- "shasum": ""
- },
- "require": {
- "php": "^7.4|^8.0"
- },
- "conflict": {
- "phpstan/phpstan-shim": "*"
- },
- "bin": [
- "phpstan",
- "phpstan.phar"
- ],
- "type": "library",
- "autoload": {
- "files": [
- "bootstrap.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "PHPStan - PHP Static Analysis Tool",
- "keywords": [
- "dev",
- "static analysis"
- ],
- "support": {
- "docs": "https://phpstan.org/user-guide/getting-started",
- "forum": "https://github.com/phpstan/phpstan/discussions",
- "issues": "https://github.com/phpstan/phpstan/issues",
- "security": "https://github.com/phpstan/phpstan/security/policy",
- "source": "https://github.com/phpstan/phpstan-src"
- },
- "funding": [
- {
- "url": "https://github.com/ondrejmirtes",
- "type": "github"
- },
- {
- "url": "https://github.com/phpstan",
- "type": "github"
- }
- ],
- "time": "2025-02-19T15:46:42+00:00"
- },
{
"name": "phpunit/php-code-coverage",
- "version": "11.0.8",
+ "version": "11.0.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "418c59fd080954f8c4aa5631d9502ecda2387118"
+ "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/418c59fd080954f8c4aa5631d9502ecda2387118",
- "reference": "418c59fd080954f8c4aa5631d9502ecda2387118",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7",
+ "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
- "nikic/php-parser": "^5.3.1",
+ "nikic/php-parser": "^5.4.0",
"php": ">=8.2",
"phpunit/php-file-iterator": "^5.1.0",
"phpunit/php-text-template": "^4.0.1",
@@ -13519,7 +6568,7 @@
"theseer/tokenizer": "^1.2.3"
},
"require-dev": {
- "phpunit/phpunit": "^11.5.0"
+ "phpunit/phpunit": "^11.5.2"
},
"suggest": {
"ext-pcov": "PHP extension that provides line coverage",
@@ -13557,7 +6606,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.8"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.9"
},
"funding": [
{
@@ -13565,7 +6614,7 @@
"type": "github"
}
],
- "time": "2024-12-11T12:34:27+00:00"
+ "time": "2025-02-25T13:26:39+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -13814,16 +6863,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "11.5.3",
+ "version": "11.5.12",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "30e319e578a7b5da3543073e30002bf82042f701"
+ "reference": "d42785840519401ed2113292263795eb4c0f95da"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/30e319e578a7b5da3543073e30002bf82042f701",
- "reference": "30e319e578a7b5da3543073e30002bf82042f701",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d42785840519401ed2113292263795eb4c0f95da",
+ "reference": "d42785840519401ed2113292263795eb4c0f95da",
"shasum": ""
},
"require": {
@@ -13833,18 +6882,18 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.12.1",
+ "myclabs/deep-copy": "^1.13.0",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=8.2",
- "phpunit/php-code-coverage": "^11.0.8",
+ "phpunit/php-code-coverage": "^11.0.9",
"phpunit/php-file-iterator": "^5.1.0",
"phpunit/php-invoker": "^5.0.1",
"phpunit/php-text-template": "^4.0.1",
"phpunit/php-timer": "^7.0.1",
"sebastian/cli-parser": "^3.0.2",
"sebastian/code-unit": "^3.0.2",
- "sebastian/comparator": "^6.3.0",
+ "sebastian/comparator": "^6.3.1",
"sebastian/diff": "^6.0.2",
"sebastian/environment": "^7.2.0",
"sebastian/exporter": "^6.3.0",
@@ -13895,7 +6944,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.3"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.12"
},
"funding": [
{
@@ -13911,66 +6960,7 @@
"type": "tidelift"
}
],
- "time": "2025-01-13T09:36:00+00:00"
- },
- {
- "name": "rector/rector",
- "version": "2.0.9",
- "source": {
- "type": "git",
- "url": "https://github.com/rectorphp/rector.git",
- "reference": "4393230e478c0006795770fe74c223b5c64ed68c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/rectorphp/rector/zipball/4393230e478c0006795770fe74c223b5c64ed68c",
- "reference": "4393230e478c0006795770fe74c223b5c64ed68c",
- "shasum": ""
- },
- "require": {
- "php": "^7.4|^8.0",
- "phpstan/phpstan": "^2.1.3"
- },
- "conflict": {
- "rector/rector-doctrine": "*",
- "rector/rector-downgrade-php": "*",
- "rector/rector-phpunit": "*",
- "rector/rector-symfony": "*"
- },
- "suggest": {
- "ext-dom": "To manipulate phpunit.xml via the custom-rule command"
- },
- "bin": [
- "bin/rector"
- ],
- "type": "library",
- "autoload": {
- "files": [
- "bootstrap.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Instant Upgrade and Automated Refactoring of any PHP code",
- "keywords": [
- "automation",
- "dev",
- "migration",
- "refactoring"
- ],
- "support": {
- "issues": "https://github.com/rectorphp/rector/issues",
- "source": "https://github.com/rectorphp/rector/tree/2.0.9"
- },
- "funding": [
- {
- "url": "https://github.com/tomasvotruba",
- "type": "github"
- }
- ],
- "time": "2025-02-10T08:14:01+00:00"
+ "time": "2025-03-07T07:31:03+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -14144,16 +7134,16 @@
},
{
"name": "sebastian/comparator",
- "version": "6.3.0",
+ "version": "6.3.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115"
+ "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/d4e47a769525c4dd38cea90e5dcd435ddbbc7115",
- "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959",
+ "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959",
"shasum": ""
},
"require": {
@@ -14172,7 +7162,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "6.2-dev"
+ "dev-main": "6.3-dev"
}
},
"autoload": {
@@ -14212,7 +7202,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
- "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.0"
+ "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1"
},
"funding": [
{
@@ -14220,7 +7210,7 @@
"type": "github"
}
],
- "time": "2025-01-06T10:28:19+00:00"
+ "time": "2025-03-07T06:57:01+00:00"
},
{
"name": "sebastian/complexity",
@@ -14898,368 +7888,6 @@
],
"time": "2024-10-09T05:16:32+00:00"
},
- {
- "name": "serversideup/spin",
- "version": "v3.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/serversideup/spin.git",
- "reference": "f0e9c78dad8fd86db6030871a9f143fd6ab918e3"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/serversideup/spin/zipball/f0e9c78dad8fd86db6030871a9f143fd6ab918e3",
- "reference": "f0e9c78dad8fd86db6030871a9f143fd6ab918e3",
- "shasum": ""
- },
- "bin": [
- "bin/spin"
- ],
- "type": "library",
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "GPL-3.0-or-later"
- ],
- "authors": [
- {
- "name": "Dan Pastori",
- "homepage": "https://twitter.com/danpastori"
- },
- {
- "name": "Jay Rogers",
- "homepage": "https://twitter.com/jaydrogers"
- }
- ],
- "description": "Replicate your production environment locally using Docker. Just run \"spin up\". It's really that easy.",
- "support": {
- "issues": "https://github.com/serversideup/spin/issues",
- "source": "https://github.com/serversideup/spin/tree/v3.0.2"
- },
- "funding": [
- {
- "url": "https://github.com/serversideup",
- "type": "github"
- }
- ],
- "time": "2025-01-14T19:02:40+00:00"
- },
- {
- "name": "spatie/error-solutions",
- "version": "1.1.3",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/error-solutions.git",
- "reference": "e495d7178ca524f2dd0fe6a1d99a1e608e1c9936"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/error-solutions/zipball/e495d7178ca524f2dd0fe6a1d99a1e608e1c9936",
- "reference": "e495d7178ca524f2dd0fe6a1d99a1e608e1c9936",
- "shasum": ""
- },
- "require": {
- "php": "^8.0"
- },
- "require-dev": {
- "illuminate/broadcasting": "^10.0|^11.0|^12.0",
- "illuminate/cache": "^10.0|^11.0|^12.0",
- "illuminate/support": "^10.0|^11.0|^12.0",
- "livewire/livewire": "^2.11|^3.5.20",
- "openai-php/client": "^0.10.1",
- "orchestra/testbench": "8.22.3|^9.0|^10.0",
- "pestphp/pest": "^2.20|^3.0",
- "phpstan/phpstan": "^2.1",
- "psr/simple-cache": "^3.0",
- "psr/simple-cache-implementation": "^3.0",
- "spatie/ray": "^1.28",
- "symfony/cache": "^5.4|^6.0|^7.0",
- "symfony/process": "^5.4|^6.0|^7.0",
- "vlucas/phpdotenv": "^5.5"
- },
- "suggest": {
- "openai-php/client": "Require get solutions from OpenAI",
- "simple-cache-implementation": "To cache solutions from OpenAI"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Spatie\\Ignition\\": "legacy/ignition",
- "Spatie\\ErrorSolutions\\": "src",
- "Spatie\\LaravelIgnition\\": "legacy/laravel-ignition"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ruben Van Assche",
- "email": "ruben@spatie.be",
- "role": "Developer"
- }
- ],
- "description": "This is my package error-solutions",
- "homepage": "https://github.com/spatie/error-solutions",
- "keywords": [
- "error-solutions",
- "spatie"
- ],
- "support": {
- "issues": "https://github.com/spatie/error-solutions/issues",
- "source": "https://github.com/spatie/error-solutions/tree/1.1.3"
- },
- "funding": [
- {
- "url": "https://github.com/Spatie",
- "type": "github"
- }
- ],
- "time": "2025-02-14T12:29:50+00:00"
- },
- {
- "name": "spatie/flare-client-php",
- "version": "1.10.1",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/flare-client-php.git",
- "reference": "bf1716eb98bd689451b071548ae9e70738dce62f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/flare-client-php/zipball/bf1716eb98bd689451b071548ae9e70738dce62f",
- "reference": "bf1716eb98bd689451b071548ae9e70738dce62f",
- "shasum": ""
- },
- "require": {
- "illuminate/pipeline": "^8.0|^9.0|^10.0|^11.0|^12.0",
- "php": "^8.0",
- "spatie/backtrace": "^1.6.1",
- "symfony/http-foundation": "^5.2|^6.0|^7.0",
- "symfony/mime": "^5.2|^6.0|^7.0",
- "symfony/process": "^5.2|^6.0|^7.0",
- "symfony/var-dumper": "^5.2|^6.0|^7.0"
- },
- "require-dev": {
- "dms/phpunit-arraysubset-asserts": "^0.5.0",
- "pestphp/pest": "^1.20|^2.0",
- "phpstan/extension-installer": "^1.1",
- "phpstan/phpstan-deprecation-rules": "^1.0",
- "phpstan/phpstan-phpunit": "^1.0",
- "spatie/pest-plugin-snapshots": "^1.0|^2.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.3.x-dev"
- }
- },
- "autoload": {
- "files": [
- "src/helpers.php"
- ],
- "psr-4": {
- "Spatie\\FlareClient\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Send PHP errors to Flare",
- "homepage": "https://github.com/spatie/flare-client-php",
- "keywords": [
- "exception",
- "flare",
- "reporting",
- "spatie"
- ],
- "support": {
- "issues": "https://github.com/spatie/flare-client-php/issues",
- "source": "https://github.com/spatie/flare-client-php/tree/1.10.1"
- },
- "funding": [
- {
- "url": "https://github.com/spatie",
- "type": "github"
- }
- ],
- "time": "2025-02-14T13:42:06+00:00"
- },
- {
- "name": "spatie/ignition",
- "version": "1.15.1",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/ignition.git",
- "reference": "31f314153020aee5af3537e507fef892ffbf8c85"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/ignition/zipball/31f314153020aee5af3537e507fef892ffbf8c85",
- "reference": "31f314153020aee5af3537e507fef892ffbf8c85",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "ext-mbstring": "*",
- "php": "^8.0",
- "spatie/error-solutions": "^1.0",
- "spatie/flare-client-php": "^1.7",
- "symfony/console": "^5.4|^6.0|^7.0",
- "symfony/var-dumper": "^5.4|^6.0|^7.0"
- },
- "require-dev": {
- "illuminate/cache": "^9.52|^10.0|^11.0|^12.0",
- "mockery/mockery": "^1.4",
- "pestphp/pest": "^1.20|^2.0",
- "phpstan/extension-installer": "^1.1",
- "phpstan/phpstan-deprecation-rules": "^1.0",
- "phpstan/phpstan-phpunit": "^1.0",
- "psr/simple-cache-implementation": "*",
- "symfony/cache": "^5.4|^6.0|^7.0",
- "symfony/process": "^5.4|^6.0|^7.0",
- "vlucas/phpdotenv": "^5.5"
- },
- "suggest": {
- "openai-php/client": "Require get solutions from OpenAI",
- "simple-cache-implementation": "To cache solutions from OpenAI"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.5.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Spatie\\Ignition\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Spatie",
- "email": "info@spatie.be",
- "role": "Developer"
- }
- ],
- "description": "A beautiful error page for PHP applications.",
- "homepage": "https://flareapp.io/ignition",
- "keywords": [
- "error",
- "flare",
- "laravel",
- "page"
- ],
- "support": {
- "docs": "https://flareapp.io/docs/ignition-for-laravel/introduction",
- "forum": "https://twitter.com/flareappio",
- "issues": "https://github.com/spatie/ignition/issues",
- "source": "https://github.com/spatie/ignition"
- },
- "funding": [
- {
- "url": "https://github.com/spatie",
- "type": "github"
- }
- ],
- "time": "2025-02-21T14:31:39+00:00"
- },
- {
- "name": "spatie/laravel-ignition",
- "version": "2.9.1",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/laravel-ignition.git",
- "reference": "1baee07216d6748ebd3a65ba97381b051838707a"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/1baee07216d6748ebd3a65ba97381b051838707a",
- "reference": "1baee07216d6748ebd3a65ba97381b051838707a",
- "shasum": ""
- },
- "require": {
- "ext-curl": "*",
- "ext-json": "*",
- "ext-mbstring": "*",
- "illuminate/support": "^10.0|^11.0|^12.0",
- "php": "^8.1",
- "spatie/ignition": "^1.15",
- "symfony/console": "^6.2.3|^7.0",
- "symfony/var-dumper": "^6.2.3|^7.0"
- },
- "require-dev": {
- "livewire/livewire": "^2.11|^3.3.5",
- "mockery/mockery": "^1.5.1",
- "openai-php/client": "^0.8.1|^0.10",
- "orchestra/testbench": "8.22.3|^9.0|^10.0",
- "pestphp/pest": "^2.34|^3.7",
- "phpstan/extension-installer": "^1.3.1",
- "phpstan/phpstan-deprecation-rules": "^1.1.1|^2.0",
- "phpstan/phpstan-phpunit": "^1.3.16|^2.0",
- "vlucas/phpdotenv": "^5.5"
- },
- "suggest": {
- "openai-php/client": "Require get solutions from OpenAI",
- "psr/simple-cache-implementation": "Needed to cache solutions from OpenAI"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "aliases": {
- "Flare": "Spatie\\LaravelIgnition\\Facades\\Flare"
- },
- "providers": [
- "Spatie\\LaravelIgnition\\IgnitionServiceProvider"
- ]
- }
- },
- "autoload": {
- "files": [
- "src/helpers.php"
- ],
- "psr-4": {
- "Spatie\\LaravelIgnition\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Spatie",
- "email": "info@spatie.be",
- "role": "Developer"
- }
- ],
- "description": "A beautiful error page for Laravel applications.",
- "homepage": "https://flareapp.io/ignition",
- "keywords": [
- "error",
- "flare",
- "laravel",
- "page"
- ],
- "support": {
- "docs": "https://flareapp.io/docs/ignition-for-laravel/introduction",
- "forum": "https://twitter.com/flareappio",
- "issues": "https://github.com/spatie/laravel-ignition/issues",
- "source": "https://github.com/spatie/laravel-ignition"
- },
- "funding": [
- {
- "url": "https://github.com/spatie",
- "type": "github"
- }
- ],
- "time": "2025-02-20T13:13:55+00:00"
- },
{
"name": "staabm/side-effects-detector",
"version": "1.0.5",
@@ -15313,57 +7941,37 @@
"time": "2024-10-20T05:08:20+00:00"
},
{
- "name": "symfony/http-client",
+ "name": "symfony/yaml",
"version": "v7.2.3",
"source": {
"type": "git",
- "url": "https://github.com/symfony/http-client.git",
- "reference": "7ce6078c79a4a7afff931c413d2959d3bffbfb8d"
+ "url": "https://github.com/symfony/yaml.git",
+ "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-client/zipball/7ce6078c79a4a7afff931c413d2959d3bffbfb8d",
- "reference": "7ce6078c79a4a7afff931c413d2959d3bffbfb8d",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/ac238f173df0c9c1120f862d0f599e17535a87ec",
+ "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec",
"shasum": ""
},
"require": {
"php": ">=8.2",
- "psr/log": "^1|^2|^3",
- "symfony/deprecation-contracts": "^2.5|^3",
- "symfony/http-client-contracts": "~3.4.4|^3.5.2",
- "symfony/service-contracts": "^2.5|^3"
+ "symfony/deprecation-contracts": "^2.5|^3.0",
+ "symfony/polyfill-ctype": "^1.8"
},
"conflict": {
- "amphp/amp": "<2.5",
- "php-http/discovery": "<1.15",
- "symfony/http-foundation": "<6.4"
- },
- "provide": {
- "php-http/async-client-implementation": "*",
- "php-http/client-implementation": "*",
- "psr/http-client-implementation": "1.0",
- "symfony/http-client-implementation": "3.0"
+ "symfony/console": "<6.4"
},
"require-dev": {
- "amphp/http-client": "^4.2.1|^5.0",
- "amphp/http-tunnel": "^1.0|^2.0",
- "amphp/socket": "^1.1",
- "guzzlehttp/promises": "^1.4|^2.0",
- "nyholm/psr7": "^1.0",
- "php-http/httplug": "^1.0|^2.0",
- "psr/http-client": "^1.0",
- "symfony/amphp-http-client-meta": "^1.0|^2.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/messenger": "^6.4|^7.0",
- "symfony/process": "^6.4|^7.0",
- "symfony/rate-limiter": "^6.4|^7.0",
- "symfony/stopwatch": "^6.4|^7.0"
+ "symfony/console": "^6.4|^7.0"
},
+ "bin": [
+ "Resources/bin/yaml-lint"
+ ],
"type": "library",
"autoload": {
"psr-4": {
- "Symfony\\Component\\HttpClient\\": ""
+ "Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
@@ -15375,21 +7983,18 @@
],
"authors": [
{
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
+ "description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
- "keywords": [
- "http"
- ],
"support": {
- "source": "https://github.com/symfony/http-client/tree/v7.2.3"
+ "source": "https://github.com/symfony/yaml/tree/v7.2.3"
},
"funding": [
{
@@ -15405,144 +8010,7 @@
"type": "tidelift"
}
],
- "time": "2025-01-28T15:51:35+00:00"
- },
- {
- "name": "symfony/http-client-contracts",
- "version": "v3.5.2",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/http-client-contracts.git",
- "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645",
- "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/contracts",
- "name": "symfony/contracts"
- },
- "branch-alias": {
- "dev-main": "3.5-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Symfony\\Contracts\\HttpClient\\": ""
- },
- "exclude-from-classmap": [
- "/Test/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Generic abstractions related to HTTP clients",
- "homepage": "https://symfony.com",
- "keywords": [
- "abstractions",
- "contracts",
- "decoupling",
- "interfaces",
- "interoperability",
- "standards"
- ],
- "support": {
- "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-12-07T08:49:48+00:00"
- },
- {
- "name": "ta-tikoma/phpunit-architecture-test",
- "version": "0.8.4",
- "source": {
- "type": "git",
- "url": "https://github.com/ta-tikoma/phpunit-architecture-test.git",
- "reference": "89f0dea1cb0f0d5744d3ec1764a286af5e006636"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/89f0dea1cb0f0d5744d3ec1764a286af5e006636",
- "reference": "89f0dea1cb0f0d5744d3ec1764a286af5e006636",
- "shasum": ""
- },
- "require": {
- "nikic/php-parser": "^4.18.0 || ^5.0.0",
- "php": "^8.1.0",
- "phpdocumentor/reflection-docblock": "^5.3.0",
- "phpunit/phpunit": "^10.5.5 || ^11.0.0",
- "symfony/finder": "^6.4.0 || ^7.0.0"
- },
- "require-dev": {
- "laravel/pint": "^1.13.7",
- "phpstan/phpstan": "^1.10.52"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "PHPUnit\\Architecture\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ni Shi",
- "email": "futik0ma011@gmail.com"
- },
- {
- "name": "Nuno Maduro",
- "email": "enunomaduro@gmail.com"
- }
- ],
- "description": "Methods for testing application architecture",
- "keywords": [
- "architecture",
- "phpunit",
- "stucture",
- "test",
- "testing"
- ],
- "support": {
- "issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues",
- "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.4"
- },
- "time": "2024-01-05T14:10:56+00:00"
+ "time": "2025-01-07T12:55:42+00:00"
},
{
"name": "theseer/tokenizer",
@@ -15597,12 +8065,12 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
- "php": "^8.4"
+ "php": "^8.2"
},
- "platform-dev": [],
- "plugin-api-version": "2.3.0"
+ "platform-dev": {},
+ "plugin-api-version": "2.6.0"
}
diff --git a/config/app.php b/config/app.php
index 371ac44ecc..324b513a27 100644
--- a/config/app.php
+++ b/config/app.php
@@ -1,23 +1,19 @@
env('APP_ID'),
- 'port' => env('APP_PORT', 8000),
/*
|--------------------------------------------------------------------------
| Application Name
|--------------------------------------------------------------------------
|
- | This value is the name of your application. This value is used when the
+ | This value is the name of your application, which will be used when the
| framework needs to place the application's name in a notification or
- | any other location as required by the application or its packages.
+ | other UI elements where an application name needs to be displayed.
|
*/
- 'name' => env('APP_NAME', 'Coolify'),
+ 'name' => env('APP_NAME', 'Laravel'),
/*
|--------------------------------------------------------------------------
@@ -52,22 +48,20 @@ return [
|
| This URL is used by the console to properly generate URLs when using
| the Artisan command line tool. You should set this to the root of
- | your application so that it is used when running Artisan tasks.
+ | the application so that it's available within Artisan commands.
|
*/
'url' => env('APP_URL', 'http://localhost'),
- 'asset_url' => env('ASSET_URL'),
-
/*
|--------------------------------------------------------------------------
| Application Timezone
|--------------------------------------------------------------------------
|
| Here you may specify the default timezone for your application, which
- | will be used by the PHP date and date-time functions. We have gone
- | ahead and set this to a sensible default for you out of the box.
+ | will be used by the PHP date and date-time functions. The timezone
+ | is set to "UTC" by default as it is suitable for most use cases.
|
*/
@@ -79,53 +73,37 @@ return [
|--------------------------------------------------------------------------
|
| The application locale determines the default locale that will be used
- | by the translation service provider. You are free to set this value
- | to any of the locales which will be supported by the application.
+ | by Laravel's translation / localization methods. This option can be
+ | set to any locale for which you plan to have translation strings.
|
*/
- 'locale' => 'en',
+ 'locale' => env('APP_LOCALE', 'en'),
- /*
- |--------------------------------------------------------------------------
- | Application Fallback Locale
- |--------------------------------------------------------------------------
- |
- | The fallback locale determines the locale to use when the current one
- | is not available. You may change the value to correspond to any of
- | the language folders that are provided through your application.
- |
- */
+ 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
- 'fallback_locale' => 'en',
-
- /*
- |--------------------------------------------------------------------------
- | Faker Locale
- |--------------------------------------------------------------------------
- |
- | This locale will be used by the Faker PHP library when generating fake
- | data for your database seeds. For example, this will be used to get
- | localized telephone numbers, street address information and more.
- |
- */
-
- 'faker_locale' => 'en_US',
+ 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
/*
|--------------------------------------------------------------------------
| Encryption Key
|--------------------------------------------------------------------------
|
- | This key is used by the Illuminate encrypter service and should be set
- | to a random, 32 character string, otherwise these encrypted strings
- | will not be safe. Please do this before deploying an application!
+ | This key is utilized by Laravel's encryption services and should be set
+ | to a random, 32 character string to ensure that all encrypted values
+ | are secure. You should do this prior to deploying the application.
|
*/
+ 'cipher' => 'AES-256-CBC',
+
'key' => env('APP_KEY'),
- 'cipher' => 'AES-256-CBC',
+ 'previous_keys' => [
+ ...array_filter(
+ explode(',', env('APP_PREVIOUS_KEYS', ''))
+ ),
+ ],
/*
|--------------------------------------------------------------------------
@@ -141,79 +119,8 @@ return [
*/
'maintenance' => [
- 'driver' => 'cache',
- 'store' => 'redis',
+ 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
+ 'store' => env('APP_MAINTENANCE_STORE', 'database'),
],
- /*
- |--------------------------------------------------------------------------
- | Autoloaded Service Providers
- |--------------------------------------------------------------------------
- |
- | The service providers listed here will be automatically loaded on the
- | request to your application. Feel free to add your own services to
- | this array to grant expanded functionality to your applications.
- |
- */
-
- 'providers' => [
-
- /*
- * Laravel Framework Service Providers...
- */
- Illuminate\Auth\AuthServiceProvider::class,
- Illuminate\Broadcasting\BroadcastServiceProvider::class,
- Illuminate\Bus\BusServiceProvider::class,
- Illuminate\Cache\CacheServiceProvider::class,
- Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
- Illuminate\Cookie\CookieServiceProvider::class,
- Illuminate\Database\DatabaseServiceProvider::class,
- Illuminate\Encryption\EncryptionServiceProvider::class,
- Illuminate\Filesystem\FilesystemServiceProvider::class,
- Illuminate\Foundation\Providers\FoundationServiceProvider::class,
- Illuminate\Hashing\HashServiceProvider::class,
- Illuminate\Mail\MailServiceProvider::class,
- Illuminate\Notifications\NotificationServiceProvider::class,
- Illuminate\Pagination\PaginationServiceProvider::class,
- Illuminate\Pipeline\PipelineServiceProvider::class,
- Illuminate\Queue\QueueServiceProvider::class,
- Illuminate\Redis\RedisServiceProvider::class,
- Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
- Illuminate\Session\SessionServiceProvider::class,
- Illuminate\Translation\TranslationServiceProvider::class,
- Illuminate\Validation\ValidationServiceProvider::class,
- Illuminate\View\ViewServiceProvider::class,
-
- /*
- * Package Service Providers...
- */
- \SocialiteProviders\Manager\ServiceProvider::class,
-
- /*
- * Application Service Providers...
- */
- App\Providers\AppServiceProvider::class,
- App\Providers\FortifyServiceProvider::class,
- App\Providers\AuthServiceProvider::class,
- App\Providers\BroadcastServiceProvider::class,
- App\Providers\EventServiceProvider::class,
- App\Providers\HorizonServiceProvider::class,
- App\Providers\RouteServiceProvider::class,
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Class Aliases
- |--------------------------------------------------------------------------
- |
- | This array of class aliases will be registered when this application
- | is started. However, feel free to register as many as you wish as
- | the aliases are "lazy" loaded so they don't hinder performance.
- |
- */
-
- 'aliases' => Facade::defaultAliases()->merge([
- // 'ExampleClass' => App\Example\ExampleClass::class,
- ])->toArray(),
-
];
diff --git a/config/auth.php b/config/auth.php
index 83c36c0d3a..0ba5d5d8f1 100644
--- a/config/auth.php
+++ b/config/auth.php
@@ -7,15 +7,15 @@ return [
| Authentication Defaults
|--------------------------------------------------------------------------
|
- | This option controls the default authentication "guard" and password
- | reset options for your application. You may change these defaults
+ | This option defines the default authentication "guard" and password
+ | reset "broker" for your application. You may change these values
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
- 'guard' => 'web',
- 'passwords' => 'users',
+ 'guard' => env('AUTH_GUARD', 'web'),
+ 'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
],
/*
@@ -25,11 +25,11 @@ return [
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
- | here which uses session storage and the Eloquent user provider.
+ | which utilizes session storage plus the Eloquent user provider.
|
- | All authentication drivers have a user provider. This defines how the
+ | All authentication guards have a user provider, which defines how the
| users are actually retrieved out of your database or other storage
- | mechanisms used by this application to persist your user's data.
+ | system used by the application. Typically, Eloquent is utilized.
|
| Supported: "session"
|
@@ -47,12 +47,12 @@ return [
| User Providers
|--------------------------------------------------------------------------
|
- | All authentication drivers have a user provider. This defines how the
+ | All authentication guards have a user provider, which defines how the
| users are actually retrieved out of your database or other storage
- | mechanisms used by this application to persist your user's data.
+ | system used by the application. Typically, Eloquent is utilized.
|
| If you have multiple user tables or models you may configure multiple
- | sources which represent each model / table. These sources may then
+ | providers to represent the model / table. These providers may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
@@ -62,7 +62,7 @@ return [
'providers' => [
'users' => [
'driver' => 'eloquent',
- 'model' => App\Models\User::class,
+ 'model' => env('AUTH_MODEL', App\Models\User::class),
],
// 'users' => [
@@ -76,9 +76,9 @@ return [
| Resetting Passwords
|--------------------------------------------------------------------------
|
- | You may specify multiple password reset configurations if you have more
- | than one user table or model in the application and you want to have
- | separate password reset settings based on the specific user types.
+ | These configuration options specify the behavior of Laravel's password
+ | reset functionality, including the table utilized for token storage
+ | and the user provider that is invoked to actually retrieve users.
|
| The expiry time is the number of minutes that each reset token will be
| considered valid. This security feature keeps tokens short-lived so
@@ -93,8 +93,8 @@ return [
'passwords' => [
'users' => [
'provider' => 'users',
- 'table' => 'password_reset_tokens',
- 'expire' => 10,
+ 'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
+ 'expire' => 60,
'throttle' => 60,
],
],
@@ -105,11 +105,11 @@ return [
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
- | times out and the user is prompted to re-enter their password via the
+ | window expires and users are asked to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
- 'password_timeout' => 10800,
+ 'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
];
diff --git a/config/broadcasting.php b/config/broadcasting.php
deleted file mode 100644
index 5509b00730..0000000000
--- a/config/broadcasting.php
+++ /dev/null
@@ -1,70 +0,0 @@
- env('BROADCAST_DRIVER', 'pusher'),
-
- /*
- |--------------------------------------------------------------------------
- | Broadcast Connections
- |--------------------------------------------------------------------------
- |
- | Here you may define all of the broadcast connections that will be used
- | to broadcast events to other systems or over websockets. Samples of
- | each available type of connection are provided inside this array.
- |
- */
-
- 'connections' => [
-
- 'pusher' => [
- 'driver' => 'pusher',
- 'key' => env('PUSHER_APP_KEY', 'coolify'),
- 'secret' => env('PUSHER_APP_SECRET', 'coolify'),
- 'app_id' => env('PUSHER_APP_ID', 'coolify'),
- 'options' => [
- 'host' => env('PUSHER_BACKEND_HOST', 'coolify-realtime'),
- 'port' => env('PUSHER_BACKEND_PORT', 6001),
- 'scheme' => env('PUSHER_SCHEME', 'http'),
- 'encrypted' => true,
- 'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
- ],
- 'client_options' => [
- // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
- ],
- ],
-
- 'ably' => [
- 'driver' => 'ably',
- 'key' => env('ABLY_KEY'),
- ],
-
- 'redis' => [
- 'driver' => 'redis',
- 'connection' => 'default',
- ],
-
- 'log' => [
- 'driver' => 'log',
- ],
-
- 'null' => [
- 'driver' => 'null',
- ],
-
- ],
-
-];
diff --git a/config/cache.php b/config/cache.php
index b82efddc6b..925f7d2ee8 100644
--- a/config/cache.php
+++ b/config/cache.php
@@ -9,13 +9,13 @@ return [
| Default Cache Store
|--------------------------------------------------------------------------
|
- | This option controls the default cache connection that gets used while
- | using this caching library. This connection is used when another is
- | not explicitly specified when executing a given caching function.
+ | This option controls the default cache store that will be used by the
+ | framework. This connection is utilized if another isn't explicitly
+ | specified when running a cache operation inside the application.
|
*/
- 'default' => env('CACHE_DRIVER', 'redis'),
+ 'default' => env('CACHE_STORE', 'database'),
/*
|--------------------------------------------------------------------------
@@ -26,17 +26,13 @@ return [
| well as their drivers. You may even define multiple stores for the
| same cache driver to group types of items stored in your caches.
|
- | Supported drivers: "apc", "array", "database", "file",
- | "memcached", "redis", "dynamodb", "octane", "null"
+ | Supported drivers: "array", "database", "file", "memcached",
+ | "redis", "dynamodb", "octane", "null"
|
*/
'stores' => [
- 'apc' => [
- 'driver' => 'apc',
- ],
-
'array' => [
'driver' => 'array',
'serialize' => false,
@@ -44,14 +40,16 @@ return [
'database' => [
'driver' => 'database',
- 'table' => 'cache',
- 'connection' => null,
- 'lock_connection' => null,
+ 'connection' => env('DB_CACHE_CONNECTION'),
+ 'table' => env('DB_CACHE_TABLE', 'cache'),
+ 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'),
+ 'lock_table' => env('DB_CACHE_LOCK_TABLE'),
],
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache/data'),
+ 'lock_path' => storage_path('framework/cache/data'),
],
'memcached' => [
@@ -75,8 +73,8 @@ return [
'redis' => [
'driver' => 'redis',
- 'connection' => 'cache',
- 'lock_connection' => 'default',
+ 'connection' => env('REDIS_CACHE_CONNECTION', 'cache'),
+ 'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'),
],
'dynamodb' => [
@@ -99,8 +97,8 @@ return [
| Cache Key Prefix
|--------------------------------------------------------------------------
|
- | When utilizing the APC, database, memcached, Redis, or DynamoDB cache
- | stores there might be other applications using the same cache. For
+ | When utilizing the APC, database, memcached, Redis, and DynamoDB cache
+ | stores, there might be other applications using the same cache. For
| that reason, you may prefix every cache key to avoid collisions.
|
*/
diff --git a/config/chunk-upload.php b/config/chunk-upload.php
deleted file mode 100644
index e577eb858c..0000000000
--- a/config/chunk-upload.php
+++ /dev/null
@@ -1,45 +0,0 @@
- [
- /*
- * Returns the folder name of the chunks. The location is in storage/app/{folder_name}
- */
- 'chunks' => 'chunks',
- 'disk' => 'local',
- ],
- 'clear' => [
- /*
- * How old chunks we should delete
- */
- 'timestamp' => '-1 HOURS',
- 'schedule' => [
- 'enabled' => false,
- 'cron' => '25 * * * *', // run every hour on the 25th minute
- ],
- ],
- 'chunk' => [
- // setup for the chunk naming setup to ensure same name upload at same time
- 'name' => [
- 'use' => [
- 'session' => true, // should the chunk name use the session id? The uploader must send cookie!,
- 'browser' => false, // instead of session we can use the ip and browser?
- ],
- ],
- ],
- 'handlers' => [
- // A list of handlers/providers that will be appended to existing list of handlers
- 'custom' => [],
- // Overrides the list of handlers - use only what you really want
- 'override' => [
- // \Pion\Laravel\ChunkUpload\Handler\DropZoneUploadHandler::class
- ],
- ],
-];
diff --git a/config/constants.php b/config/constants.php
deleted file mode 100644
index 9d15da1da1..0000000000
--- a/config/constants.php
+++ /dev/null
@@ -1,83 +0,0 @@
- [
- 'version' => '4.0.0-beta.399',
- 'helper_version' => '1.0.7',
- 'realtime_version' => '1.0.6',
- 'self_hosted' => env('SELF_HOSTED', true),
- 'autoupdate' => env('AUTOUPDATE'),
- 'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
- 'helper_image' => env('HELPER_IMAGE', 'ghcr.io/coollabsio/coolify-helper'),
- 'is_windows_docker_desktop' => env('IS_WINDOWS_DOCKER_DESKTOP', false),
- ],
-
- 'urls' => [
- 'docs' => 'https://coolify.io/docs',
- 'contact' => 'https://coolify.io/docs/contact',
- ],
-
- 'services' => [
- // Temporary disabled until cache is implemented
- // 'official' => 'https://cdn.coollabs.io/coolify/service-templates.json',
- 'official' => 'https://raw.githubusercontent.com/coollabsio/coolify/main/templates/service-templates.json',
- ],
-
- 'terminal' => [
- 'protocol' => env('TERMINAL_PROTOCOL'),
- 'host' => env('TERMINAL_HOST'),
- 'port' => env('TERMINAL_PORT'),
- ],
-
- 'pusher' => [
- 'host' => env('PUSHER_HOST'),
- 'port' => env('PUSHER_PORT'),
- 'app_key' => env('PUSHER_APP_KEY'),
- ],
-
- 'migration' => [
- 'is_migration_enabled' => env('MIGRATION_ENABLED', true),
- ],
-
- 'seeder' => [
- 'is_seeder_enabled' => env('SEEDER_ENABLED', true),
- ],
-
- 'horizon' => [
- 'is_horizon_enabled' => env('HORIZON_ENABLED', true),
- 'is_scheduler_enabled' => env('SCHEDULER_ENABLED', true),
- ],
-
- 'docker' => [
- 'minimum_required_version' => '24.0',
- ],
-
- 'ssh' => [
- 'mux_enabled' => env('MUX_ENABLED', env('SSH_MUX_ENABLED', true)),
- 'mux_persist_time' => env('SSH_MUX_PERSIST_TIME', 3600),
- 'connection_timeout' => 10,
- 'server_interval' => 20,
- 'command_timeout' => 7200,
- ],
-
- 'invitation' => [
- 'link' => [
- 'base_url' => '/invitations/',
- 'expiration_days' => 3,
- ],
- ],
-
- 'sentry' => [
- 'sentry_dsn' => env('SENTRY_DSN'),
- ],
-
- 'webhooks' => [
- 'feedback_discord_webhook' => env('FEEDBACK_DISCORD_WEBHOOK'),
- 'dev_webhook' => env('SERVEO_URL'),
- ],
-
- 'bunny' => [
- 'storage_api_key' => env('BUNNY_STORAGE_API_KEY'),
- 'api_key' => env('BUNNY_API_KEY'),
- ],
-];
diff --git a/config/cors.php b/config/cors.php
deleted file mode 100644
index 8a39e6daa6..0000000000
--- a/config/cors.php
+++ /dev/null
@@ -1,34 +0,0 @@
- ['api/*', 'sanctum/csrf-cookie'],
-
- 'allowed_methods' => ['*'],
-
- 'allowed_origins' => ['*'],
-
- 'allowed_origins_patterns' => [],
-
- 'allowed_headers' => ['*'],
-
- 'exposed_headers' => [],
-
- 'max_age' => 0,
-
- 'supports_credentials' => false,
-
-];
diff --git a/config/database.php b/config/database.php
index a40987de8a..8910562d61 100644
--- a/config/database.php
+++ b/config/database.php
@@ -10,59 +10,106 @@ return [
|--------------------------------------------------------------------------
|
| Here you may specify which of the database connections below you wish
- | to use as your default connection for all database work. Of course
- | you may use many connections at once using the Database library.
+ | to use as your default connection for database operations. This is
+ | the connection which will be utilized unless another connection
+ | is explicitly specified when you execute a query / statement.
|
*/
- 'default' => env('DB_CONNECTION', 'pgsql'),
+ 'default' => env('DB_CONNECTION', 'sqlite'),
/*
|--------------------------------------------------------------------------
| Database Connections
|--------------------------------------------------------------------------
|
- | Here are each of the database connections setup for your application.
- | Of course, examples of configuring each database platform that is
- | supported by Laravel is shown below to make development simple.
- |
- |
- | All database work in Laravel is done through the PHP PDO facilities
- | so make sure you have the driver for your particular database of
- | choice installed on your machine before you begin development.
+ | Below are all of the database connections defined for your application.
+ | An example configuration is provided for each database system which
+ | is supported by Laravel. You're free to add / remove connections.
|
*/
'connections' => [
+ 'sqlite' => [
+ 'driver' => 'sqlite',
+ 'url' => env('DB_URL'),
+ 'database' => env('DB_DATABASE', database_path('database.sqlite')),
+ 'prefix' => '',
+ 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
+ 'busy_timeout' => null,
+ 'journal_mode' => null,
+ 'synchronous' => null,
+ ],
+
+ 'mysql' => [
+ 'driver' => 'mysql',
+ 'url' => env('DB_URL'),
+ 'host' => env('DB_HOST', '127.0.0.1'),
+ 'port' => env('DB_PORT', '3306'),
+ 'database' => env('DB_DATABASE', 'laravel'),
+ 'username' => env('DB_USERNAME', 'root'),
+ 'password' => env('DB_PASSWORD', ''),
+ 'unix_socket' => env('DB_SOCKET', ''),
+ 'charset' => env('DB_CHARSET', 'utf8mb4'),
+ 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
+ 'prefix' => '',
+ 'prefix_indexes' => true,
+ 'strict' => true,
+ 'engine' => null,
+ 'options' => extension_loaded('pdo_mysql') ? array_filter([
+ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
+ ]) : [],
+ ],
+
+ 'mariadb' => [
+ 'driver' => 'mariadb',
+ 'url' => env('DB_URL'),
+ 'host' => env('DB_HOST', '127.0.0.1'),
+ 'port' => env('DB_PORT', '3306'),
+ 'database' => env('DB_DATABASE', 'laravel'),
+ 'username' => env('DB_USERNAME', 'root'),
+ 'password' => env('DB_PASSWORD', ''),
+ 'unix_socket' => env('DB_SOCKET', ''),
+ 'charset' => env('DB_CHARSET', 'utf8mb4'),
+ 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
+ 'prefix' => '',
+ 'prefix_indexes' => true,
+ 'strict' => true,
+ 'engine' => null,
+ 'options' => extension_loaded('pdo_mysql') ? array_filter([
+ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
+ ]) : [],
+ ],
+
'pgsql' => [
'driver' => 'pgsql',
- 'url' => env('DATABASE_URL'),
- 'host' => env('DB_HOST', 'coolify-db'),
+ 'url' => env('DB_URL'),
+ 'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
- 'database' => env('DB_DATABASE', 'coolify'),
- 'username' => env('DB_USERNAME', 'coolify'),
+ 'database' => env('DB_DATABASE', 'laravel'),
+ 'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
- 'charset' => 'utf8',
+ 'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
'search_path' => 'public',
'sslmode' => 'prefer',
],
- 'testing' => [
- 'driver' => 'pgsql',
- 'url' => env('DATABASE_TEST_URL'),
- 'host' => env('DB_TEST_HOST', 'postgres'),
- 'port' => env('DB_TEST_PORT', '5432'),
- 'database' => env('DB_TEST_DATABASE', 'coolify_test'),
- 'username' => env('DB_TEST_USERNAME', 'coolify'),
- 'password' => env('DB_TEST_PASSWORD', 'password'),
- 'charset' => 'utf8',
+ 'sqlsrv' => [
+ 'driver' => 'sqlsrv',
+ 'url' => env('DB_URL'),
+ 'host' => env('DB_HOST', 'localhost'),
+ 'port' => env('DB_PORT', '1433'),
+ 'database' => env('DB_DATABASE', 'laravel'),
+ 'username' => env('DB_USERNAME', 'root'),
+ 'password' => env('DB_PASSWORD', ''),
+ 'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
- 'search_path' => 'public',
- 'sslmode' => 'prefer',
+ // 'encrypt' => env('DB_ENCRYPT', 'yes'),
+ // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
],
],
@@ -74,11 +121,14 @@ return [
|
| This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of
- | the migrations on disk haven't actually been run in the database.
+ | the migrations on disk haven't actually been run on the database.
|
*/
- 'migrations' => 'migrations',
+ 'migrations' => [
+ 'table' => 'migrations',
+ 'update_date_on_publish' => true,
+ ],
/*
|--------------------------------------------------------------------------
@@ -87,7 +137,7 @@ return [
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer body of commands than a typical key-value system
- | such as APC or Memcached. Laravel makes it easy to dig right in.
+ | such as Memcached. You may define your connection settings here.
|
*/
@@ -98,11 +148,12 @@ return [
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
+ 'persistent' => env('REDIS_PERSISTENT', false),
],
'default' => [
'url' => env('REDIS_URL'),
- 'host' => env('REDIS_HOST', 'coolify-redis'),
+ 'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
@@ -111,7 +162,7 @@ return [
'cache' => [
'url' => env('REDIS_URL'),
- 'host' => env('REDIS_HOST', 'coolify-redis'),
+ 'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
diff --git a/config/debugbar.php b/config/debugbar.php
deleted file mode 100644
index 4bc660fff6..0000000000
--- a/config/debugbar.php
+++ /dev/null
@@ -1,326 +0,0 @@
- env('DEBUGBAR_ENABLED', null),
- 'except' => [
- 'telescope*',
- 'horizon*',
- 'api*',
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Storage settings
- |--------------------------------------------------------------------------
- |
- | DebugBar stores data for session/ajax requests.
- | You can disable this, so the debugbar stores data in headers/session,
- | but this can cause problems with large data collectors.
- | By default, file storage (in the storage folder) is used. Redis and PDO
- | can also be used. For PDO, run the package migrations first.
- |
- | Warning: Enabling storage.open will allow everyone to access previous
- | request, do not enable open storage in publicly available environments!
- | Specify a callback if you want to limit based on IP or authentication.
- | Leaving it to null will allow localhost only.
- */
- 'storage' => [
- 'enabled' => true,
- 'open' => env('DEBUGBAR_OPEN_STORAGE'), // bool/callback.
- 'driver' => 'file', // redis, file, pdo, socket, custom
- 'path' => storage_path('debugbar'), // For file driver
- 'connection' => null, // Leave null for default connection (Redis/PDO)
- 'provider' => '', // Instance of StorageInterface for custom driver
- 'hostname' => '127.0.0.1', // Hostname to use with the "socket" driver
- 'port' => 2304, // Port to use with the "socket" driver
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Editor
- |--------------------------------------------------------------------------
- |
- | Choose your preferred editor to use when clicking file name.
- |
- | Supported: "phpstorm", "vscode", "vscode-insiders", "vscode-remote",
- | "vscode-insiders-remote", "vscodium", "textmate", "emacs",
- | "sublime", "atom", "nova", "macvim", "idea", "netbeans",
- | "xdebug", "espresso"
- |
- */
-
- 'editor' => env('DEBUGBAR_EDITOR') ?: env('IGNITION_EDITOR', 'phpstorm'),
-
- /*
- |--------------------------------------------------------------------------
- | Remote Path Mapping
- |--------------------------------------------------------------------------
- |
- | If you are using a remote dev server, like Laravel Homestead, Docker, or
- | even a remote VPS, it will be necessary to specify your path mapping.
- |
- | Leaving one, or both of these, empty or null will not trigger the remote
- | URL changes and Debugbar will treat your editor links as local files.
- |
- | "remote_sites_path" is an absolute base path for your sites or projects
- | in Homestead, Vagrant, Docker, or another remote development server.
- |
- | Example value: "/home/vagrant/Code"
- |
- | "local_sites_path" is an absolute base path for your sites or projects
- | on your local computer where your IDE or code editor is running on.
- |
- | Example values: "/Users//Code", "C:\Users\\Documents\Code"
- |
- */
-
- 'remote_sites_path' => env('DEBUGBAR_REMOTE_SITES_PATH'),
- 'local_sites_path' => env('DEBUGBAR_LOCAL_SITES_PATH', env('IGNITION_LOCAL_SITES_PATH')),
-
- /*
- |--------------------------------------------------------------------------
- | Vendors
- |--------------------------------------------------------------------------
- |
- | Vendor files are included by default, but can be set to false.
- | This can also be set to 'js' or 'css', to only include javascript or css vendor files.
- | Vendor files are for css: font-awesome (including fonts) and highlight.js (css files)
- | and for js: jquery and highlight.js
- | So if you want syntax highlighting, set it to true.
- | jQuery is set to not conflict with existing jQuery scripts.
- |
- */
-
- 'include_vendors' => true,
-
- /*
- |--------------------------------------------------------------------------
- | Capture Ajax Requests
- |--------------------------------------------------------------------------
- |
- | The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors),
- | you can use this option to disable sending the data through the headers.
- |
- | Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools.
- |
- | Note for your request to be identified as ajax requests they must either send the header
- | X-Requested-With with the value XMLHttpRequest (most JS libraries send this), or have application/json as a Accept header.
- |
- | By default `ajax_handler_auto_show` is set to true allowing ajax requests to be shown automatically in the Debugbar.
- | Changing `ajax_handler_auto_show` to false will prevent the Debugbar from reloading.
- */
-
- 'capture_ajax' => true,
- 'add_ajax_timing' => false,
- 'ajax_handler_auto_show' => true,
- 'ajax_handler_enable_tab' => true,
-
- /*
- |--------------------------------------------------------------------------
- | Custom Error Handler for Deprecated warnings
- |--------------------------------------------------------------------------
- |
- | When enabled, the Debugbar shows deprecated warnings for Symfony components
- | in the Messages tab.
- |
- */
- 'error_handler' => false,
-
- /*
- |--------------------------------------------------------------------------
- | Clockwork integration
- |--------------------------------------------------------------------------
- |
- | The Debugbar can emulate the Clockwork headers, so you can use the Chrome
- | Extension, without the server-side code. It uses Debugbar collectors instead.
- |
- */
- 'clockwork' => false,
-
- /*
- |--------------------------------------------------------------------------
- | DataCollectors
- |--------------------------------------------------------------------------
- |
- | Enable/disable DataCollectors
- |
- */
-
- 'collectors' => [
- 'phpinfo' => true, // Php version
- 'messages' => true, // Messages
- 'time' => true, // Time Datalogger
- 'memory' => true, // Memory usage
- 'exceptions' => true, // Exception displayer
- 'log' => true, // Logs from Monolog (merged in messages if enabled)
- 'db' => true, // Show database (PDO) queries and bindings
- 'views' => true, // Views with their data
- 'route' => true, // Current route information
- 'auth' => false, // Display Laravel authentication status
- 'gate' => true, // Display Laravel Gate checks
- 'session' => true, // Display session data
- 'symfony_request' => true, // Only one can be enabled..
- 'mail' => true, // Catch mail messages
- 'laravel' => false, // Laravel version and environment
- 'events' => false, // All events fired
- 'default_request' => false, // Regular or special Symfony request logger
- 'logs' => false, // Add the latest log messages
- 'files' => false, // Show the included files
- 'config' => false, // Display config settings
- 'cache' => false, // Display cache events
- 'models' => true, // Display models
- 'livewire' => true, // Display Livewire (when available)
- 'jobs' => false, // Display dispatched jobs
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Extra options
- |--------------------------------------------------------------------------
- |
- | Configure some DataCollectors
- |
- */
-
- 'options' => [
- 'time' => [
- 'memory_usage' => false, // Calculated by subtracting memory start and end, it may be inaccurate
- ],
- 'messages' => [
- 'trace' => true, // Trace the origin of the debug message
- ],
- 'memory' => [
- 'reset_peak' => false, // run memory_reset_peak_usage before collecting
- 'with_baseline' => false, // Set boot memory usage as memory peak baseline
- 'precision' => 0, // Memory rounding precision
- ],
- 'auth' => [
- 'show_name' => true, // Also show the users name/email in the debugbar
- 'show_guards' => true, // Show the guards that are used
- ],
- 'db' => [
- 'with_params' => true, // Render SQL with the parameters substituted
- 'backtrace' => true, // Use a backtrace to find the origin of the query in your files.
- 'backtrace_exclude_paths' => [], // Paths to exclude from backtrace. (in addition to defaults)
- 'timeline' => false, // Add the queries to the timeline
- 'duration_background' => true, // Show shaded background on each query relative to how long it took to execute.
- 'explain' => [ // Show EXPLAIN output on queries
- 'enabled' => false,
- 'types' => ['SELECT'], // Deprecated setting, is always only SELECT
- ],
- 'hints' => false, // Show hints for common mistakes
- 'show_copy' => false, // Show copy button next to the query,
- 'slow_threshold' => false, // Only track queries that last longer than this time in ms
- 'memory_usage' => false, // Show queries memory usage
- 'soft_limit' => 100, // After the soft limit, no parameters/backtrace are captured
- 'hard_limit' => 500, // After the hard limit, queries are ignored
- ],
- 'mail' => [
- 'timeline' => false, // Add mails to the timeline
- 'show_body' => true,
- ],
- 'views' => [
- 'timeline' => false, // Add the views to the timeline (Experimental)
- 'data' => false, // true for all data, 'keys' for only names, false for no parameters.
- 'group' => 50, // Group duplicate views. Pass value to auto-group, or true/false to force
- 'exclude_paths' => [ // Add the paths which you don't want to appear in the views
- 'vendor/filament', // Exclude Filament components by default
- ],
- ],
- 'route' => [
- 'label' => true, // show complete route on bar
- ],
- 'session' => [
- 'hiddens' => [], // hides sensitive values using array paths
- ],
- 'symfony_request' => [
- 'hiddens' => [], // hides sensitive values using array paths, example: request_request.password
- ],
- 'events' => [
- 'data' => false, // collect events data, listeners
- ],
- 'logs' => [
- 'file' => null,
- ],
- 'cache' => [
- 'values' => true, // collect cache values
- ],
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Inject Debugbar in Response
- |--------------------------------------------------------------------------
- |
- | Usually, the debugbar is added just before of pages containing Livewire components. By disabling
- | this behavior, you need to use @livewireStyles and @livewireScripts.
- |
- */
-
- 'inject_assets' => true,
-
- /*
- |---------------------------------------------------------------------------
- | Navigate (SPA mode)
- |---------------------------------------------------------------------------
- |
- | By adding `` to links in your Livewire application, Livewire
- | will prevent the default link handling and instead request those pages
- | via AJAX, creating an SPA-like effect. Configure this behavior here.
- |
- */
-
- 'navigate' => [
- 'show_progress_bar' => true,
- 'progress_bar_color' => '#ffff00',
- ],
-
- /*
- |---------------------------------------------------------------------------
- | HTML Morph Markers
- |---------------------------------------------------------------------------
- |
- | Livewire intelligently "morphs" existing HTML into the newly rendered HTML
- | after each update. To make this process more reliable, Livewire injects
- | "markers" into the rendered Blade surrounding @if, @class & @foreach.
- |
- */
-
- 'inject_morph_markers' => true,
-
- /*
- |---------------------------------------------------------------------------
- | Pagination Theme
- |---------------------------------------------------------------------------
- |
- | When enabling Livewire's pagination feature by using the `WithPagination`
- | trait, Livewire will use Tailwind templates to render pagination views
- | on the page. If you want Bootstrap CSS, you can specify: "bootstrap"
- |
- */
-
- 'pagination_theme' => 'tailwind',
- 'lazy_placeholder' => 'components.page-loading',
-];
diff --git a/config/logging.php b/config/logging.php
index 4c3df4ce14..8d94292b29 100644
--- a/config/logging.php
+++ b/config/logging.php
@@ -3,6 +3,7 @@
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
+use Monolog\Processor\PsrLogMessageProcessor;
return [
@@ -11,9 +12,9 @@ return [
| Default Log Channel
|--------------------------------------------------------------------------
|
- | This option defines the default log channel that gets used when writing
- | messages to the logs. The name specified in this option should match
- | one of the channels defined in the "channels" configuration array.
+ | This option defines the default log channel that is utilized to write
+ | messages to your logs. The value provided here should match one of
+ | the channels present in the list of "channels" configured below.
|
*/
@@ -32,7 +33,7 @@ return [
'deprecations' => [
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
- 'trace' => false,
+ 'trace' => env('LOG_DEPRECATIONS_TRACE', false),
],
/*
@@ -40,20 +41,20 @@ return [
| Log Channels
|--------------------------------------------------------------------------
|
- | Here you may configure the log channels for your application. Out of
- | the box, Laravel uses the Monolog PHP logging library. This gives
- | you a variety of powerful log handlers / formatters to utilize.
+ | Here you may configure the log channels for your application. Laravel
+ | utilizes the Monolog PHP logging library, which includes a variety
+ | of powerful log handlers and formatters that you're free to use.
|
- | Available Drivers: "single", "daily", "slack", "syslog",
- | "errorlog", "monolog",
- | "custom", "stack"
+ | Available drivers: "single", "daily", "slack", "syslog",
+ | "errorlog", "monolog", "custom", "stack"
|
*/
'channels' => [
+
'stack' => [
'driver' => 'stack',
- 'channels' => ['single'],
+ 'channels' => explode(',', env('LOG_STACK', 'single')),
'ignore_exceptions' => false,
],
@@ -61,21 +62,24 @@ return [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
+ 'replace_placeholders' => true,
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
- 'days' => 14,
+ 'days' => env('LOG_DAILY_DAYS', 14),
+ 'replace_placeholders' => true,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
- 'username' => 'Laravel Log',
- 'emoji' => ':boom:',
+ 'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
+ 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),
'level' => env('LOG_LEVEL', 'critical'),
+ 'replace_placeholders' => true,
],
'papertrail' => [
@@ -87,6 +91,7 @@ return [
'port' => env('PAPERTRAIL_PORT'),
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
],
+ 'processors' => [PsrLogMessageProcessor::class],
],
'stderr' => [
@@ -97,17 +102,20 @@ return [
'with' => [
'stream' => 'php://stderr',
],
+ 'processors' => [PsrLogMessageProcessor::class],
],
'syslog' => [
'driver' => 'syslog',
'level' => env('LOG_LEVEL', 'debug'),
- 'facility' => LOG_USER,
+ 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER),
+ 'replace_placeholders' => true,
],
'errorlog' => [
'driver' => 'errorlog',
'level' => env('LOG_LEVEL', 'debug'),
+ 'replace_placeholders' => true,
],
'null' => [
@@ -118,6 +126,7 @@ return [
'emergency' => [
'path' => storage_path('logs/laravel.log'),
],
+
],
];
diff --git a/config/mail.php b/config/mail.php
index 5b647944b3..756305b3c7 100644
--- a/config/mail.php
+++ b/config/mail.php
@@ -7,13 +7,14 @@ return [
| Default Mailer
|--------------------------------------------------------------------------
|
- | This option controls the default mailer that is used to send any email
- | messages sent by your application. Alternative mailers may be setup
- | and used as needed; however, this mailer will be used by default.
+ | This option controls the default mailer that is used to send all email
+ | messages unless another mailer is explicitly specified when sending
+ | the message. All additional mailers can be configured within the
+ | "mailers" array. Examples of each type of mailer are provided.
|
*/
- 'default' => env('MAIL_MAILER', 'array'),
+ 'default' => env('MAIL_MAILER', 'log'),
/*
|--------------------------------------------------------------------------
@@ -24,45 +25,44 @@ return [
| their respective settings. Several examples have been configured for
| you and you are free to add your own as your application requires.
|
- | Laravel supports a variety of mail "transport" drivers to be used while
- | sending an e-mail. You will specify which one you are using for your
- | mailers below. You are free to add additional mailers as required.
+ | Laravel supports a variety of mail "transport" drivers that can be used
+ | when delivering an email. You may specify which one you're using for
+ | your mailers below. You may also add additional mailers if needed.
|
| Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2",
- | "postmark", "log", "array", "failover"
+ | "postmark", "resend", "log", "array",
+ | "failover", "roundrobin"
|
*/
'mailers' => [
+
'smtp' => [
'transport' => 'smtp',
- 'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
- 'port' => env('MAIL_PORT', 587),
- 'encryption' => env('MAIL_ENCRYPTION', 'tls'),
+ 'scheme' => env('MAIL_SCHEME'),
+ 'url' => env('MAIL_URL'),
+ 'host' => env('MAIL_HOST', '127.0.0.1'),
+ 'port' => env('MAIL_PORT', 2525),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'timeout' => null,
- 'local_domain' => env('MAIL_EHLO_DOMAIN'),
- ],
- 'resend' => [
- 'transport' => 'resend',
+ 'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)),
],
+
'ses' => [
'transport' => 'ses',
],
- 'mailgun' => [
- 'transport' => 'mailgun',
+ 'postmark' => [
+ 'transport' => 'postmark',
+ // 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
// 'client' => [
// 'timeout' => 5,
// ],
],
- 'postmark' => [
- 'transport' => 'postmark',
- // 'client' => [
- // 'timeout' => 5,
- // ],
+ 'resend' => [
+ 'transport' => 'resend',
],
'sendmail' => [
@@ -86,6 +86,15 @@ return [
'log',
],
],
+
+ 'roundrobin' => [
+ 'transport' => 'roundrobin',
+ 'mailers' => [
+ 'ses',
+ 'postmark',
+ ],
+ ],
+
],
/*
@@ -93,9 +102,9 @@ return [
| Global "From" Address
|--------------------------------------------------------------------------
|
- | You may wish for all e-mails sent by your application to be sent from
- | the same address. Here, you may specify a name and address that is
- | used globally for all e-mails that are sent by your application.
+ | You may wish for all emails sent by your application to be sent from
+ | the same address. Here you may specify a name and address that is
+ | used globally for all emails that are sent by your application.
|
*/
@@ -104,23 +113,4 @@ return [
'name' => env('MAIL_FROM_NAME', 'Example'),
],
- /*
- |--------------------------------------------------------------------------
- | Markdown Mail Settings
- |--------------------------------------------------------------------------
- |
- | If you are using Markdown based email rendering, you may configure your
- | theme and component paths here, allowing you to customize the design
- | of the emails. Or, you may simply stick with the Laravel defaults!
- |
- */
-
- 'markdown' => [
- 'theme' => 'default',
-
- 'paths' => [
- resource_path('views/vendor/mail'),
- ],
- ],
-
];
diff --git a/config/purify.php b/config/purify.php
deleted file mode 100644
index 66dbbb5683..0000000000
--- a/config/purify.php
+++ /dev/null
@@ -1,115 +0,0 @@
- 'default',
-
- /*
- |--------------------------------------------------------------------------
- | Config sets
- |--------------------------------------------------------------------------
- |
- | Here you may configure various sets of configuration for differentiated use of HTMLPurifier.
- | A specific set of configuration can be applied by calling the "config($name)" method on
- | a Purify instance. Feel free to add/remove/customize these attributes as you wish.
- |
- | Documentation: http://htmlpurifier.org/live/configdoc/plain.html
- |
- | Core.Encoding The encoding to convert input to.
- | HTML.Doctype Doctype to use during filtering.
- | HTML.Allowed The allowed HTML Elements with their allowed attributes.
- | HTML.ForbiddenElements The forbidden HTML elements. Elements that are listed in this
- | string will be removed, however their content will remain.
- | CSS.AllowedProperties The Allowed CSS properties.
- | AutoFormat.AutoParagraph Newlines are converted in to paragraphs whenever possible.
- | AutoFormat.RemoveEmpty Remove empty elements that contribute no semantic information to the document.
- |
- */
-
- 'configs' => [
-
- 'default' => [
- 'Core.Encoding' => 'utf-8',
- 'HTML.Doctype' => 'HTML 4.01 Transitional',
- 'HTML.Allowed' => 'h1,h2,h3,h4,h5,h6,b,u,strong,i,em,s,del,a[href|title],ul,ol,li,p[style],br,span,img[width|height|alt|src],blockquote',
- 'HTML.ForbiddenElements' => '',
- 'CSS.AllowedProperties' => 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align',
- 'AutoFormat.AutoParagraph' => false,
- 'AutoFormat.RemoveEmpty' => false,
- ],
-
- ],
-
- /*
- |--------------------------------------------------------------------------
- | HTMLPurifier definitions
- |--------------------------------------------------------------------------
- |
- | Here you may specify a class that augments the HTML definitions used by
- | HTMLPurifier. Additional HTML5 definitions are provided out of the box.
- | When specifying a custom class, make sure it implements the interface:
- |
- | \Stevebauman\Purify\Definitions\Definition
- |
- | Note that these definitions are applied to every Purifier instance.
- |
- | Documentation: http://htmlpurifier.org/docs/enduser-customize.html
- |
- */
-
- 'definitions' => Html5Definition::class,
-
- /*
- |--------------------------------------------------------------------------
- | HTMLPurifier CSS definitions
- |--------------------------------------------------------------------------
- |
- | Here you may specify a class that augments the CSS definitions used by
- | HTMLPurifier. When specifying a custom class, make sure it implements
- | the interface:
- |
- | \Stevebauman\Purify\Definitions\CssDefinition
- |
- | Note that these definitions are applied to every Purifier instance.
- |
- | CSS should be extending $definition->info['css-attribute'] = values
- | See HTMLPurifier_CSSDefinition for further explanation
- |
- */
-
- 'css-definitions' => null,
-
- /*
- |--------------------------------------------------------------------------
- | Serializer
- |--------------------------------------------------------------------------
- |
- | The storage implementation where HTMLPurifier can store its serializer files.
- | If the filesystem cache is in use, the path must be writable through the
- | storage disk by the web server, otherwise an exception will be thrown.
- |
- */
-
- 'serializer' => [
- 'driver' => env('CACHE_STORE', env('CACHE_DRIVER', 'file')),
- 'cache' => \Stevebauman\Purify\Cache\CacheDefinitionCache::class,
- ],
-
- // 'serializer' => [
- // 'disk' => env('FILESYSTEM_DISK', 'local'),
- // 'path' => 'purify',
- // 'cache' => \Stevebauman\Purify\Cache\FilesystemDefinitionCache::class,
- // ],
-
-];
diff --git a/config/queue.php b/config/queue.php
index a46085a9f9..116bd8d002 100644
--- a/config/queue.php
+++ b/config/queue.php
@@ -7,22 +7,22 @@ return [
| Default Queue Connection Name
|--------------------------------------------------------------------------
|
- | Laravel's queue API supports an assortment of back-ends via a single
- | API, giving you convenient access to each back-end using the same
- | syntax for every one. Here you may define a default connection.
+ | Laravel's queue supports a variety of backends via a single, unified
+ | API, giving you convenient access to each backend using identical
+ | syntax for each. The default queue connection is defined below.
|
*/
- 'default' => env('QUEUE_CONNECTION', 'redis'),
+ 'default' => env('QUEUE_CONNECTION', 'database'),
/*
|--------------------------------------------------------------------------
| Queue Connections
|--------------------------------------------------------------------------
|
- | Here you may configure the connection information for each server that
- | is used by your application. A default configuration has been added
- | for each back-end shipped with Laravel. You are free to add more.
+ | Here you may configure the connection options for every queue backend
+ | used by your application. An example configuration is provided for
+ | each backend supported by Laravel. You're also free to add more.
|
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
@@ -33,19 +33,21 @@ return [
'sync' => [
'driver' => 'sync',
],
+
'database' => [
'driver' => 'database',
- 'table' => 'jobs',
- 'queue' => 'default',
- 'retry_after' => 90,
+ 'connection' => env('DB_QUEUE_CONNECTION'),
+ 'table' => env('DB_QUEUE_TABLE', 'jobs'),
+ 'queue' => env('DB_QUEUE', 'default'),
+ 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90),
'after_commit' => false,
],
'beanstalkd' => [
'driver' => 'beanstalkd',
- 'host' => 'localhost',
- 'queue' => 'default',
- 'retry_after' => 90,
+ 'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'),
+ 'queue' => env('BEANSTALKD_QUEUE', 'default'),
+ 'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90),
'block_for' => 0,
'after_commit' => false,
],
@@ -63,29 +65,47 @@ return [
'redis' => [
'driver' => 'redis',
- 'connection' => 'default',
+ 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
'queue' => env('REDIS_QUEUE', 'default'),
- 'retry_after' => 86400,
+ 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90),
'block_for' => null,
- 'after_commit' => true,
+ 'after_commit' => false,
],
],
+ /*
+ |--------------------------------------------------------------------------
+ | Job Batching
+ |--------------------------------------------------------------------------
+ |
+ | The following options configure the database and table that store job
+ | batching information. These options can be updated to any database
+ | connection and table which has been defined by your application.
+ |
+ */
+
+ 'batching' => [
+ 'database' => env('DB_CONNECTION', 'sqlite'),
+ 'table' => 'job_batches',
+ ],
+
/*
|--------------------------------------------------------------------------
| Failed Queue Jobs
|--------------------------------------------------------------------------
|
| These options configure the behavior of failed queue job logging so you
- | can control which database and table are used to store the jobs that
- | have failed. You may change them to any database / table you wish.
+ | can control how and where failed jobs are stored. Laravel ships with
+ | support for storing failed jobs in a simple file or in a database.
+ |
+ | Supported drivers: "database-uuids", "dynamodb", "file", "null"
|
*/
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
- 'database' => env('DB_CONNECTION', 'pgsql'),
+ 'database' => env('DB_CONNECTION', 'sqlite'),
'table' => 'failed_jobs',
],
diff --git a/config/ray.php b/config/ray.php
deleted file mode 100644
index 08598c4e8c..0000000000
--- a/config/ray.php
+++ /dev/null
@@ -1,108 +0,0 @@
- env('RAY_ENABLED', true),
-
- /*
- * When enabled, all cache events will automatically be sent to Ray.
- */
- 'send_cache_to_ray' => env('SEND_CACHE_TO_RAY', false),
-
- /*
- * When enabled, all things passed to `dump` or `dd`
- * will be sent to Ray as well.
- */
- 'send_dumps_to_ray' => env('SEND_DUMPS_TO_RAY', true),
-
- /*
- * When enabled all job events will automatically be sent to Ray.
- */
- 'send_jobs_to_ray' => env('SEND_JOBS_TO_RAY', false),
-
- /*
- * When enabled, all things logged to the application log
- * will be sent to Ray as well.
- */
- 'send_log_calls_to_ray' => env('SEND_LOG_CALLS_TO_RAY', true),
-
- /*
- * When enabled, all queries will automatically be sent to Ray.
- */
- 'send_queries_to_ray' => env('SEND_QUERIES_TO_RAY', false),
-
- /**
- * When enabled, all duplicate queries will automatically be sent to Ray.
- */
- 'send_duplicate_queries_to_ray' => env('SEND_DUPLICATE_QUERIES_TO_RAY', false),
-
- /*
- * When enabled, slow queries will automatically be sent to Ray.
- */
- 'send_slow_queries_to_ray' => env('SEND_SLOW_QUERIES_TO_RAY', false),
-
- /**
- * Queries that are longer than this number of milliseconds will be regarded as slow.
- */
- 'slow_query_threshold_in_ms' => env('RAY_SLOW_QUERY_THRESHOLD_IN_MS', 500),
-
- /*
- * When enabled, all requests made to this app will automatically be sent to Ray.
- */
- 'send_requests_to_ray' => env('SEND_REQUESTS_TO_RAY', false),
-
- /**
- * When enabled, all Http Client requests made by this app will be automatically sent to Ray.
- */
- 'send_http_client_requests_to_ray' => env('SEND_HTTP_CLIENT_REQUESTS_TO_RAY', false),
-
- /*
- * When enabled, all views that are rendered automatically be sent to Ray.
- */
- 'send_views_to_ray' => env('SEND_VIEWS_TO_RAY', false),
-
- /*
- * When enabled, all exceptions will be automatically sent to Ray.
- */
- 'send_exceptions_to_ray' => env('SEND_EXCEPTIONS_TO_RAY', true),
-
- /*
- * When enabled, all deprecation notices will be automatically sent to Ray.
- */
- 'send_deprecated_notices_to_ray' => env('SEND_DEPRECATED_NOTICES_TO_RAY', false),
-
- /*
- * The host used to communicate with the Ray app.
- * When using Docker on Mac or Windows, you can replace localhost with 'host.docker.internal'
- * When using Docker on Linux, you can replace localhost with '172.17.0.1'
- * When using Homestead with the VirtualBox provider, you can replace localhost with '10.0.2.2'
- * When using Homestead with the Parallels provider, you can replace localhost with '10.211.55.2'
- */
- 'host' => env('RAY_HOST', 'host.docker.internal'),
-
- /*
- * The port number used to communicate with the Ray app.
- */
- 'port' => env('RAY_PORT', 23517),
-
- /*
- * Absolute base path for your sites or projects in Homestead,
- * Vagrant, Docker, or another remote development server.
- */
- 'remote_path' => env('RAY_REMOTE_PATH', null),
-
- /*
- * Absolute base path for your sites or projects on your local
- * computer where your IDE or code editor is running on.
- */
- 'local_path' => env('RAY_LOCAL_PATH', null),
-
- /*
- * When this setting is enabled, the package will not try to format values sent to Ray.
- */
- 'always_send_raw_values' => false,
-];
diff --git a/config/redoc.php b/config/redoc.php
deleted file mode 100644
index 439e93e7b6..0000000000
--- a/config/redoc.php
+++ /dev/null
@@ -1,28 +0,0 @@
- '',
-
- /*
- |--------------------------------------------------------------------------
- | Variables
- |--------------------------------------------------------------------------
- |
- | You can automatically replace variables in your OpenAPI definitions by
- | adding a key value pair to the array below. This will replace any
- | instances of :key with the given value.
- |
- */
-
- 'variables' => [],
-
-];
diff --git a/config/sanctum.php b/config/sanctum.php
deleted file mode 100644
index f1e5fc0e51..0000000000
--- a/config/sanctum.php
+++ /dev/null
@@ -1,68 +0,0 @@
- explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
- '%s%s',
- 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
- Sanctum::currentApplicationUrlWithPort()
- ))),
-
- /*
- |--------------------------------------------------------------------------
- | Sanctum Guards
- |--------------------------------------------------------------------------
- |
- | This array contains the authentication guards that will be checked when
- | Sanctum is trying to authenticate a request. If none of these guards
- | are able to authenticate the request, Sanctum will use the bearer
- | token that's present on an incoming request for authentication.
- |
- */
-
- 'guard' => ['web'],
-
- /*
- |--------------------------------------------------------------------------
- | Expiration Minutes
- |--------------------------------------------------------------------------
- |
- | This value controls the number of minutes until an issued token will be
- | considered expired. If this value is null, personal access tokens do
- | not expire. This won't tweak the lifetime of first-party sessions.
- |
- */
-
- 'expiration' => null,
-
- /*
- |--------------------------------------------------------------------------
- | Sanctum Middleware
- |--------------------------------------------------------------------------
- |
- | When authenticating your first-party SPA with Sanctum you may need to
- | customize some of the middleware Sanctum uses while processing the
- | request. You may change the middleware listed below as required.
- |
- */
-
- 'middleware' => [
- 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
- 'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
- 'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
- ],
-
-];
diff --git a/config/sentry.php b/config/sentry.php
deleted file mode 100644
index 0efb4a0e2b..0000000000
--- a/config/sentry.php
+++ /dev/null
@@ -1,85 +0,0 @@
- config('constants.sentry.sentry_dsn'),
-
- // The release version of your application
- // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
- 'release' => config('constants.coolify.version'),
-
- // When left empty or `null` the Laravel environment will be used
- 'environment' => config('app.env'),
-
- 'breadcrumbs' => [
- // Capture Laravel logs in breadcrumbs
- 'logs' => true,
-
- // Capture Laravel cache events in breadcrumbs
- 'cache' => true,
-
- // Capture Livewire components in breadcrumbs
- 'livewire' => true,
-
- // Capture SQL queries in breadcrumbs
- 'sql_queries' => true,
-
- // Capture bindings on SQL queries logged in breadcrumbs
- 'sql_bindings' => true,
-
- // Capture queue job information in breadcrumbs
- 'queue_info' => true,
-
- // Capture command information in breadcrumbs
- 'command_info' => true,
-
- // Capture HTTP client requests information in breadcrumbs
- 'http_client_requests' => true,
- ],
-
- 'tracing' => [
- // Trace queue jobs as their own transactions
- 'queue_job_transactions' => env('SENTRY_TRACE_QUEUE_ENABLED', false),
-
- // Capture queue jobs as spans when executed on the sync driver
- 'queue_jobs' => true,
-
- // Capture SQL queries as spans
- 'sql_queries' => true,
-
- // Try to find out where the SQL query originated from and add it to the query spans
- 'sql_origin' => true,
-
- // Capture views as spans
- 'views' => true,
-
- // Capture Livewire components as spans
- 'livewire' => true,
-
- // Capture HTTP client requests as spans
- 'http_client_requests' => true,
-
- // Capture Redis operations as spans (this enables Redis events in Laravel)
- 'redis_commands' => env('SENTRY_TRACE_REDIS_COMMANDS', false),
-
- // Try to find out where the Redis command originated from and add it to the command spans
- 'redis_origin' => true,
-
- // Indicates if the tracing integrations supplied by Sentry should be loaded
- 'default_integrations' => true,
-
- // Indicates that requests without a matching route should be traced
- 'missing_routes' => false,
- ],
-
- // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send-default-pii
- 'send_default_pii' => env('SENTRY_SEND_DEFAULT_PII', false),
-
- // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#traces-sample-rate
- 'enable_tracing' => env('SENTRY_ENABLE_TRACING', false),
- 'traces_sample_rate' => 0.2,
-
- 'profiles_sample_rate' => env('SENTRY_PROFILES_SAMPLE_RATE') === null ? null : (float) env('SENTRY_PROFILES_SAMPLE_RATE'),
-
-];
diff --git a/config/services.php b/config/services.php
index d1c4a36995..27a36175f8 100644
--- a/config/services.php
+++ b/config/services.php
@@ -14,13 +14,6 @@ return [
|
*/
- 'mailgun' => [
- 'domain' => env('MAILGUN_DOMAIN'),
- 'secret' => env('MAILGUN_SECRET'),
- 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
- 'scheme' => 'https',
- ],
-
'postmark' => [
'token' => env('POSTMARK_TOKEN'),
],
@@ -31,26 +24,15 @@ return [
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
- 'azure' => [
- 'client_id' => env('AZURE_CLIENT_ID'),
- 'client_secret' => env('AZURE_CLIENT_SECRET'),
- 'redirect' => env('AZURE_REDIRECT_URI'),
- 'tenant' => env('AZURE_TENANT_ID'),
- 'proxy' => env('AZURE_PROXY'),
+ 'resend' => [
+ 'key' => env('RESEND_KEY'),
],
- 'authentik' => [
- 'base_url' => env('AUTHENTIK_BASE_URL'),
- 'client_id' => env('AUTHENTIK_CLIENT_ID'),
- 'client_secret' => env('AUTHENTIK_CLIENT_SECRET'),
- 'redirect' => env('AUTHENTIK_REDIRECT_URI'),
- ],
-
- 'google' => [
- 'client_id' => env('GOOGLE_CLIENT_ID'),
- 'client_secret' => env('GOOGLE_CLIENT_SECRET'),
- 'redirect' => env('GOOGLE_REDIRECT_URI'),
- 'tenant' => env('GOOGLE_TENANT'),
+ 'slack' => [
+ 'notifications' => [
+ 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
+ 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
+ ],
],
];
diff --git a/config/session.php b/config/session.php
index 44ca7ded90..ba0aa60b07 100644
--- a/config/session.php
+++ b/config/session.php
@@ -9,9 +9,9 @@ return [
| Default Session Driver
|--------------------------------------------------------------------------
|
- | This option controls the default session "driver" that will be used on
- | requests. By default, we will use the lightweight native driver but
- | you may specify any of the other wonderful drivers provided here.
+ | This option determines the default session driver that is utilized for
+ | incoming requests. Laravel supports a variety of storage options to
+ | persist session data. Database storage is a great default choice.
|
| Supported: "file", "cookie", "database", "apc",
| "memcached", "redis", "dynamodb", "array"
@@ -27,13 +27,14 @@ return [
|
| Here you may specify the number of minutes that you wish the session
| to be allowed to remain idle before it expires. If you want them
- | to immediately expire on the browser closing, set that option.
+ | to expire immediately when the browser is closed then you may
+ | indicate that via the expire_on_close configuration option.
|
*/
- 'lifetime' => env('SESSION_LIFETIME', 10080),
+ 'lifetime' => (int) env('SESSION_LIFETIME', 120),
- 'expire_on_close' => false,
+ 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false),
/*
|--------------------------------------------------------------------------
@@ -41,21 +42,21 @@ return [
|--------------------------------------------------------------------------
|
| This option allows you to easily specify that all of your session data
- | should be encrypted before it is stored. All encryption will be run
- | automatically by Laravel and you can use the Session like normal.
+ | should be encrypted before it's stored. All encryption is performed
+ | automatically by Laravel and you may use the session like normal.
|
*/
- 'encrypt' => true,
+ 'encrypt' => env('SESSION_ENCRYPT', false),
/*
|--------------------------------------------------------------------------
| Session File Location
|--------------------------------------------------------------------------
|
- | When using the native session driver, we need a location where session
- | files may be stored. A default has been set for you but a different
- | location may be specified. This is only needed for file sessions.
+ | When utilizing the "file" session driver, the session files are placed
+ | on disk. The default storage location is defined here; however, you
+ | are free to provide another location where they should be stored.
|
*/
@@ -79,22 +80,22 @@ return [
| Session Database Table
|--------------------------------------------------------------------------
|
- | When using the "database" session driver, you may specify the table we
- | should use to manage the sessions. Of course, a sensible default is
- | provided for you; however, you are free to change this as needed.
+ | When using the "database" session driver, you may specify the table to
+ | be used to store sessions. Of course, a sensible default is defined
+ | for you; however, you're welcome to change this to another table.
|
*/
- 'table' => 'sessions',
+ 'table' => env('SESSION_TABLE', 'sessions'),
/*
|--------------------------------------------------------------------------
| Session Cache Store
|--------------------------------------------------------------------------
|
- | While using one of the framework's cache driven session backends you may
- | list a cache store that should be used for these sessions. This value
- | must match with one of the application's configured cache "stores".
+ | When using one of the framework's cache driven session backends, you may
+ | define the cache store which should be used to store the session data
+ | between requests. This must match one of your defined cache stores.
|
| Affects: "apc", "dynamodb", "memcached", "redis"
|
@@ -120,9 +121,9 @@ return [
| Session Cookie Name
|--------------------------------------------------------------------------
|
- | Here you may change the name of the cookie used to identify a session
- | instance by ID. The name specified here will get used every time a
- | new session cookie is created by the framework for every driver.
+ | Here you may change the name of the session cookie that is created by
+ | the framework. Typically, you should not need to change this value
+ | since doing so does not grant a meaningful security improvement.
|
*/
@@ -138,20 +139,20 @@ return [
|
| The session cookie path determines the path for which the cookie will
| be regarded as available. Typically, this will be the root path of
- | your application but you are free to change this when necessary.
+ | your application, but you're free to change this when necessary.
|
*/
- 'path' => '/',
+ 'path' => env('SESSION_PATH', '/'),
/*
|--------------------------------------------------------------------------
| Session Cookie Domain
|--------------------------------------------------------------------------
|
- | Here you may change the domain of the cookie used to identify a session
- | in your application. This will determine which domains the cookie is
- | available to in your application. A sensible default has been set.
+ | This value determines the domain and subdomains the session cookie is
+ | available to. By default, the cookie will be available to the root
+ | domain and all subdomains. Typically, this shouldn't be changed.
|
*/
@@ -177,11 +178,11 @@ return [
|
| Setting this value to true will prevent JavaScript from accessing the
| value of the cookie and the cookie will only be accessible through
- | the HTTP protocol. You are free to modify this option if needed.
+ | the HTTP protocol. It's unlikely you should disable this option.
|
*/
- 'http_only' => true,
+ 'http_only' => env('SESSION_HTTP_ONLY', true),
/*
|--------------------------------------------------------------------------
@@ -190,12 +191,27 @@ return [
|
| This option determines how your cookies behave when cross-site requests
| take place, and can be used to mitigate CSRF attacks. By default, we
- | will set this value to "lax" since this is a secure default value.
+ | will set this value to "lax" to permit secure cross-site requests.
+ |
+ | See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value
|
| Supported: "lax", "strict", "none", null
|
*/
- 'same_site' => 'lax',
+ 'same_site' => env('SESSION_SAME_SITE', 'lax'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Partitioned Cookies
+ |--------------------------------------------------------------------------
+ |
+ | Setting this value to true will tie the cookie to the top-level site for
+ | a cross-site context. Partitioned cookies are accepted by the browser
+ | when flagged "secure" and the Same-Site attribute is set to "none".
+ |
+ */
+
+ 'partitioned' => env('SESSION_PARTITIONED_COOKIE', false),
];
diff --git a/config/subscription.php b/config/subscription.php
deleted file mode 100644
index a033862d26..0000000000
--- a/config/subscription.php
+++ /dev/null
@@ -1,12 +0,0 @@
- env('SUBSCRIPTION_PROVIDER', null), // stripe
-
- // Stripe
- 'stripe_api_key' => env('STRIPE_API_KEY', null),
- 'stripe_webhook_secret' => env('STRIPE_WEBHOOK_SECRET', null),
- 'stripe_excluded_plans' => env('STRIPE_EXCLUDED_PLANS', null),
- 'stripe_price_id_dynamic_monthly' => env('STRIPE_PRICE_ID_DYNAMIC_MONTHLY', null),
- 'stripe_price_id_dynamic_yearly' => env('STRIPE_PRICE_ID_DYNAMIC_YEARLY', null),
-];
diff --git a/config/telescope.php b/config/telescope.php
deleted file mode 100644
index c940bec8a8..0000000000
--- a/config/telescope.php
+++ /dev/null
@@ -1,205 +0,0 @@
- env('TELESCOPE_ENABLED', false),
-
- /*
- |--------------------------------------------------------------------------
- | Telescope Domain
- |--------------------------------------------------------------------------
- |
- | This is the subdomain where Telescope will be accessible from. If the
- | setting is null, Telescope will reside under the same domain as the
- | application. Otherwise, this value will be used as the subdomain.
- |
- */
-
- 'domain' => env('TELESCOPE_DOMAIN'),
-
- /*
- |--------------------------------------------------------------------------
- | Telescope Path
- |--------------------------------------------------------------------------
- |
- | This is the URI path where Telescope will be accessible from. Feel free
- | to change this path to anything you like. Note that the URI will not
- | affect the paths of its internal API that aren't exposed to users.
- |
- */
-
- 'path' => env('TELESCOPE_PATH', 'telescope'),
-
- /*
- |--------------------------------------------------------------------------
- | Telescope Storage Driver
- |--------------------------------------------------------------------------
- |
- | This configuration options determines the storage driver that will
- | be used to store Telescope's data. In addition, you may set any
- | custom options as needed by the particular driver you choose.
- |
- */
-
- 'driver' => env('TELESCOPE_DRIVER', 'database'),
-
- 'storage' => [
- 'database' => [
- 'connection' => env('DB_CONNECTION', 'pgsql'),
- 'chunk' => 1000,
- ],
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Telescope Queue
- |--------------------------------------------------------------------------
- |
- | This configuration options determines the queue connection and queue
- | which will be used to process ProcessPendingUpdate jobs. This can
- | be changed if you would prefer to use a non-default connection.
- |
- */
-
- 'queue' => [
- 'connection' => env('TELESCOPE_QUEUE_CONNECTION', 'redis'),
- 'queue' => env('TELESCOPE_QUEUE', 'default'),
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Telescope Route Middleware
- |--------------------------------------------------------------------------
- |
- | These middleware will be assigned to every Telescope route, giving you
- | the chance to add your own middleware to this list or change any of
- | the existing middleware. Or, you can simply stick with this list.
- |
- */
-
- 'middleware' => [
- 'web',
- Authorize::class,
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Allowed / Ignored Paths & Commands
- |--------------------------------------------------------------------------
- |
- | The following array lists the URI paths and Artisan commands that will
- | not be watched by Telescope. In addition to this list, some Laravel
- | commands, like migrations and queue commands, are always ignored.
- |
- */
-
- 'only_paths' => [
- // 'api/*'
- ],
-
- 'ignore_paths' => [
- 'livewire*',
- 'nova-api*',
- 'pulse*',
- ],
-
- 'ignore_commands' => [
- //
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Telescope Watchers
- |--------------------------------------------------------------------------
- |
- | The following array lists the "watchers" that will be registered with
- | Telescope. The watchers gather the application's profile data when
- | a request or task is executed. Feel free to customize this list.
- |
- */
-
- 'watchers' => [
- Watchers\BatchWatcher::class => env('TELESCOPE_BATCH_WATCHER', true),
-
- Watchers\CacheWatcher::class => [
- 'enabled' => env('TELESCOPE_CACHE_WATCHER', true),
- 'hidden' => [],
- ],
-
- Watchers\ClientRequestWatcher::class => env('TELESCOPE_CLIENT_REQUEST_WATCHER', true),
-
- Watchers\CommandWatcher::class => [
- 'enabled' => env('TELESCOPE_COMMAND_WATCHER', true),
- 'ignore' => [],
- ],
-
- Watchers\DumpWatcher::class => [
- 'enabled' => env('TELESCOPE_DUMP_WATCHER', true),
- 'always' => env('TELESCOPE_DUMP_WATCHER_ALWAYS', false),
- ],
-
- Watchers\EventWatcher::class => [
- 'enabled' => env('TELESCOPE_EVENT_WATCHER', true),
- 'ignore' => [],
- ],
-
- Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true),
-
- Watchers\GateWatcher::class => [
- 'enabled' => env('TELESCOPE_GATE_WATCHER', true),
- 'ignore_abilities' => [],
- 'ignore_packages' => true,
- 'ignore_paths' => [],
- ],
-
- Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true),
-
- Watchers\LogWatcher::class => [
- 'enabled' => env('TELESCOPE_LOG_WATCHER', true),
- 'level' => 'error',
- ],
-
- Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true),
-
- Watchers\ModelWatcher::class => [
- 'enabled' => env('TELESCOPE_MODEL_WATCHER', true),
- 'events' => ['eloquent.*'],
- 'hydrations' => true,
- ],
-
- Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true),
-
- Watchers\QueryWatcher::class => [
- 'enabled' => env('TELESCOPE_QUERY_WATCHER', true),
- 'ignore_packages' => true,
- 'ignore_paths' => [],
- 'slow' => 100,
- ],
-
- Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true),
-
- Watchers\RequestWatcher::class => [
- 'enabled' => env('TELESCOPE_REQUEST_WATCHER', true),
- 'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64),
- 'ignore_http_methods' => [],
- 'ignore_status_codes' => [],
- ],
-
- Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true),
- Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true),
- ],
-];
diff --git a/config/testing.php b/config/testing.php
deleted file mode 100644
index 41b8eadf01..0000000000
--- a/config/testing.php
+++ /dev/null
@@ -1,6 +0,0 @@
- env('DUSK_TEST_EMAIL', 'test@example.com'),
- 'dusk_test_password' => env('DUSK_TEST_PASSWORD', 'password'),
-];
diff --git a/config/view.php b/config/view.php
deleted file mode 100644
index 22b8a18d32..0000000000
--- a/config/view.php
+++ /dev/null
@@ -1,36 +0,0 @@
- [
- resource_path('views'),
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Compiled View Path
- |--------------------------------------------------------------------------
- |
- | This option determines where all the compiled Blade templates will be
- | stored for your application. Typically, this is within the storage
- | directory. However, as usual, you are free to change this value.
- |
- */
-
- 'compiled' => env(
- 'VIEW_COMPILED_PATH',
- realpath(storage_path('framework/views'))
- ),
-
-];
diff --git a/database/.gitignore b/database/.gitignore
deleted file mode 100644
index 9b19b93c9f..0000000000
--- a/database/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.sqlite*
diff --git a/database/factories/ApplicationFactory.php b/database/factories/ApplicationFactory.php
deleted file mode 100644
index ded507c56d..0000000000
--- a/database/factories/ApplicationFactory.php
+++ /dev/null
@@ -1,22 +0,0 @@
- fake()->unique()->name(),
- 'destination_id' => 1,
- 'git_repository' => fake()->url(),
- 'git_branch' => fake()->word(),
- 'build_pack' => 'nixpacks',
- 'ports_exposes' => '3000',
- 'environment_id' => 1,
- 'destination_id' => 1,
- ];
- }
-}
diff --git a/database/factories/ServerFactory.php b/database/factories/ServerFactory.php
deleted file mode 100644
index 29546bf565..0000000000
--- a/database/factories/ServerFactory.php
+++ /dev/null
@@ -1,17 +0,0 @@
- fake()->unique()->name(),
- 'ip' => fake()->unique()->ipv4(),
- 'private_key_id' => 1,
- ];
- }
-}
diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php
deleted file mode 100644
index 31ddf87205..0000000000
--- a/database/factories/UserFactory.php
+++ /dev/null
@@ -1,37 +0,0 @@
-
- */
-class UserFactory extends Factory
-{
- /**
- * Define the model's default state.
- *
- * @return array
- */
- public function definition(): array
- {
- return [
- 'email' => fake()->unique()->safeEmail(),
- 'email_verified_at' => now(),
- 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
- 'remember_token' => Str::random(10),
- ];
- }
-
- /**
- * Indicate that the model's email address should be unverified.
- */
- public function unverified(): static
- {
- return $this->state(fn (array $attributes) => [
- 'email_verified_at' => null,
- ]);
- }
-}
diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php
deleted file mode 100644
index 321128a8f4..0000000000
--- a/database/migrations/2014_10_12_000000_create_users_table.php
+++ /dev/null
@@ -1,32 +0,0 @@
-id();
- $table->string('name')->default('Anonymous');
- $table->string('email')->unique();
- $table->timestamp('email_verified_at')->nullable();
- $table->string('password');
- $table->rememberToken();
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('users');
- }
-};
diff --git a/database/migrations/2014_10_12_100000_create_password_reset_tokens_table.php b/database/migrations/2014_10_12_100000_create_password_reset_tokens_table.php
deleted file mode 100644
index 81a7229b08..0000000000
--- a/database/migrations/2014_10_12_100000_create_password_reset_tokens_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('email')->primary();
- $table->string('token');
- $table->timestamp('created_at')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('password_reset_tokens');
- }
-};
diff --git a/database/migrations/2014_10_12_200000_add_two_factor_columns_to_users_table.php b/database/migrations/2014_10_12_200000_add_two_factor_columns_to_users_table.php
deleted file mode 100644
index b490e24f5a..0000000000
--- a/database/migrations/2014_10_12_200000_add_two_factor_columns_to_users_table.php
+++ /dev/null
@@ -1,46 +0,0 @@
-text('two_factor_secret')
- ->after('password')
- ->nullable();
-
- $table->text('two_factor_recovery_codes')
- ->after('two_factor_secret')
- ->nullable();
-
- if (Fortify::confirmsTwoFactorAuthentication()) {
- $table->timestamp('two_factor_confirmed_at')
- ->after('two_factor_recovery_codes')
- ->nullable();
- }
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('users', function (Blueprint $table) {
- $table->dropColumn(array_merge([
- 'two_factor_secret',
- 'two_factor_recovery_codes',
- ], Fortify::confirmsTwoFactorAuthentication() ? [
- 'two_factor_confirmed_at',
- ] : []));
- });
- }
-};
diff --git a/database/migrations/2018_08_08_100000_create_telescope_entries_table.php b/database/migrations/2018_08_08_100000_create_telescope_entries_table.php
deleted file mode 100644
index 700a83f095..0000000000
--- a/database/migrations/2018_08_08_100000_create_telescope_entries_table.php
+++ /dev/null
@@ -1,70 +0,0 @@
-getConnection());
-
- $schema->create('telescope_entries', function (Blueprint $table) {
- $table->bigIncrements('sequence');
- $table->uuid('uuid');
- $table->uuid('batch_id');
- $table->string('family_hash')->nullable();
- $table->boolean('should_display_on_index')->default(true);
- $table->string('type', 20);
- $table->longText('content');
- $table->dateTime('created_at')->nullable();
-
- $table->unique('uuid');
- $table->index('batch_id');
- $table->index('family_hash');
- $table->index('created_at');
- $table->index(['type', 'should_display_on_index']);
- });
-
- $schema->create('telescope_entries_tags', function (Blueprint $table) {
- $table->uuid('entry_uuid');
- $table->string('tag');
-
- $table->primary(['entry_uuid', 'tag']);
- $table->index('tag');
-
- $table->foreign('entry_uuid')
- ->references('uuid')
- ->on('telescope_entries')
- ->onDelete('cascade');
- });
-
- $schema->create('telescope_monitoring', function (Blueprint $table) {
- $table->string('tag')->primary();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- $schema = Schema::connection($this->getConnection());
-
- $schema->dropIfExists('telescope_entries_tags');
- $schema->dropIfExists('telescope_entries');
- $schema->dropIfExists('telescope_monitoring');
- }
-};
diff --git a/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php b/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php
deleted file mode 100644
index 954f7518f5..0000000000
--- a/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php
+++ /dev/null
@@ -1,34 +0,0 @@
-id();
- $table->morphs('tokenable');
- $table->string('name');
- $table->string('token', 64)->unique();
- $table->string('team_id');
- $table->text('abilities')->nullable();
- $table->timestamp('last_used_at')->nullable();
- $table->timestamp('expires_at')->nullable();
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('personal_access_tokens');
- }
-};
diff --git a/database/migrations/2023_03_20_112410_create_activity_log_table.php b/database/migrations/2023_03_20_112410_create_activity_log_table.php
deleted file mode 100755
index c94274b315..0000000000
--- a/database/migrations/2023_03_20_112410_create_activity_log_table.php
+++ /dev/null
@@ -1,27 +0,0 @@
-create(config('activitylog.table_name'), function (Blueprint $table) {
- $table->id();
- $table->string('log_name')->nullable();
- $table->text('description');
- $table->nullableMorphs('subject', 'subject');
- $table->nullableMorphs('causer', 'causer');
- $table->json('properties')->nullable();
- $table->timestamps();
- $table->index('log_name');
- });
- }
-
- public function down()
- {
- Schema::connection(config('activitylog.database_connection'))->dropIfExists(config('activitylog.table_name'));
- }
-}
diff --git a/database/migrations/2023_03_20_112411_add_event_column_to_activity_log_table.php b/database/migrations/2023_03_20_112411_add_event_column_to_activity_log_table.php
deleted file mode 100755
index 78d9a0e0ae..0000000000
--- a/database/migrations/2023_03_20_112411_add_event_column_to_activity_log_table.php
+++ /dev/null
@@ -1,22 +0,0 @@
-table(config('activitylog.table_name'), function (Blueprint $table) {
- $table->string('event')->nullable()->after('subject_type');
- });
- }
-
- public function down()
- {
- Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) {
- $table->dropColumn('event');
- });
- }
-}
diff --git a/database/migrations/2023_03_20_112412_add_batch_uuid_column_to_activity_log_table.php b/database/migrations/2023_03_20_112412_add_batch_uuid_column_to_activity_log_table.php
deleted file mode 100755
index 320ef5ccec..0000000000
--- a/database/migrations/2023_03_20_112412_add_batch_uuid_column_to_activity_log_table.php
+++ /dev/null
@@ -1,22 +0,0 @@
-table(config('activitylog.table_name'), function (Blueprint $table) {
- $table->uuid('batch_uuid')->nullable()->after('properties');
- });
- }
-
- public function down()
- {
- Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) {
- $table->dropColumn('batch_uuid');
- });
- }
-}
diff --git a/database/migrations/2023_03_20_112809_create_sessions_table.php b/database/migrations/2023_03_20_112809_create_sessions_table.php
deleted file mode 100644
index f60625bb57..0000000000
--- a/database/migrations/2023_03_20_112809_create_sessions_table.php
+++ /dev/null
@@ -1,31 +0,0 @@
-string('id')->primary();
- $table->foreignId('user_id')->nullable()->index();
- $table->string('ip_address', 45)->nullable();
- $table->text('user_agent')->nullable();
- $table->longText('payload');
- $table->integer('last_activity')->index();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('sessions');
- }
-};
diff --git a/database/migrations/2023_03_20_112811_create_teams_table.php b/database/migrations/2023_03_20_112811_create_teams_table.php
deleted file mode 100644
index 0f41c5e95d..0000000000
--- a/database/migrations/2023_03_20_112811_create_teams_table.php
+++ /dev/null
@@ -1,34 +0,0 @@
-id();
- $table->string('name');
- $table->string('description')->nullable();
- $table->boolean('personal_team')->default(false);
- $table->schemalessAttributes('smtp');
- $table->schemalessAttributes('smtp_notifications');
- $table->schemalessAttributes('discord');
- $table->schemalessAttributes('discord_notifications');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('teams');
- }
-};
diff --git a/database/migrations/2023_03_20_112812_create_team_user_table.php b/database/migrations/2023_03_20_112812_create_team_user_table.php
deleted file mode 100644
index 9eeeb4b31b..0000000000
--- a/database/migrations/2023_03_20_112812_create_team_user_table.php
+++ /dev/null
@@ -1,32 +0,0 @@
-id();
- $table->foreignId('team_id');
- $table->foreignId('user_id');
- $table->string('role')->default('member');
- $table->timestamps();
-
- $table->unique(['team_id', 'user_id']);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('team_user');
- }
-};
diff --git a/database/migrations/2023_03_20_112813_create_team_invitations_table.php b/database/migrations/2023_03_20_112813_create_team_invitations_table.php
deleted file mode 100644
index 9bce2be922..0000000000
--- a/database/migrations/2023_03_20_112813_create_team_invitations_table.php
+++ /dev/null
@@ -1,35 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->foreignId('team_id')->constrained()->cascadeOnDelete();
- $table->string('email');
- $table->string('role')->default('member');
- $table->string('link');
- $table->string('via')->default('link');
- $table->timestamps();
-
- $table->unique(['team_id', 'email']);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('team_invitations');
- }
-};
diff --git a/database/migrations/2023_03_20_112814_create_instance_settings_table.php b/database/migrations/2023_03_20_112814_create_instance_settings_table.php
deleted file mode 100644
index 51b156ccbf..0000000000
--- a/database/migrations/2023_03_20_112814_create_instance_settings_table.php
+++ /dev/null
@@ -1,38 +0,0 @@
-id();
- $table->string('public_ipv4')->nullable();
- $table->string('public_ipv6')->nullable();
- $table->string('fqdn')->nullable();
- $table->string('wildcard_domain')->nullable();
- $table->string('default_redirect_404')->nullable();
- $table->integer('public_port_min')->default(9000);
- $table->integer('public_port_max')->default(9100);
- $table->boolean('do_not_track')->default(false);
- $table->boolean('is_auto_update_enabled')->default(true);
- $table->boolean('is_registration_enabled')->default(true);
- $table->schemalessAttributes('smtp');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('instance_settings');
- }
-};
diff --git a/database/migrations/2023_03_24_140711_create_servers_table.php b/database/migrations/2023_03_24_140711_create_servers_table.php
deleted file mode 100644
index 0f3bf7419c..0000000000
--- a/database/migrations/2023_03_24_140711_create_servers_table.php
+++ /dev/null
@@ -1,36 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('description')->nullable();
- $table->string('ip');
- $table->integer('port')->default(22);
- $table->string('user')->default('root');
- $table->foreignId('team_id');
- $table->foreignId('private_key_id');
- $table->schemalessAttributes('proxy');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('servers');
- }
-};
diff --git a/database/migrations/2023_03_24_140712_create_server_settings_table.php b/database/migrations/2023_03_24_140712_create_server_settings_table.php
deleted file mode 100644
index a3b1c8b44e..0000000000
--- a/database/migrations/2023_03_24_140712_create_server_settings_table.php
+++ /dev/null
@@ -1,33 +0,0 @@
-id();
- $table->boolean('is_part_of_swarm')->default(false);
- $table->boolean('is_jump_server')->default(false);
- $table->boolean('is_build_server')->default(false);
- $table->boolean('is_reachable')->default(false);
- $table->boolean('is_usable')->default(false);
- $table->foreignId('server_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('server_settings');
- }
-};
diff --git a/database/migrations/2023_03_24_140853_create_private_keys_table.php b/database/migrations/2023_03_24_140853_create_private_keys_table.php
deleted file mode 100644
index 21acf7d058..0000000000
--- a/database/migrations/2023_03_24_140853_create_private_keys_table.php
+++ /dev/null
@@ -1,33 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('description')->nullable();
- $table->longText('private_key');
- $table->boolean('is_git_related')->default(false);
- $table->foreignId('team_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('private_keys');
- }
-};
diff --git a/database/migrations/2023_03_27_075351_create_projects_table.php b/database/migrations/2023_03_27_075351_create_projects_table.php
deleted file mode 100644
index 432496268e..0000000000
--- a/database/migrations/2023_03_27_075351_create_projects_table.php
+++ /dev/null
@@ -1,33 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('description')->nullable();
-
- $table->foreignId('team_id');
-
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('projects');
- }
-};
diff --git a/database/migrations/2023_03_27_075443_create_project_settings_table.php b/database/migrations/2023_03_27_075443_create_project_settings_table.php
deleted file mode 100644
index 35f691ea83..0000000000
--- a/database/migrations/2023_03_27_075443_create_project_settings_table.php
+++ /dev/null
@@ -1,29 +0,0 @@
-id();
- $table->string('wildcard_domain')->nullable();
- $table->foreignId('project_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('project_settings');
- }
-};
diff --git a/database/migrations/2023_03_27_075444_create_environments_table.php b/database/migrations/2023_03_27_075444_create_environments_table.php
deleted file mode 100644
index f9514dcce3..0000000000
--- a/database/migrations/2023_03_27_075444_create_environments_table.php
+++ /dev/null
@@ -1,30 +0,0 @@
-id();
- $table->string('name');
- $table->foreignId('project_id');
- $table->timestamps();
- $table->unique(['name', 'project_id']);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('environments');
- }
-};
diff --git a/database/migrations/2023_03_27_081716_create_applications_table.php b/database/migrations/2023_03_27_081716_create_applications_table.php
deleted file mode 100644
index 3a41a26b20..0000000000
--- a/database/migrations/2023_03_27_081716_create_applications_table.php
+++ /dev/null
@@ -1,85 +0,0 @@
-id();
- $table->integer('repository_project_id')->nullable();
- $table->string('uuid')->unique();
- $table->string('name');
-
- $table->string('fqdn')->unique()->nullable();
- $table->string('config_hash')->nullable();
-
- $table->string('git_repository');
- $table->string('git_branch');
- $table->string('git_commit_sha')->default('HEAD');
- // TODO: remove this column, it is not used
- $table->string('git_full_url')->nullable();
-
- $table->string('docker_registry_image_name')->nullable();
- $table->string('docker_registry_image_tag')->nullable();
-
- $table->string('build_pack');
- $table->string('static_image')->default('nginx:alpine');
-
- $table->string('install_command')->nullable();
- $table->string('build_command')->nullable();
- $table->string('start_command')->nullable();
-
- $table->string('ports_exposes');
- $table->string('ports_mappings')->nullable();
-
- $table->string('base_directory')->default('/');
- $table->string('publish_directory')->nullable();
-
- $table->string('health_check_path')->default('/');
- $table->string('health_check_port')->nullable();
- $table->string('health_check_host')->default('localhost');
- $table->string('health_check_method')->default('GET');
- $table->integer('health_check_return_code')->default(200);
- $table->string('health_check_scheme')->default('http');
- $table->string('health_check_response_text')->nullable();
- $table->integer('health_check_interval')->default(5);
- $table->integer('health_check_timeout')->default(5);
- $table->integer('health_check_retries')->default(10);
- $table->integer('health_check_start_period')->default(5);
-
- $table->string('limits_memory')->default('0');
- $table->string('limits_memory_swap')->default('0');
- $table->integer('limits_memory_swappiness')->default(60);
- $table->string('limits_memory_reservation')->default('0');
-
- $table->string('limits_cpus')->default('0');
- $table->string('limits_cpuset')->nullable()->default('0');
- $table->integer('limits_cpu_shares')->default(1024);
-
- $table->string('status')->default('exited');
- $table->string('preview_url_template')->default('{{pr_id}}.{{domain}}');
-
- $table->nullableMorphs('destination');
- $table->nullableMorphs('source');
-
- $table->foreignId('private_key_id')->nullable();
- $table->foreignId('environment_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('applications');
- }
-};
diff --git a/database/migrations/2023_03_27_081717_create_application_settings_table.php b/database/migrations/2023_03_27_081717_create_application_settings_table.php
deleted file mode 100644
index e13f7f3666..0000000000
--- a/database/migrations/2023_03_27_081717_create_application_settings_table.php
+++ /dev/null
@@ -1,38 +0,0 @@
-id();
- $table->boolean('is_static')->default(false);
- $table->boolean('is_git_submodules_enabled')->default(true);
- $table->boolean('is_git_lfs_enabled')->default(true);
- $table->boolean('is_auto_deploy_enabled')->default(true);
- $table->boolean('is_force_https_enabled')->default(true);
- $table->boolean('is_debug_enabled')->default(false);
- $table->boolean('is_preview_deployments_enabled')->default(false);
- // $table->boolean('is_dual_cert')->default(false);
- // $table->boolean('is_custom_ssl')->default(false);
- // $table->boolean('is_http2')->default(false);
- $table->foreignId('application_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('application_settings');
- }
-};
diff --git a/database/migrations/2023_03_27_081718_create_application_previews_table.php b/database/migrations/2023_03_27_081718_create_application_previews_table.php
deleted file mode 100644
index 66211eee46..0000000000
--- a/database/migrations/2023_03_27_081718_create_application_previews_table.php
+++ /dev/null
@@ -1,36 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->integer('pull_request_id');
- $table->string('pull_request_html_url');
- $table->integer('pull_request_issue_comment_id')->nullable();
-
- $table->string('fqdn')->unique()->nullable();
- $table->string('status')->default('exited');
-
- $table->foreignId('application_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('application_previews');
- }
-};
diff --git a/database/migrations/2023_03_27_083621_create_services_table.php b/database/migrations/2023_03_27_083621_create_services_table.php
deleted file mode 100644
index 12bb77b1ba..0000000000
--- a/database/migrations/2023_03_27_083621_create_services_table.php
+++ /dev/null
@@ -1,33 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
-
- $table->morphs('destination');
-
- $table->foreignId('environment_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('services');
- }
-};
diff --git a/database/migrations/2023_03_27_085020_create_standalone_dockers_table.php b/database/migrations/2023_03_27_085020_create_standalone_dockers_table.php
deleted file mode 100644
index f7f4300994..0000000000
--- a/database/migrations/2023_03_27_085020_create_standalone_dockers_table.php
+++ /dev/null
@@ -1,33 +0,0 @@
-id();
- $table->string('name');
- $table->string('uuid')->unique();
- $table->string('network');
-
- $table->foreignId('server_id');
- $table->unique(['server_id', 'network']);
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('standalone_dockers');
- }
-};
diff --git a/database/migrations/2023_03_27_085022_create_swarm_dockers_table.php b/database/migrations/2023_03_27_085022_create_swarm_dockers_table.php
deleted file mode 100644
index ea85640baa..0000000000
--- a/database/migrations/2023_03_27_085022_create_swarm_dockers_table.php
+++ /dev/null
@@ -1,31 +0,0 @@
-id();
- $table->string('name');
- $table->string('uuid')->unique();
-
- $table->foreignId('server_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('swarm_dockers');
- }
-};
diff --git a/database/migrations/2023_03_28_062150_create_kubernetes_table.php b/database/migrations/2023_03_28_062150_create_kubernetes_table.php
deleted file mode 100644
index 365380e1fc..0000000000
--- a/database/migrations/2023_03_28_062150_create_kubernetes_table.php
+++ /dev/null
@@ -1,29 +0,0 @@
-id();
- $table->string('uuid')->unique();
-
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('kubernetes');
- }
-};
diff --git a/database/migrations/2023_03_28_083723_create_github_apps_table.php b/database/migrations/2023_03_28_083723_create_github_apps_table.php
deleted file mode 100644
index 27f1939125..0000000000
--- a/database/migrations/2023_03_28_083723_create_github_apps_table.php
+++ /dev/null
@@ -1,47 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
-
- $table->string('organization')->nullable();
- $table->string('api_url');
- $table->string('html_url');
- $table->string('custom_user')->default('git');
- $table->integer('custom_port')->default(22);
-
- $table->integer('app_id')->nullable();
- $table->integer('installation_id')->nullable();
- $table->string('client_id')->nullable();
- $table->longText('client_secret')->nullable();
- $table->longText('webhook_secret')->nullable();
-
- $table->boolean('is_system_wide')->default(false);
- $table->boolean('is_public')->default(false);
-
- $table->foreignId('private_key_id')->nullable();
- $table->foreignId('team_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('github_apps');
- }
-};
diff --git a/database/migrations/2023_03_28_083726_create_gitlab_apps_table.php b/database/migrations/2023_03_28_083726_create_gitlab_apps_table.php
deleted file mode 100644
index 24db88d863..0000000000
--- a/database/migrations/2023_03_28_083726_create_gitlab_apps_table.php
+++ /dev/null
@@ -1,49 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
-
- $table->string('organization')->nullable();
- $table->string('api_url');
- $table->string('html_url');
- $table->integer('custom_port')->default(22);
- $table->string('custom_user')->default('git');
- $table->boolean('is_system_wide')->default(false);
- $table->boolean('is_public')->default(false);
-
- $table->integer('app_id')->nullable();
- $table->string('app_secret')->nullable();
- $table->integer('oauth_id')->nullable();
- $table->string('group_name')->nullable();
- $table->longText('public_key')->nullable();
- $table->longText('webhook_token')->nullable();
- $table->integer('deploy_key_id')->nullable();
-
- $table->foreignId('private_key_id')->nullable();
- $table->foreignId('team_id');
-
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('gitlab_apps');
- }
-};
diff --git a/database/migrations/2023_04_03_111012_create_local_persistent_volumes_table.php b/database/migrations/2023_04_03_111012_create_local_persistent_volumes_table.php
deleted file mode 100644
index c3f2a976a9..0000000000
--- a/database/migrations/2023_04_03_111012_create_local_persistent_volumes_table.php
+++ /dev/null
@@ -1,35 +0,0 @@
-id();
- $table->string('name');
- $table->string('mount_path');
- $table->string('host_path')->nullable();
- $table->string('container_id')->nullable();
-
- $table->nullableMorphs('resource');
-
- $table->unique(['name', 'resource_id', 'resource_type']);
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('local_persistent_volumes');
- }
-};
diff --git a/database/migrations/2023_05_04_194548_create_environment_variables_table.php b/database/migrations/2023_05_04_194548_create_environment_variables_table.php
deleted file mode 100644
index 4a03ead55a..0000000000
--- a/database/migrations/2023_05_04_194548_create_environment_variables_table.php
+++ /dev/null
@@ -1,40 +0,0 @@
-id();
-
- $table->string('key');
- $table->string('value')->nullable();
- $table->boolean('is_build_time')->default(false);
- $table->boolean('is_preview')->default(false);
-
- $table->foreignId('application_id')->nullable();
- $table->foreignId('service_id')->nullable();
- $table->foreignId('database_id')->nullable();
-
- $table->unique(['key', 'application_id', 'is_build_time', 'is_preview']);
- $table->unique(['key', 'service_id', 'is_build_time', 'is_preview']);
- $table->unique(['key', 'database_id', 'is_build_time', 'is_preview']);
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('environment_variables');
- }
-};
diff --git a/database/migrations/2023_05_17_104039_create_failed_jobs_table.php b/database/migrations/2023_05_17_104039_create_failed_jobs_table.php
deleted file mode 100644
index 249da8171a..0000000000
--- a/database/migrations/2023_05_17_104039_create_failed_jobs_table.php
+++ /dev/null
@@ -1,32 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->text('connection');
- $table->text('queue');
- $table->longText('payload');
- $table->longText('exception');
- $table->timestamp('failed_at')->useCurrent();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('failed_jobs');
- }
-};
diff --git a/database/migrations/2023_05_24_083426_create_application_deployment_queues_table.php b/database/migrations/2023_05_24_083426_create_application_deployment_queues_table.php
deleted file mode 100644
index 9573b9735e..0000000000
--- a/database/migrations/2023_05_24_083426_create_application_deployment_queues_table.php
+++ /dev/null
@@ -1,34 +0,0 @@
-id();
- $table->string('application_id');
- $table->string('deployment_uuid')->unique();
- $table->integer('pull_request_id')->default(0);
- $table->boolean('force_rebuild')->default(false);
- $table->string('commit')->default('HEAD');
- $table->string('status')->default('queued');
- $table->boolean('is_webhook')->default(false);
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('application_deployment_queues');
- }
-};
diff --git a/database/migrations/2023_06_22_131459_move_wildcard_to_server.php b/database/migrations/2023_06_22_131459_move_wildcard_to_server.php
deleted file mode 100644
index cd258fbea1..0000000000
--- a/database/migrations/2023_06_22_131459_move_wildcard_to_server.php
+++ /dev/null
@@ -1,34 +0,0 @@
-dropColumn('wildcard_domain');
- });
- Schema::table('server_settings', function (Blueprint $table) {
- $table->string('wildcard_domain')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('project_settings', function (Blueprint $table) {
- $table->string('wildcard_domain')->nullable();
- });
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('wildcard_domain');
- });
- }
-};
diff --git a/database/migrations/2023_06_23_084605_remove_wildcard_domain_from_instancesettings.php b/database/migrations/2023_06_23_084605_remove_wildcard_domain_from_instancesettings.php
deleted file mode 100644
index a4260ce1d2..0000000000
--- a/database/migrations/2023_06_23_084605_remove_wildcard_domain_from_instancesettings.php
+++ /dev/null
@@ -1,28 +0,0 @@
-dropColumn('wildcard_domain');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->string('wildcard_domain')->nullable();
- });
- }
-};
diff --git a/database/migrations/2023_06_23_110548_next_channel_updates.php b/database/migrations/2023_06_23_110548_next_channel_updates.php
deleted file mode 100644
index 83c4dacf3d..0000000000
--- a/database/migrations/2023_06_23_110548_next_channel_updates.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('next_channel')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('next_channel');
- });
- }
-};
diff --git a/database/migrations/2023_06_23_114131_change_env_var_value_length.php b/database/migrations/2023_06_23_114131_change_env_var_value_length.php
deleted file mode 100644
index ca8bd1e0ce..0000000000
--- a/database/migrations/2023_06_23_114131_change_env_var_value_length.php
+++ /dev/null
@@ -1,28 +0,0 @@
-text('value')->nullable()->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->string('value')->nullable()->change();
- });
- }
-};
diff --git a/database/migrations/2023_06_23_114132_remove_default_redirect_from_instance_settings.php b/database/migrations/2023_06_23_114132_remove_default_redirect_from_instance_settings.php
deleted file mode 100644
index 9c14b7c398..0000000000
--- a/database/migrations/2023_06_23_114132_remove_default_redirect_from_instance_settings.php
+++ /dev/null
@@ -1,28 +0,0 @@
-dropColumn('default_redirect_404');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->string('default_redirect_404')->nullable();
- });
- }
-};
diff --git a/database/migrations/2023_06_23_114133_use_application_deployment_queues_as_activity.php b/database/migrations/2023_06_23_114133_use_application_deployment_queues_as_activity.php
deleted file mode 100644
index 36623ee7bc..0000000000
--- a/database/migrations/2023_06_23_114133_use_application_deployment_queues_as_activity.php
+++ /dev/null
@@ -1,30 +0,0 @@
-text('logs')->default(null)->nullable();
- $table->string('current_process_id')->default(null)->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('logs');
- $table->dropColumn('current_process_id');
- });
- }
-};
diff --git a/database/migrations/2023_06_23_114134_add_disk_usage_percentage_to_servers.php b/database/migrations/2023_06_23_114134_add_disk_usage_percentage_to_servers.php
deleted file mode 100644
index 79846bb0a3..0000000000
--- a/database/migrations/2023_06_23_114134_add_disk_usage_percentage_to_servers.php
+++ /dev/null
@@ -1,28 +0,0 @@
-integer('cleanup_after_percentage')->default(80);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('cleanup_after_percentage');
- });
- }
-};
diff --git a/database/migrations/2023_07_13_115117_create_subscriptions_table.php b/database/migrations/2023_07_13_115117_create_subscriptions_table.php
deleted file mode 100644
index e24e56555e..0000000000
--- a/database/migrations/2023_07_13_115117_create_subscriptions_table.php
+++ /dev/null
@@ -1,39 +0,0 @@
-id();
- $table->string('lemon_subscription_id');
- $table->string('lemon_order_id');
- $table->string('lemon_product_id');
- $table->string('lemon_variant_id');
- $table->string('lemon_variant_name');
- $table->string('lemon_customer_id');
- $table->string('lemon_status');
- $table->string('lemon_trial_ends_at')->nullable();
- $table->string('lemon_renews_at');
- $table->string('lemon_ends_at')->nullable();
- $table->string('lemon_update_payment_menthod_url');
- $table->foreignId('team_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('subscriptions');
- }
-};
diff --git a/database/migrations/2023_07_13_120719_create_webhooks_table.php b/database/migrations/2023_07_13_120719_create_webhooks_table.php
deleted file mode 100644
index 9376a10c92..0000000000
--- a/database/migrations/2023_07_13_120719_create_webhooks_table.php
+++ /dev/null
@@ -1,31 +0,0 @@
-id();
- $table->enum('status', ['pending', 'success', 'failed'])->default('pending');
- $table->enum('type', ['github', 'gitlab', 'bitbucket', 'lemonsqueezy']);
- $table->longText('payload');
- $table->longText('failure_reason')->nullable();
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('webhooks');
- }
-};
diff --git a/database/migrations/2023_07_13_120721_add_license_to_instance_settings.php b/database/migrations/2023_07_13_120721_add_license_to_instance_settings.php
deleted file mode 100644
index c32cd0f9a5..0000000000
--- a/database/migrations/2023_07_13_120721_add_license_to_instance_settings.php
+++ /dev/null
@@ -1,30 +0,0 @@
-boolean('is_resale_license_active')->default(false);
- $table->longText('resale_license')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('is_resale_license_active');
- $table->dropColumn('resale_license');
- });
- }
-};
diff --git a/database/migrations/2023_07_27_182013_smtp_discord_schemaless_to_normal.php b/database/migrations/2023_07_27_182013_smtp_discord_schemaless_to_normal.php
deleted file mode 100644
index 3e3a90b6d8..0000000000
--- a/database/migrations/2023_07_27_182013_smtp_discord_schemaless_to_normal.php
+++ /dev/null
@@ -1,193 +0,0 @@
-boolean('smtp_enabled')->default(false);
- $table->string('smtp_from_address')->nullable();
- $table->string('smtp_from_name')->nullable();
- $table->string('smtp_recipients')->nullable();
- $table->string('smtp_host')->nullable();
- $table->integer('smtp_port')->nullable();
- $table->string('smtp_encryption')->nullable();
- $table->text('smtp_username')->nullable();
- $table->text('smtp_password')->nullable();
- $table->integer('smtp_timeout')->nullable();
- $table->boolean('smtp_notifications_test')->default(true);
- $table->boolean('smtp_notifications_deployments')->default(false);
- $table->boolean('smtp_notifications_status_changes')->default(false);
-
- $table->boolean('discord_enabled')->default(false);
- $table->string('discord_webhook_url')->nullable();
- $table->boolean('discord_notifications_test')->default(true);
- $table->boolean('discord_notifications_deployments')->default(true);
- $table->boolean('discord_notifications_status_changes')->default(true);
- });
- $teams = Team::all();
- foreach ($teams as $team) {
- $team->smtp_enabled = data_get($team, 'smtp.enabled', false);
- $team->smtp_from_address = data_get($team, 'smtp.from_address');
- $team->smtp_from_name = data_get($team, 'smtp.from_name');
- $team->smtp_recipients = data_get($team, 'smtp.recipients');
- $team->smtp_host = data_get($team, 'smtp.host');
- $team->smtp_port = data_get($team, 'smtp.port');
- $team->smtp_encryption = data_get($team, 'smtp.encryption');
- $team->smtp_username = data_get($team, 'smtp.username');
- $team->smtp_password = data_get($team, 'smtp.password');
- $team->smtp_timeout = data_get($team, 'smtp.timeout');
- $team->smtp_notifications_test = data_get($team, 'smtp_notifications.test', true);
- $team->smtp_notifications_deployments = data_get($team, 'smtp_notifications.deployments', false);
- $team->smtp_notifications_status_changes = data_get($team, 'smtp_notifications.status_changes', false);
-
- $team->discord_enabled = data_get($team, 'discord.enabled', false);
- $team->discord_webhook_url = data_get($team, 'discord.webhook_url');
- $team->discord_notifications_test = data_get($team, 'discord_notifications.test', true);
- $team->discord_notifications_deployments = data_get($team, 'discord_notifications.deployments', true);
- $team->discord_notifications_status_changes = data_get($team, 'discord_notifications.status_changes', true);
-
- $team->save();
- }
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn('smtp');
- $table->dropColumn('smtp_notifications');
- $table->dropColumn('discord');
- $table->dropColumn('discord_notifications');
- });
-
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->boolean('smtp_enabled')->default(false);
- $table->string('smtp_from_address')->nullable();
- $table->string('smtp_from_name')->nullable();
- $table->text('smtp_recipients')->nullable();
- $table->string('smtp_host')->nullable();
- $table->integer('smtp_port')->nullable();
- $table->string('smtp_encryption')->nullable();
- $table->text('smtp_username')->nullable();
- $table->text('smtp_password')->nullable();
- $table->integer('smtp_timeout')->nullable();
- });
- $instance_settings = InstanceSettings::all();
- foreach ($instance_settings as $instance_setting) {
- $instance_setting->smtp_enabled = data_get($instance_setting, 'smtp.enabled', false);
- $instance_setting->smtp_from_address = data_get($instance_setting, 'smtp.from_address');
- $instance_setting->smtp_from_name = data_get($instance_setting, 'smtp.from_name');
- $instance_setting->smtp_recipients = data_get($instance_setting, 'smtp.recipients');
- $instance_setting->smtp_host = data_get($instance_setting, 'smtp.host');
- $instance_setting->smtp_port = data_get($instance_setting, 'smtp.port');
- $instance_setting->smtp_encryption = data_get($instance_setting, 'smtp.encryption');
- $instance_setting->smtp_username = data_get($instance_setting, 'smtp.username');
- $instance_setting->smtp_password = data_get($instance_setting, 'smtp.password');
- $instance_setting->smtp_timeout = data_get($instance_setting, 'smtp.timeout');
- $instance_setting->save();
- }
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('smtp');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->schemalessAttributes('smtp');
- $table->schemalessAttributes('smtp_notifications');
- $table->schemalessAttributes('discord');
- $table->schemalessAttributes('discord_notifications');
- });
- $teams = Team::all();
- foreach ($teams as $team) {
- $team->smtp = [
- 'enabled' => $team->smtp_enabled,
- 'from_address' => $team->smtp_from_address,
- 'from_name' => $team->smtp_from_name,
- 'recipients' => $team->smtp_recipients,
- 'host' => $team->smtp_host,
- 'port' => $team->smtp_port,
- 'encryption' => $team->smtp_encryption,
- 'username' => $team->smtp_username,
- 'password' => $team->smtp_password,
- 'timeout' => $team->smtp_timeout,
- ];
- $team->smtp_notifications = [
- 'test' => $team->smtp_notifications_test,
- 'deployments' => $team->smtp_notifications_deployments,
- 'status_changes' => $team->smtp_notifications_status_changes,
- ];
- $team->discord = [
- 'enabled' => $team->discord_enabled,
- 'webhook_url' => $team->discord_webhook_url,
- ];
- $team->discord_notifications = [
- 'test' => $team->discord_notifications_test,
- 'deployments' => $team->discord_notifications_deployments,
- 'status_changes' => $team->discord_notifications_status_changes,
- ];
- $team->save();
- }
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn('smtp_enabled');
- $table->dropColumn('smtp_from_address');
- $table->dropColumn('smtp_from_name');
- $table->dropColumn('smtp_recipients');
- $table->dropColumn('smtp_host');
- $table->dropColumn('smtp_port');
- $table->dropColumn('smtp_encryption');
- $table->dropColumn('smtp_username');
- $table->dropColumn('smtp_password');
- $table->dropColumn('smtp_timeout');
- $table->dropColumn('smtp_notifications_test');
- $table->dropColumn('smtp_notifications_deployments');
- $table->dropColumn('smtp_notifications_status_changes');
-
- $table->dropColumn('discord_enabled');
- $table->dropColumn('discord_webhook_url');
- $table->dropColumn('discord_notifications_test');
- $table->dropColumn('discord_notifications_deployments');
- $table->dropColumn('discord_notifications_status_changes');
- });
-
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->schemalessAttributes('smtp');
- });
-
- $instance_setting = instanceSettings();
- $instance_setting->smtp = [
- 'enabled' => $instance_setting->smtp_enabled,
- 'from_address' => $instance_setting->smtp_from_address,
- 'from_name' => $instance_setting->smtp_from_name,
- 'recipients' => $instance_setting->smtp_recipients,
- 'host' => $instance_setting->smtp_host,
- 'port' => $instance_setting->smtp_port,
- 'encryption' => $instance_setting->smtp_encryption,
- 'username' => $instance_setting->smtp_username,
- 'password' => $instance_setting->smtp_password,
- 'timeout' => $instance_setting->smtp_timeout,
- ];
- $instance_setting->save();
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('smtp_enabled');
- $table->dropColumn('smtp_from_address');
- $table->dropColumn('smtp_from_name');
- $table->dropColumn('smtp_recipients');
- $table->dropColumn('smtp_host');
- $table->dropColumn('smtp_port');
- $table->dropColumn('smtp_encryption');
- $table->dropColumn('smtp_username');
- $table->dropColumn('smtp_password');
- $table->dropColumn('smtp_timeout');
- });
- }
-};
diff --git a/database/migrations/2023_08_06_142951_add_description_field_to_applications_table.php b/database/migrations/2023_08_06_142951_add_description_field_to_applications_table.php
deleted file mode 100644
index 5be2f2959c..0000000000
--- a/database/migrations/2023_08_06_142951_add_description_field_to_applications_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('description')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('description');
- });
- }
-};
diff --git a/database/migrations/2023_08_06_142952_remove_foreignId_environment_variables.php b/database/migrations/2023_08_06_142952_remove_foreignId_environment_variables.php
deleted file mode 100644
index d24dbb4464..0000000000
--- a/database/migrations/2023_08_06_142952_remove_foreignId_environment_variables.php
+++ /dev/null
@@ -1,32 +0,0 @@
-dropColumn('service_id');
- $table->dropColumn('database_id');
- $table->foreignId('standalone_postgresql_id')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->foreignId('service_id')->nullable();
- $table->foreignId('database_id')->nullable();
- $table->dropColumn('standalone_postgresql_id');
- });
- }
-};
diff --git a/database/migrations/2023_08_06_142954_add_readonly_localpersistentvolumes.php b/database/migrations/2023_08_06_142954_add_readonly_localpersistentvolumes.php
deleted file mode 100644
index f0bce760d7..0000000000
--- a/database/migrations/2023_08_06_142954_add_readonly_localpersistentvolumes.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_readonly')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('local_persistent_volumes', function (Blueprint $table) {
- $table->dropColumn('is_readonly');
- });
- }
-};
diff --git a/database/migrations/2023_08_07_073651_create_s3_storages_table.php b/database/migrations/2023_08_07_073651_create_s3_storages_table.php
deleted file mode 100644
index 0eded30242..0000000000
--- a/database/migrations/2023_08_07_073651_create_s3_storages_table.php
+++ /dev/null
@@ -1,37 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->longText('description')->nullable();
- $table->string('region')->default('us-east-1');
- $table->longText('key');
- $table->longText('secret');
- $table->longText('bucket');
- $table->longText('endpoint')->nullable();
-
- $table->foreignId('team_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('s3_storages');
- }
-};
diff --git a/database/migrations/2023_08_07_142950_create_standalone_postgresqls_table.php b/database/migrations/2023_08_07_142950_create_standalone_postgresqls_table.php
deleted file mode 100644
index fc33acaef2..0000000000
--- a/database/migrations/2023_08_07_142950_create_standalone_postgresqls_table.php
+++ /dev/null
@@ -1,58 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('description')->nullable();
-
- $table->string('postgres_user')->default('postgres');
- $table->text('postgres_password');
- $table->string('postgres_db')->default('postgres');
- $table->string('postgres_initdb_args')->nullable();
- $table->string('postgres_host_auth_method')->nullable();
- $table->json('init_scripts')->nullable();
-
- $table->string('status')->default('exited');
-
- $table->string('image')->default('postgres:15-alpine');
- $table->boolean('is_public')->default(false);
- $table->integer('public_port')->nullable();
- $table->text('ports_mappings')->nullable();
-
- $table->string('limits_memory')->default('0');
- $table->string('limits_memory_swap')->default('0');
- $table->integer('limits_memory_swappiness')->default(60);
- $table->string('limits_memory_reservation')->default('0');
-
- $table->string('limits_cpus')->default('0');
- $table->string('limits_cpuset')->nullable()->default('0');
- $table->integer('limits_cpu_shares')->default(1024);
-
- $table->timestamp('started_at')->nullable();
- $table->morphs('destination');
-
- $table->foreignId('environment_id')->nullable();
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('standalone_postgresqls');
- }
-};
diff --git a/database/migrations/2023_08_08_150103_create_scheduled_database_backups_table.php b/database/migrations/2023_08_08_150103_create_scheduled_database_backups_table.php
deleted file mode 100644
index cc6726f362..0000000000
--- a/database/migrations/2023_08_08_150103_create_scheduled_database_backups_table.php
+++ /dev/null
@@ -1,30 +0,0 @@
-id();
- $table->text('description')->nullable();
- $table->string('uuid')->unique();
- $table->boolean('enabled')->default(true);
- $table->boolean('save_s3')->default(true);
- $table->string('frequency');
- $table->integer('number_of_backups_locally')->default(7);
- $table->morphs('database');
- $table->foreignId('s3_storage_id')->nullable();
- $table->foreignId('team_id');
- $table->timestamps();
- });
- }
-
- public function down(): void
- {
- Schema::dropIfExists('scheduled_database_backups');
- }
-};
diff --git a/database/migrations/2023_08_10_113306_create_scheduled_database_backup_executions_table.php b/database/migrations/2023_08_10_113306_create_scheduled_database_backup_executions_table.php
deleted file mode 100644
index a7ecc37963..0000000000
--- a/database/migrations/2023_08_10_113306_create_scheduled_database_backup_executions_table.php
+++ /dev/null
@@ -1,27 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->enum('status', ['success', 'failed', 'running'])->default('running');
- $table->longText('message')->nullable();
- $table->text('size')->nullable();
- $table->text('filename')->nullable();
- $table->foreignId('scheduled_database_backup_id');
- $table->timestamps();
- });
- }
-
- public function down(): void
- {
- Schema::dropIfExists('scheduled_database_backup_executions');
- }
-};
diff --git a/database/migrations/2023_08_10_201311_add_backup_notifications_to_teams.php b/database/migrations/2023_08_10_201311_add_backup_notifications_to_teams.php
deleted file mode 100644
index 128aa5b250..0000000000
--- a/database/migrations/2023_08_10_201311_add_backup_notifications_to_teams.php
+++ /dev/null
@@ -1,24 +0,0 @@
-boolean('smtp_notifications_database_backups')->default(true)->after('smtp_notifications_status_changes');
- $table->boolean('discord_notifications_database_backups')->default(true)->after('discord_notifications_status_changes');
- });
- }
-
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn('smtp_notifications_database_backups');
- $table->dropColumn('discord_notifications_database_backups');
- });
- }
-};
diff --git a/database/migrations/2023_08_11_190528_add_dockerfile_to_applications_table.php b/database/migrations/2023_08_11_190528_add_dockerfile_to_applications_table.php
deleted file mode 100644
index f2ee106408..0000000000
--- a/database/migrations/2023_08_11_190528_add_dockerfile_to_applications_table.php
+++ /dev/null
@@ -1,25 +0,0 @@
-longText('dockerfile')->nullable();
- });
- }
-
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('dockerfile');
- });
- }
-};
diff --git a/database/migrations/2023_08_15_095902_create_waitlists_table.php b/database/migrations/2023_08_15_095902_create_waitlists_table.php
deleted file mode 100644
index 641d152d19..0000000000
--- a/database/migrations/2023_08_15_095902_create_waitlists_table.php
+++ /dev/null
@@ -1,31 +0,0 @@
-id();
- $table->string('uuid');
- $table->string('type');
- $table->string('email')->unique();
- $table->boolean('verified')->default(false);
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('waitlists');
- }
-};
diff --git a/database/migrations/2023_08_15_111125_update_users_table.php b/database/migrations/2023_08_15_111125_update_users_table.php
deleted file mode 100644
index 4453d39d49..0000000000
--- a/database/migrations/2023_08_15_111125_update_users_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('force_password_reset')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('users', function (Blueprint $table) {
- $table->dropColumn('force_password_reset');
- });
- }
-};
diff --git a/database/migrations/2023_08_15_111126_update_servers_add_unreachable_count_table.php b/database/migrations/2023_08_15_111126_update_servers_add_unreachable_count_table.php
deleted file mode 100644
index b6a0d710ad..0000000000
--- a/database/migrations/2023_08_15_111126_update_servers_add_unreachable_count_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-integer('unreachable_count')->default(0);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('servers', function (Blueprint $table) {
- $table->dropColumn('unreachable_count');
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071048_add_boarding_to_teams.php b/database/migrations/2023_08_22_071048_add_boarding_to_teams.php
deleted file mode 100644
index 0fe2062e38..0000000000
--- a/database/migrations/2023_08_22_071048_add_boarding_to_teams.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('show_boarding')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn('show_boarding');
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071049_update_webhooks_type.php b/database/migrations/2023_08_22_071049_update_webhooks_type.php
deleted file mode 100644
index 13f0276f9a..0000000000
--- a/database/migrations/2023_08_22_071049_update_webhooks_type.php
+++ /dev/null
@@ -1,29 +0,0 @@
-string('type')->change();
- });
- DB::statement('ALTER TABLE webhooks DROP CONSTRAINT webhooks_type_check');
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('webhooks', function (Blueprint $table) {
- $table->string('type')->change();
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071050_update_subscriptions_stripe.php b/database/migrations/2023_08_22_071050_update_subscriptions_stripe.php
deleted file mode 100644
index 70462fe208..0000000000
--- a/database/migrations/2023_08_22_071050_update_subscriptions_stripe.php
+++ /dev/null
@@ -1,52 +0,0 @@
-boolean('stripe_invoice_paid')->default(false);
- $table->string('stripe_subscription_id')->nullable();
- $table->string('stripe_customer_id')->nullable();
- $table->boolean('stripe_cancel_at_period_end')->default(false);
- $table->string('lemon_subscription_id')->nullable()->change();
- $table->string('lemon_order_id')->nullable()->change();
- $table->string('lemon_product_id')->nullable()->change();
- $table->string('lemon_variant_id')->nullable()->change();
- $table->string('lemon_variant_name')->nullable()->change();
- $table->string('lemon_customer_id')->nullable()->change();
- $table->string('lemon_status')->nullable()->change();
- $table->string('lemon_renews_at')->nullable()->change();
- $table->string('lemon_update_payment_menthod_url')->nullable()->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('subscriptions', function (Blueprint $table) {
- $table->dropColumn('stripe_invoice_paid');
- $table->dropColumn('stripe_subscription_id');
- $table->dropColumn('stripe_customer_id');
- $table->dropColumn('stripe_cancel_at_period_end');
- $table->string('lemon_subscription_id')->change();
- $table->string('lemon_order_id')->change();
- $table->string('lemon_product_id')->change();
- $table->string('lemon_variant_id')->change();
- $table->string('lemon_variant_name')->change();
- $table->string('lemon_customer_id')->change();
- $table->string('lemon_status')->change();
- $table->string('lemon_renews_at')->change();
- $table->string('lemon_update_payment_menthod_url')->change();
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071051_add_stripe_plan_to_subscriptions.php b/database/migrations/2023_08_22_071051_add_stripe_plan_to_subscriptions.php
deleted file mode 100644
index a04eaf9836..0000000000
--- a/database/migrations/2023_08_22_071051_add_stripe_plan_to_subscriptions.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('stripe_plan_id')->nullable()->after('stripe_cancel_at_period_end');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('subscriptions', function (Blueprint $table) {
- $table->dropColumn('stripe_plan_id');
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071052_add_resend_as_email.php b/database/migrations/2023_08_22_071052_add_resend_as_email.php
deleted file mode 100644
index fd7368bfe0..0000000000
--- a/database/migrations/2023_08_22_071052_add_resend_as_email.php
+++ /dev/null
@@ -1,30 +0,0 @@
-boolean('resend_enabled')->default(false);
- $table->text('resend_api_key')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('resend_enabled');
- $table->dropColumn('resend_api_key');
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071053_add_resend_as_email_to_teams.php b/database/migrations/2023_08_22_071053_add_resend_as_email_to_teams.php
deleted file mode 100644
index 72be88b2cb..0000000000
--- a/database/migrations/2023_08_22_071053_add_resend_as_email_to_teams.php
+++ /dev/null
@@ -1,32 +0,0 @@
-boolean('resend_enabled')->default(false);
- $table->text('resend_api_key')->nullable();
- $table->boolean('use_instance_email_settings')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn('resend_enabled');
- $table->dropColumn('resend_api_key');
- $table->dropColumn('use_instance_email_settings');
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071054_add_stripe_reasons.php b/database/migrations/2023_08_22_071054_add_stripe_reasons.php
deleted file mode 100644
index 6ffe37e982..0000000000
--- a/database/migrations/2023_08_22_071054_add_stripe_reasons.php
+++ /dev/null
@@ -1,30 +0,0 @@
-string('stripe_feedback')->nullable()->after('stripe_cancel_at_period_end');
- $table->string('stripe_comment')->nullable()->after('stripe_feedback');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('subscriptions', function (Blueprint $table) {
- $table->dropColumn('stripe_feedback');
- $table->dropColumn('stripe_comment');
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071055_add_discord_notifications_to_teams.php b/database/migrations/2023_08_22_071055_add_discord_notifications_to_teams.php
deleted file mode 100644
index 0439cae540..0000000000
--- a/database/migrations/2023_08_22_071055_add_discord_notifications_to_teams.php
+++ /dev/null
@@ -1,34 +0,0 @@
-boolean('telegram_enabled')->default(false);
- $table->text('telegram_token')->nullable();
- $table->text('telegram_chat_id')->nullable();
- $table->boolean('telegram_notifications_test')->default(true);
- $table->boolean('telegram_notifications_deployments')->default(true);
- $table->boolean('telegram_notifications_status_changes')->default(true);
- $table->boolean('telegram_notifications_database_backups')->default(true);
- });
- }
-
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn('telegram_enabled');
- $table->dropColumn('telegram_token');
- $table->dropColumn('telegram_chat_id');
- $table->dropColumn('telegram_notifications_test');
- $table->dropColumn('telegram_notifications_deployments');
- $table->dropColumn('telegram_notifications_status_changes');
- $table->dropColumn('telegram_notifications_database_backups');
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071056_update_telegram_notifications.php b/database/migrations/2023_08_22_071056_update_telegram_notifications.php
deleted file mode 100644
index 6e1da18e3d..0000000000
--- a/database/migrations/2023_08_22_071056_update_telegram_notifications.php
+++ /dev/null
@@ -1,29 +0,0 @@
-text('telegram_notifications_test_message_thread_id')->nullable();
- $table->text('telegram_notifications_deployments_message_thread_id')->nullable();
- $table->text('telegram_notifications_status_changes_message_thread_id')->nullable();
- $table->text('telegram_notifications_database_backups_message_thread_id')->nullable();
- });
- }
-
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn('telegram_message_thread_id');
- $table->dropColumn('telegram_notifications_test_message_thread_id');
- $table->dropColumn('telegram_notifications_deployments_message_thread_id');
- $table->dropColumn('telegram_notifications_status_changes_message_thread_id');
- $table->dropColumn('telegram_notifications_database_backups_message_thread_id');
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071057_add_nixpkgsarchive_to_applications.php b/database/migrations/2023_08_22_071057_add_nixpkgsarchive_to_applications.php
deleted file mode 100644
index 4c3b283db2..0000000000
--- a/database/migrations/2023_08_22_071057_add_nixpkgsarchive_to_applications.php
+++ /dev/null
@@ -1,22 +0,0 @@
-string('nixpkgsarchive')->nullable();
- });
- }
-
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn('nixpkgsarchive');
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071058_add_nixpkgsarchive_to_applications_remove.php b/database/migrations/2023_08_22_071058_add_nixpkgsarchive_to_applications_remove.php
deleted file mode 100644
index 69845d4d02..0000000000
--- a/database/migrations/2023_08_22_071058_add_nixpkgsarchive_to_applications_remove.php
+++ /dev/null
@@ -1,22 +0,0 @@
-dropColumn('nixpkgsarchive');
- });
- }
-
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->string('nixpkgsarchive')->nullable();
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071059_add_stripe_trial_ended.php b/database/migrations/2023_08_22_071059_add_stripe_trial_ended.php
deleted file mode 100644
index 61fcbda6b3..0000000000
--- a/database/migrations/2023_08_22_071059_add_stripe_trial_ended.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('stripe_trial_already_ended')->default(false)->after('stripe_cancel_at_period_end');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('subscriptions', function (Blueprint $table) {
- $table->dropColumn('stripe_trial_already_ended');
- });
- }
-};
diff --git a/database/migrations/2023_08_22_071060_change_invitation_link_length.php b/database/migrations/2023_08_22_071060_change_invitation_link_length.php
deleted file mode 100644
index 9d14c3f265..0000000000
--- a/database/migrations/2023_08_22_071060_change_invitation_link_length.php
+++ /dev/null
@@ -1,28 +0,0 @@
-text('link')->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('team_invitations', function (Blueprint $table) {
- $table->string('link')->change();
- });
- }
-};
diff --git a/database/migrations/2023_09_20_082541_update_services_table.php b/database/migrations/2023_09_20_082541_update_services_table.php
deleted file mode 100644
index c70cd28f7c..0000000000
--- a/database/migrations/2023_09_20_082541_update_services_table.php
+++ /dev/null
@@ -1,34 +0,0 @@
-foreignId('server_id')->nullable();
- $table->longText('description')->nullable();
- $table->longText('docker_compose_raw');
- $table->longText('docker_compose')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('services', function (Blueprint $table) {
- $table->dropColumn('server_id');
- $table->dropColumn('description');
- $table->dropColumn('docker_compose_raw');
- $table->dropColumn('docker_compose');
- });
- }
-};
diff --git a/database/migrations/2023_09_20_082733_create_service_databases_table.php b/database/migrations/2023_09_20_082733_create_service_databases_table.php
deleted file mode 100644
index c76a7bb8f0..0000000000
--- a/database/migrations/2023_09_20_082733_create_service_databases_table.php
+++ /dev/null
@@ -1,38 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('human_name')->nullable();
- $table->longText('description')->nullable();
-
- $table->longText('ports')->nullable();
- $table->longText('exposes')->nullable();
-
- $table->string('status')->default('exited');
-
- $table->foreignId('service_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('service_databases');
- }
-};
diff --git a/database/migrations/2023_09_20_082737_create_service_applications_table.php b/database/migrations/2023_09_20_082737_create_service_applications_table.php
deleted file mode 100644
index 50a0d55b1e..0000000000
--- a/database/migrations/2023_09_20_082737_create_service_applications_table.php
+++ /dev/null
@@ -1,39 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('human_name')->nullable();
- $table->longText('description')->nullable();
-
- $table->string('fqdn')->unique()->nullable();
- $table->longText('ports')->nullable();
- $table->longText('exposes')->nullable();
-
- $table->string('status')->default('exited');
-
- $table->foreignId('service_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('service_applications');
- }
-};
diff --git a/database/migrations/2023_09_20_083549_update_environment_variables_table.php b/database/migrations/2023_09_20_083549_update_environment_variables_table.php
deleted file mode 100644
index a96d096bbf..0000000000
--- a/database/migrations/2023_09_20_083549_update_environment_variables_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-foreignId('service_id')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('service_id');
- });
- }
-};
diff --git a/database/migrations/2023_09_22_185356_create_local_file_volumes_table.php b/database/migrations/2023_09_22_185356_create_local_file_volumes_table.php
deleted file mode 100644
index 9dc6e13bb0..0000000000
--- a/database/migrations/2023_09_22_185356_create_local_file_volumes_table.php
+++ /dev/null
@@ -1,34 +0,0 @@
-id();
- $table->string('uuid');
- $table->mediumText('fs_path');
- $table->string('mount_path');
- $table->mediumText('content')->nullable();
- $table->nullableMorphs('resource');
-
- $table->unique(['mount_path', 'resource_id', 'resource_type']);
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('local_file_volumes');
- }
-};
diff --git a/database/migrations/2023_09_23_111808_update_servers_with_cloudflared.php b/database/migrations/2023_09_23_111808_update_servers_with_cloudflared.php
deleted file mode 100644
index c2609d4142..0000000000
--- a/database/migrations/2023_09_23_111808_update_servers_with_cloudflared.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_cloudflare_tunnel')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('is_cloudflare_tunnel');
- });
- }
-};
diff --git a/database/migrations/2023_09_23_111809_remove_destination_from_services_table.php b/database/migrations/2023_09_23_111809_remove_destination_from_services_table.php
deleted file mode 100644
index 729146a4ad..0000000000
--- a/database/migrations/2023_09_23_111809_remove_destination_from_services_table.php
+++ /dev/null
@@ -1,29 +0,0 @@
-dropColumn('destination_type');
- $table->dropColumn('destination_id');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('services', function (Blueprint $table) {
- $table->morphs('destination');
- });
- }
-};
diff --git a/database/migrations/2023_09_23_111811_update_service_applications_table.php b/database/migrations/2023_09_23_111811_update_service_applications_table.php
deleted file mode 100644
index 7e3e5984b9..0000000000
--- a/database/migrations/2023_09_23_111811_update_service_applications_table.php
+++ /dev/null
@@ -1,32 +0,0 @@
-boolean('exclude_from_status')->default(false);
- $table->boolean('required_fqdn')->default(false);
- $table->string('image')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('service_applications', function (Blueprint $table) {
- $table->dropColumn('exclude_from_status');
- $table->dropColumn('required_fqdn');
- $table->dropColumn('image');
- });
- }
-};
diff --git a/database/migrations/2023_09_23_111812_update_service_databases_table.php b/database/migrations/2023_09_23_111812_update_service_databases_table.php
deleted file mode 100644
index 2f02b5afe7..0000000000
--- a/database/migrations/2023_09_23_111812_update_service_databases_table.php
+++ /dev/null
@@ -1,30 +0,0 @@
-boolean('exclude_from_status')->default(false);
- $table->string('image')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('service_databases', function (Blueprint $table) {
- $table->dropColumn('exclude_from_status');
- $table->dropColumn('image');
- });
- }
-};
diff --git a/database/migrations/2023_09_23_111813_update_users_databases_table.php b/database/migrations/2023_09_23_111813_update_users_databases_table.php
deleted file mode 100644
index d79b9471c1..0000000000
--- a/database/migrations/2023_09_23_111813_update_users_databases_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('marketing_emails')->default(true);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('users', function (Blueprint $table) {
- $table->dropColumn('marketing_emails');
- });
- }
-};
diff --git a/database/migrations/2023_09_23_111814_update_local_file_volumes_table.php b/database/migrations/2023_09_23_111814_update_local_file_volumes_table.php
deleted file mode 100644
index c1ccd80247..0000000000
--- a/database/migrations/2023_09_23_111814_update_local_file_volumes_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_directory')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('local_file_volumes', function (Blueprint $table) {
- $table->dropColumn('is_directory');
- });
- }
-};
diff --git a/database/migrations/2023_09_23_111815_add_healthcheck_disable_to_apps_table.php b/database/migrations/2023_09_23_111815_add_healthcheck_disable_to_apps_table.php
deleted file mode 100644
index 4b8eeea08d..0000000000
--- a/database/migrations/2023_09_23_111815_add_healthcheck_disable_to_apps_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('health_check_enabled')->default(true);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('health_check_enabled');
- });
- }
-};
diff --git a/database/migrations/2023_09_23_111816_add_destination_to_services_table.php b/database/migrations/2023_09_23_111816_add_destination_to_services_table.php
deleted file mode 100644
index 2ec71bfdbe..0000000000
--- a/database/migrations/2023_09_23_111816_add_destination_to_services_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-nullableMorphs('destination');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('services', function (Blueprint $table) {
- $table->dropMorphs('destination');
- });
- }
-};
diff --git a/database/migrations/2023_09_23_111817_use_instance_email_settings_by_default.php b/database/migrations/2023_09_23_111817_use_instance_email_settings_by_default.php
deleted file mode 100644
index 86a77c22dc..0000000000
--- a/database/migrations/2023_09_23_111817_use_instance_email_settings_by_default.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('use_instance_email_settings')->default(true)->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->boolean('use_instance_email_settings')->default(false)->change();
- });
- }
-};
diff --git a/database/migrations/2023_09_23_111818_set_notifications_on_by_default.php b/database/migrations/2023_09_23_111818_set_notifications_on_by_default.php
deleted file mode 100644
index a7edc7860a..0000000000
--- a/database/migrations/2023_09_23_111818_set_notifications_on_by_default.php
+++ /dev/null
@@ -1,30 +0,0 @@
-boolean('smtp_notifications_deployments')->default(true)->change();
- $table->boolean('smtp_notifications_status_changes')->default(true)->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->boolean('smtp_notifications_deployments')->default(false)->change();
- $table->boolean('smtp_notifications_status_changes')->default(false)->change();
- });
- }
-};
diff --git a/database/migrations/2023_09_23_111819_add_server_emails.php b/database/migrations/2023_09_23_111819_add_server_emails.php
deleted file mode 100644
index 775e820108..0000000000
--- a/database/migrations/2023_09_23_111819_add_server_emails.php
+++ /dev/null
@@ -1,30 +0,0 @@
-boolean('unreachable_email_sent')->default(false);
- $table->dropColumn('unreachable_count');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('servers', function (Blueprint $table) {
- $table->dropColumn('unreachable_email_sent');
- $table->integer('unreachable_count')->default(0);
- });
- }
-};
diff --git a/database/migrations/2023_10_08_111819_add_server_unreachable_count.php b/database/migrations/2023_10_08_111819_add_server_unreachable_count.php
deleted file mode 100644
index b6a0d710ad..0000000000
--- a/database/migrations/2023_10_08_111819_add_server_unreachable_count.php
+++ /dev/null
@@ -1,28 +0,0 @@
-integer('unreachable_count')->default(0);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('servers', function (Blueprint $table) {
- $table->dropColumn('unreachable_count');
- });
- }
-};
diff --git a/database/migrations/2023_10_10_100320_update_s3_storages_table.php b/database/migrations/2023_10_10_100320_update_s3_storages_table.php
deleted file mode 100644
index b9c482c829..0000000000
--- a/database/migrations/2023_10_10_100320_update_s3_storages_table.php
+++ /dev/null
@@ -1,30 +0,0 @@
-boolean('is_usable')->default(false);
- $table->boolean('unusable_email_sent')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('s3_storages', function (Blueprint $table) {
- $table->dropColumn('is_usable');
- $table->dropColumn('unusable_email_sent');
- });
- }
-};
diff --git a/database/migrations/2023_10_10_113144_add_dockerfile_location_applications_table.php b/database/migrations/2023_10_10_113144_add_dockerfile_location_applications_table.php
deleted file mode 100644
index 39956a9edb..0000000000
--- a/database/migrations/2023_10_10_113144_add_dockerfile_location_applications_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('dockerfile_location')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('dockerfile_location');
- });
- }
-};
diff --git a/database/migrations/2023_10_12_132430_create_standalone_redis_table.php b/database/migrations/2023_10_12_132430_create_standalone_redis_table.php
deleted file mode 100644
index 772ee7cfd9..0000000000
--- a/database/migrations/2023_10_12_132430_create_standalone_redis_table.php
+++ /dev/null
@@ -1,54 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('description')->nullable();
-
- $table->text('redis_password');
- $table->longText('redis_conf')->nullable();
-
- $table->string('status')->default('exited');
-
- $table->string('image')->default('redis:7.2');
-
- $table->boolean('is_public')->default(false);
- $table->integer('public_port')->nullable();
- $table->text('ports_mappings')->nullable();
-
- $table->string('limits_memory')->default('0');
- $table->string('limits_memory_swap')->default('0');
- $table->integer('limits_memory_swappiness')->default(60);
- $table->string('limits_memory_reservation')->default('0');
-
- $table->string('limits_cpus')->default('0');
- $table->string('limits_cpuset')->nullable()->default('0');
- $table->integer('limits_cpu_shares')->default(1024);
-
- $table->timestamp('started_at')->nullable();
- $table->morphs('destination');
- $table->foreignId('environment_id')->nullable();
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('standalone_redis');
- }
-};
diff --git a/database/migrations/2023_10_12_132431_add_standalone_redis_to_environment_variables_table.php b/database/migrations/2023_10_12_132431_add_standalone_redis_to_environment_variables_table.php
deleted file mode 100644
index 2fdacc9e5f..0000000000
--- a/database/migrations/2023_10_12_132431_add_standalone_redis_to_environment_variables_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-foreignId('standalone_redis_id')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('standalone_redis_id');
- });
- }
-};
diff --git a/database/migrations/2023_10_12_132432_add_database_selection_to_backups.php b/database/migrations/2023_10_12_132432_add_database_selection_to_backups.php
deleted file mode 100644
index 40ade57e82..0000000000
--- a/database/migrations/2023_10_12_132432_add_database_selection_to_backups.php
+++ /dev/null
@@ -1,34 +0,0 @@
-text('databases_to_backup')->nullable();
- });
- Schema::table('scheduled_database_backup_executions', function (Blueprint $table) {
- $table->string('database_name')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('scheduled_database_backups', function (Blueprint $table) {
- $table->dropColumn('databases_to_backup');
- });
- Schema::table('scheduled_database_backup_executions', function (Blueprint $table) {
- $table->dropColumn('database_name');
- });
- }
-};
diff --git a/database/migrations/2023_10_18_072519_add_custom_labels_applications_table.php b/database/migrations/2023_10_18_072519_add_custom_labels_applications_table.php
deleted file mode 100644
index f993e35eed..0000000000
--- a/database/migrations/2023_10_18_072519_add_custom_labels_applications_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-text('custom_labels')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('custom_labels');
- });
- }
-};
diff --git a/database/migrations/2023_10_19_101331_create_standalone_mongodbs_table.php b/database/migrations/2023_10_19_101331_create_standalone_mongodbs_table.php
deleted file mode 100644
index 26173ffc01..0000000000
--- a/database/migrations/2023_10_19_101331_create_standalone_mongodbs_table.php
+++ /dev/null
@@ -1,56 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('description')->nullable();
-
- $table->text('mongo_conf')->nullable();
- $table->text('mongo_initdb_root_username')->default('root');
- $table->text('mongo_initdb_root_password');
- $table->text('mongo_initdb_database')->default('default');
-
- $table->string('status')->default('exited');
-
- $table->string('image')->default('mongo:7');
-
- $table->boolean('is_public')->default(false);
- $table->integer('public_port')->nullable();
- $table->text('ports_mappings')->nullable();
-
- $table->string('limits_memory')->default('0');
- $table->string('limits_memory_swap')->default('0');
- $table->integer('limits_memory_swappiness')->default(60);
- $table->string('limits_memory_reservation')->default('0');
-
- $table->string('limits_cpus')->default('0');
- $table->string('limits_cpuset')->nullable()->default('0');
- $table->integer('limits_cpu_shares')->default(1024);
-
- $table->timestamp('started_at')->nullable();
- $table->morphs('destination');
- $table->foreignId('environment_id')->nullable();
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('standalone_mongodbs');
- }
-};
diff --git a/database/migrations/2023_10_19_101332_add_standalone_mongodb_to_environment_variables_table.php b/database/migrations/2023_10_19_101332_add_standalone_mongodb_to_environment_variables_table.php
deleted file mode 100644
index b67c226371..0000000000
--- a/database/migrations/2023_10_19_101332_add_standalone_mongodb_to_environment_variables_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-foreignId('standalone_mongodb_id')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('standalone_mongodb_id');
- });
- }
-};
diff --git a/database/migrations/2023_10_24_103548_create_standalone_mysqls_table.php b/database/migrations/2023_10_24_103548_create_standalone_mysqls_table.php
deleted file mode 100644
index f27d4690e2..0000000000
--- a/database/migrations/2023_10_24_103548_create_standalone_mysqls_table.php
+++ /dev/null
@@ -1,57 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('description')->nullable();
-
- $table->text('mysql_root_password');
- $table->string('mysql_user')->default('mysql');
- $table->text('mysql_password');
- $table->string('mysql_database')->default('default');
- $table->longText('mysql_conf')->nullable();
-
- $table->string('status')->default('exited');
-
- $table->string('image')->default('mysql:8');
- $table->boolean('is_public')->default(false);
- $table->integer('public_port')->nullable();
- $table->text('ports_mappings')->nullable();
-
- $table->string('limits_memory')->default('0');
- $table->string('limits_memory_swap')->default('0');
- $table->integer('limits_memory_swappiness')->default(60);
- $table->string('limits_memory_reservation')->default('0');
-
- $table->string('limits_cpus')->default('0');
- $table->string('limits_cpuset')->nullable()->default('0');
- $table->integer('limits_cpu_shares')->default(1024);
-
- $table->timestamp('started_at')->nullable();
- $table->morphs('destination');
-
- $table->foreignId('environment_id')->nullable();
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('standalone_mysqls');
- }
-};
diff --git a/database/migrations/2023_10_24_120523_create_standalone_mariadbs_table.php b/database/migrations/2023_10_24_120523_create_standalone_mariadbs_table.php
deleted file mode 100644
index a0350bcdea..0000000000
--- a/database/migrations/2023_10_24_120523_create_standalone_mariadbs_table.php
+++ /dev/null
@@ -1,57 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('description')->nullable();
-
- $table->text('mariadb_root_password');
- $table->string('mariadb_user')->default('mariadb');
- $table->text('mariadb_password');
- $table->string('mariadb_database')->default('default');
- $table->longText('mariadb_conf')->nullable();
-
- $table->string('status')->default('exited');
-
- $table->string('image')->default('mariadb:11');
- $table->boolean('is_public')->default(false);
- $table->integer('public_port')->nullable();
- $table->text('ports_mappings')->nullable();
-
- $table->string('limits_memory')->default('0');
- $table->string('limits_memory_swap')->default('0');
- $table->integer('limits_memory_swappiness')->default(60);
- $table->string('limits_memory_reservation')->default('0');
-
- $table->string('limits_cpus')->default('0');
- $table->string('limits_cpuset')->nullable()->default('0');
- $table->integer('limits_cpu_shares')->default(1024);
-
- $table->timestamp('started_at')->nullable();
- $table->morphs('destination');
-
- $table->foreignId('environment_id')->nullable();
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('standalone_mariadbs');
- }
-};
diff --git a/database/migrations/2023_10_24_120524_add_standalone_mysql_to_environment_variables_table.php b/database/migrations/2023_10_24_120524_add_standalone_mysql_to_environment_variables_table.php
deleted file mode 100644
index a511e9b21c..0000000000
--- a/database/migrations/2023_10_24_120524_add_standalone_mysql_to_environment_variables_table.php
+++ /dev/null
@@ -1,30 +0,0 @@
-foreignId('standalone_mysql_id')->nullable();
- $table->foreignId('standalone_mariadb_id')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('standalone_mysql_id');
- $table->dropColumn('standalone_mariadb_id');
- });
- }
-};
diff --git a/database/migrations/2023_10_24_124934_add_is_shown_once_to_environment_variables_table.php b/database/migrations/2023_10_24_124934_add_is_shown_once_to_environment_variables_table.php
deleted file mode 100644
index e0df21186c..0000000000
--- a/database/migrations/2023_10_24_124934_add_is_shown_once_to_environment_variables_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_shown_once')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('is_shown_once');
- });
- }
-};
diff --git a/database/migrations/2023_11_01_100437_add_restart_to_deployment_queue.php b/database/migrations/2023_11_01_100437_add_restart_to_deployment_queue.php
deleted file mode 100644
index 608fdd9241..0000000000
--- a/database/migrations/2023_11_01_100437_add_restart_to_deployment_queue.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('restart_only')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('restart_only');
- });
- }
-};
diff --git a/database/migrations/2023_11_07_123731_add_target_build_dockerfile.php b/database/migrations/2023_11_07_123731_add_target_build_dockerfile.php
deleted file mode 100644
index 26f43e9252..0000000000
--- a/database/migrations/2023_11_07_123731_add_target_build_dockerfile.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('dockerfile_target_build')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('dockerfile_target_build');
- });
- }
-};
diff --git a/database/migrations/2023_11_08_112815_add_custom_config_standalone_postgresql.php b/database/migrations/2023_11_08_112815_add_custom_config_standalone_postgresql.php
deleted file mode 100644
index c583fb3ff7..0000000000
--- a/database/migrations/2023_11_08_112815_add_custom_config_standalone_postgresql.php
+++ /dev/null
@@ -1,30 +0,0 @@
-longText('postgres_conf')->nullable();
- $table->string('image')->default('postgres:16-alpine')->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->dropColumn('postgres_conf');
- $table->string('image')->default('postgres:15-alpine')->change();
- });
- }
-};
diff --git a/database/migrations/2023_11_09_133332_add_public_port_to_service_databases.php b/database/migrations/2023_11_09_133332_add_public_port_to_service_databases.php
deleted file mode 100644
index 1a01d0ab22..0000000000
--- a/database/migrations/2023_11_09_133332_add_public_port_to_service_databases.php
+++ /dev/null
@@ -1,30 +0,0 @@
-integer('public_port')->nullable();
- $table->boolean('is_public')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('service_databases', function (Blueprint $table) {
- $table->dropColumn('public_port');
- $table->dropColumn('is_public');
- });
- }
-};
diff --git a/database/migrations/2023_11_12_180605_change_fqdn_to_longer_field.php b/database/migrations/2023_11_12_180605_change_fqdn_to_longer_field.php
deleted file mode 100644
index f10d5207ff..0000000000
--- a/database/migrations/2023_11_12_180605_change_fqdn_to_longer_field.php
+++ /dev/null
@@ -1,40 +0,0 @@
-longText('fqdn')->nullable()->change();
- });
- Schema::table('application_previews', function (Blueprint $table) {
- $table->longText('fqdn')->nullable()->change();
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->longText('fqdn')->nullable()->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->string('fqdn')->nullable()->change();
- });
- Schema::table('application_previews', function (Blueprint $table) {
- $table->string('fqdn')->nullable()->change();
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->string('fqdn')->nullable()->change();
- });
- }
-};
diff --git a/database/migrations/2023_11_13_133059_add_sponsorship_disable.php b/database/migrations/2023_11_13_133059_add_sponsorship_disable.php
deleted file mode 100644
index 6fe42b3904..0000000000
--- a/database/migrations/2023_11_13_133059_add_sponsorship_disable.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_notification_sponsorship_enabled')->default(true);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('users', function (Blueprint $table) {
- $table->dropColumn('is_notification_sponsorship_enabled');
- });
- }
-};
diff --git a/database/migrations/2023_11_14_103450_add_manual_webhook_secret.php b/database/migrations/2023_11_14_103450_add_manual_webhook_secret.php
deleted file mode 100644
index 3d1f37d383..0000000000
--- a/database/migrations/2023_11_14_103450_add_manual_webhook_secret.php
+++ /dev/null
@@ -1,30 +0,0 @@
-string('manual_webhook_secret_github')->nullable();
- $table->string('manual_webhook_secret_gitlab')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('manual_webhook_secret_github');
- $table->dropColumn('manual_webhook_secret_gitlab');
- });
- }
-};
diff --git a/database/migrations/2023_11_14_121416_add_git_type.php b/database/migrations/2023_11_14_121416_add_git_type.php
deleted file mode 100644
index 1e2a307fe8..0000000000
--- a/database/migrations/2023_11_14_121416_add_git_type.php
+++ /dev/null
@@ -1,34 +0,0 @@
-string('git_type')->nullable();
- });
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->string('git_type')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_previews', function (Blueprint $table) {
- $table->dropColumn('git_type');
- });
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('git_type');
- });
- }
-};
diff --git a/database/migrations/2023_11_16_101819_add_high_disk_usage_notification.php b/database/migrations/2023_11_16_101819_add_high_disk_usage_notification.php
deleted file mode 100644
index 67d8d3e470..0000000000
--- a/database/migrations/2023_11_16_101819_add_high_disk_usage_notification.php
+++ /dev/null
@@ -1,30 +0,0 @@
-boolean('high_disk_usage_notification_sent')->default(false);
- $table->renameColumn('unreachable_email_sent', 'unreachable_notification_sent');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('servers', function (Blueprint $table) {
- $table->dropColumn('high_disk_usage_notification_sent');
- $table->renameColumn('unreachable_notification_sent', 'unreachable_email_sent');
- });
- }
-};
diff --git a/database/migrations/2023_11_16_220647_add_log_drains.php b/database/migrations/2023_11_16_220647_add_log_drains.php
deleted file mode 100644
index f5161b3d7f..0000000000
--- a/database/migrations/2023_11_16_220647_add_log_drains.php
+++ /dev/null
@@ -1,46 +0,0 @@
-boolean('is_logdrain_newrelic_enabled')->default(false);
- $table->string('logdrain_newrelic_license_key')->nullable();
- $table->string('logdrain_newrelic_base_uri')->nullable();
-
- $table->boolean('is_logdrain_highlight_enabled')->default(false);
- $table->string('logdrain_highlight_project_id')->nullable();
-
- $table->boolean('is_logdrain_axiom_enabled')->default(false);
- $table->string('logdrain_axiom_dataset_name')->nullable();
- $table->string('logdrain_axiom_api_key')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('is_logdrain_newrelic_enabled');
- $table->dropColumn('logdrain_newrelic_license_key');
- $table->dropColumn('logdrain_newrelic_base_uri');
-
- $table->dropColumn('is_logdrain_highlight_enabled');
- $table->dropColumn('logdrain_highlight_project_id');
-
- $table->dropColumn('is_logdrain_axiom_enabled');
- $table->dropColumn('logdrain_axiom_dataset_name');
- $table->dropColumn('logdrain_axiom_api_key');
- });
- }
-};
diff --git a/database/migrations/2023_11_17_160437_add_drain_log_enable_by_service.php b/database/migrations/2023_11_17_160437_add_drain_log_enable_by_service.php
deleted file mode 100644
index 8d0853be30..0000000000
--- a/database/migrations/2023_11_17_160437_add_drain_log_enable_by_service.php
+++ /dev/null
@@ -1,76 +0,0 @@
-boolean('is_log_drain_enabled')->default(false);
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->boolean('is_log_drain_enabled')->default(false);
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->boolean('is_log_drain_enabled')->default(false);
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->boolean('is_log_drain_enabled')->default(false);
- });
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->boolean('is_log_drain_enabled')->default(false);
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->boolean('is_log_drain_enabled')->default(false);
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->boolean('is_log_drain_enabled')->default(false);
- });
- Schema::table('service_databases', function (Blueprint $table) {
- $table->boolean('is_log_drain_enabled')->default(false);
- });
- Schema::table('servers', function (Blueprint $table) {
- $table->boolean('log_drain_notification_sent')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_log_drain_enabled');
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->dropColumn('is_log_drain_enabled');
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->dropColumn('is_log_drain_enabled');
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->dropColumn('is_log_drain_enabled');
- });
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->dropColumn('is_log_drain_enabled');
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->dropColumn('is_log_drain_enabled');
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->dropColumn('is_log_drain_enabled');
- });
- Schema::table('service_databases', function (Blueprint $table) {
- $table->dropColumn('is_log_drain_enabled');
- });
- Schema::table('servers', function (Blueprint $table) {
- $table->dropColumn('log_drain_notification_sent');
- });
- }
-};
diff --git a/database/migrations/2023_11_20_094628_add_gpu_settings.php b/database/migrations/2023_11_20_094628_add_gpu_settings.php
deleted file mode 100644
index 9aeb255d98..0000000000
--- a/database/migrations/2023_11_20_094628_add_gpu_settings.php
+++ /dev/null
@@ -1,36 +0,0 @@
-boolean('is_gpu_enabled')->default(false);
- $table->string('gpu_driver')->default('nvidia');
- $table->string('gpu_count')->nullable();
- $table->string('gpu_device_ids')->nullable();
- $table->longText('gpu_options')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_gpu_enabled');
- $table->dropColumn('gpu_driver');
- $table->dropColumn('gpu_count');
- $table->dropColumn('gpu_device_ids');
- $table->dropColumn('gpu_options');
- });
- }
-};
diff --git a/database/migrations/2023_11_21_121920_add_additional_destinations_to_apps.php b/database/migrations/2023_11_21_121920_add_additional_destinations_to_apps.php
deleted file mode 100644
index 4852007b49..0000000000
--- a/database/migrations/2023_11_21_121920_add_additional_destinations_to_apps.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('additional_destinations')->nullable()->after('destination');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('additional_destinations');
- });
- }
-};
diff --git a/database/migrations/2023_11_24_080341_add_docker_compose_location.php b/database/migrations/2023_11_24_080341_add_docker_compose_location.php
deleted file mode 100644
index 8508181a39..0000000000
--- a/database/migrations/2023_11_24_080341_add_docker_compose_location.php
+++ /dev/null
@@ -1,42 +0,0 @@
-string('docker_compose_location')->nullable()->default('/docker-compose.yaml')->after('dockerfile_location');
- $table->string('docker_compose_pr_location')->nullable()->default('/docker-compose.yaml')->after('docker_compose_location');
-
- $table->longText('docker_compose')->nullable()->after('docker_compose_location');
- $table->longText('docker_compose_pr')->nullable()->after('docker_compose_location');
- $table->longText('docker_compose_raw')->nullable()->after('docker_compose');
- $table->longText('docker_compose_pr_raw')->nullable()->after('docker_compose');
-
- $table->text('docker_compose_domains')->nullable()->after('docker_compose_raw');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('docker_compose_location');
- $table->dropColumn('docker_compose_pr_location');
- $table->dropColumn('docker_compose');
- $table->dropColumn('docker_compose_pr');
- $table->dropColumn('docker_compose_raw');
- $table->dropColumn('docker_compose_pr_raw');
- $table->dropColumn('docker_compose_domains');
- });
- }
-};
diff --git a/database/migrations/2023_11_28_143533_add_fields_to_swarm_dockers.php b/database/migrations/2023_11_28_143533_add_fields_to_swarm_dockers.php
deleted file mode 100644
index 7ca398b90a..0000000000
--- a/database/migrations/2023_11_28_143533_add_fields_to_swarm_dockers.php
+++ /dev/null
@@ -1,30 +0,0 @@
-string('network');
-
- $table->unique(['server_id', 'network']);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('swarm_dockers', function (Blueprint $table) {
- $table->dropColumn('network');
- });
- }
-};
diff --git a/database/migrations/2023_11_29_075937_change_swarm_properties.php b/database/migrations/2023_11_29_075937_change_swarm_properties.php
deleted file mode 100644
index 6c0edc432e..0000000000
--- a/database/migrations/2023_11_29_075937_change_swarm_properties.php
+++ /dev/null
@@ -1,30 +0,0 @@
-renameColumn('is_part_of_swarm', 'is_swarm_manager');
- $table->boolean('is_swarm_worker')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->renameColumn('is_swarm_manager', 'is_part_of_swarm');
- $table->dropColumn('is_swarm_worker');
- });
- }
-};
diff --git a/database/migrations/2023_12_01_091723_save_logs_view_settings.php b/database/migrations/2023_12_01_091723_save_logs_view_settings.php
deleted file mode 100644
index a435644549..0000000000
--- a/database/migrations/2023_12_01_091723_save_logs_view_settings.php
+++ /dev/null
@@ -1,64 +0,0 @@
-boolean('is_include_timestamps')->default(false);
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->boolean('is_include_timestamps')->default(false);
- });
- Schema::table('service_databases', function (Blueprint $table) {
- $table->boolean('is_include_timestamps')->default(false);
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->boolean('is_include_timestamps')->default(false);
- });
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->boolean('is_include_timestamps')->default(false);
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->boolean('is_include_timestamps')->default(false);
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->boolean('is_include_timestamps')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_include_timestamps');
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->dropColumn('is_include_timestamps');
- });
- Schema::table('service_databases', function (Blueprint $table) {
- $table->dropColumn('is_include_timestamps');
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->dropColumn('is_include_timestamps');
- });
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->dropColumn('is_include_timestamps');
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->dropColumn('is_include_timestamps');
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->dropColumn('is_include_timestamps');
- });
- }
-};
diff --git a/database/migrations/2023_12_01_095356_add_custom_fluentd_config_for_logdrains.php b/database/migrations/2023_12_01_095356_add_custom_fluentd_config_for_logdrains.php
deleted file mode 100644
index ff100b484d..0000000000
--- a/database/migrations/2023_12_01_095356_add_custom_fluentd_config_for_logdrains.php
+++ /dev/null
@@ -1,32 +0,0 @@
-boolean('is_logdrain_custom_enabled')->default(false);
- $table->text('logdrain_custom_config')->nullable();
- $table->text('logdrain_custom_config_parser')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('is_logdrain_custom_enabled');
- $table->dropColumn('logdrain_custom_config');
- $table->dropColumn('logdrain_custom_config_parser');
- });
- }
-};
diff --git a/database/migrations/2023_12_08_162228_add_soft_delete_services.php b/database/migrations/2023_12_08_162228_add_soft_delete_services.php
deleted file mode 100644
index c45ecf5bf1..0000000000
--- a/database/migrations/2023_12_08_162228_add_soft_delete_services.php
+++ /dev/null
@@ -1,28 +0,0 @@
-softDeletes();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('services', function (Blueprint $table) {
- $table->dropSoftDeletes();
- });
- }
-};
diff --git a/database/migrations/2023_12_11_103611_add_realtime_connection_problem.php b/database/migrations/2023_12_11_103611_add_realtime_connection_problem.php
deleted file mode 100644
index 285e2f4574..0000000000
--- a/database/migrations/2023_12_11_103611_add_realtime_connection_problem.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_notification_realtime_enabled')->default(true);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('users', function (Blueprint $table) {
- $table->dropColumn('is_notification_realtime_enabled');
- });
- }
-};
diff --git a/database/migrations/2023_12_13_110214_add_soft_deletes.php b/database/migrations/2023_12_13_110214_add_soft_deletes.php
deleted file mode 100644
index 72350b77fb..0000000000
--- a/database/migrations/2023_12_13_110214_add_soft_deletes.php
+++ /dev/null
@@ -1,70 +0,0 @@
-softDeletes();
- });
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->softDeletes();
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->softDeletes();
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->softDeletes();
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->softDeletes();
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->softDeletes();
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->softDeletes();
- });
- Schema::table('service_databases', function (Blueprint $table) {
- $table->softDeletes();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropSoftDeletes();
- });
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->dropSoftDeletes();
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->dropSoftDeletes();
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->dropSoftDeletes();
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->dropSoftDeletes();
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->dropSoftDeletes();
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->dropSoftDeletes();
- });
- Schema::table('service_databases', function (Blueprint $table) {
- $table->dropSoftDeletes();
- });
- }
-};
diff --git a/database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php b/database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php
deleted file mode 100644
index f28b2670e3..0000000000
--- a/database/migrations/2023_12_17_155616_add_custom_docker_compose_start_command.php
+++ /dev/null
@@ -1,30 +0,0 @@
-string('docker_compose_custom_start_command')->nullable();
- $table->string('docker_compose_custom_build_command')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('docker_compose_custom_start_command');
- $table->dropColumn('docker_compose_custom_build_command');
- });
- }
-};
diff --git a/database/migrations/2023_12_18_093514_add_swarm_related_things.php b/database/migrations/2023_12_18_093514_add_swarm_related_things.php
deleted file mode 100644
index 0f44f35ec4..0000000000
--- a/database/migrations/2023_12_18_093514_add_swarm_related_things.php
+++ /dev/null
@@ -1,36 +0,0 @@
-integer('swarm_replicas')->default(1);
- $table->text('swarm_placement_constraints')->nullable();
- });
- Schema::table('application_settings', function (Blueprint $table) {
- $table->boolean('is_swarm_only_worker_nodes')->default(true);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('swarm_replicas');
- $table->dropColumn('swarm_placement_constraints');
- });
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_swarm_only_worker_nodes');
- });
- }
-};
diff --git a/database/migrations/2023_12_19_124111_add_swarm_cluster_grouping.php b/database/migrations/2023_12_19_124111_add_swarm_cluster_grouping.php
deleted file mode 100644
index 668acb6fed..0000000000
--- a/database/migrations/2023_12_19_124111_add_swarm_cluster_grouping.php
+++ /dev/null
@@ -1,28 +0,0 @@
-integer('swarm_cluster')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('servers', function (Blueprint $table) {
- $table->dropColumn('swarm_cluster');
- });
- }
-};
diff --git a/database/migrations/2023_12_30_134507_add_description_to_environments.php b/database/migrations/2023_12_30_134507_add_description_to_environments.php
deleted file mode 100644
index 0e8f4fec38..0000000000
--- a/database/migrations/2023_12_30_134507_add_description_to_environments.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('description')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environments', function (Blueprint $table) {
- $table->dropColumn('description');
- });
- }
-};
diff --git a/database/migrations/2023_12_31_173041_create_scheduled_tasks_table.php b/database/migrations/2023_12_31_173041_create_scheduled_tasks_table.php
deleted file mode 100644
index c3c2e2f488..0000000000
--- a/database/migrations/2023_12_31_173041_create_scheduled_tasks_table.php
+++ /dev/null
@@ -1,37 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->boolean('enabled')->default(true);
- $table->string('name');
- $table->string('command');
- $table->string('frequency');
- $table->string('container')->nullable();
- $table->timestamps();
-
- $table->foreignId('application_id')->nullable();
- $table->foreignId('service_id')->nullable();
- $table->foreignId('team_id');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('scheduled_tasks');
- }
-};
diff --git a/database/migrations/2024_01_01_231053_create_scheduled_task_executions_table.php b/database/migrations/2024_01_01_231053_create_scheduled_task_executions_table.php
deleted file mode 100644
index 27ace08d4c..0000000000
--- a/database/migrations/2024_01_01_231053_create_scheduled_task_executions_table.php
+++ /dev/null
@@ -1,31 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->enum('status', ['success', 'failed', 'running'])->default('running');
- $table->longText('message')->nullable();
- $table->foreignId('scheduled_task_id');
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('scheduled_task_executions');
- }
-};
diff --git a/database/migrations/2024_01_02_113855_add_raw_compose_deployment.php b/database/migrations/2024_01_02_113855_add_raw_compose_deployment.php
deleted file mode 100644
index 6f99bdc4b8..0000000000
--- a/database/migrations/2024_01_02_113855_add_raw_compose_deployment.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_raw_compose_deployment_enabled')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_raw_compose_deployment_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_01_12_123422_update_cpuset_limits.php b/database/migrations/2024_01_12_123422_update_cpuset_limits.php
deleted file mode 100644
index d1956eb9ff..0000000000
--- a/database/migrations/2024_01_12_123422_update_cpuset_limits.php
+++ /dev/null
@@ -1,76 +0,0 @@
-string('limits_cpuset')->nullable()->default(null)->change();
- });
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->string('limits_cpuset')->nullable()->default(null)->change();
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->string('limits_cpuset')->nullable()->default(null)->change();
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->string('limits_cpuset')->nullable()->default(null)->change();
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->string('limits_cpuset')->nullable()->default(null)->change();
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->string('limits_cpuset')->nullable()->default(null)->change();
- });
- Application::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
- StandalonePostgresql::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
- StandaloneRedis::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
- StandaloneMariadb::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
- StandaloneMysql::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
- StandaloneMongodb::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->string('limits_cpuset')->nullable()->default('0')->change();
- });
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->string('limits_cpuset')->nullable()->default('0')->change();
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->string('limits_cpuset')->nullable()->default('0')->change();
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->string('limits_cpuset')->nullable()->default('0')->change();
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->string('limits_cpuset')->nullable()->default('0')->change();
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->string('limits_cpuset')->nullable()->default('0')->change();
- });
- Application::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
- StandalonePostgresql::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
- StandaloneRedis::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
- StandaloneMariadb::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
- StandaloneMysql::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
- StandaloneMongodb::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
- }
-};
diff --git a/database/migrations/2024_01_15_084609_add_custom_dns_server.php b/database/migrations/2024_01_15_084609_add_custom_dns_server.php
deleted file mode 100644
index 24d288d020..0000000000
--- a/database/migrations/2024_01_15_084609_add_custom_dns_server.php
+++ /dev/null
@@ -1,30 +0,0 @@
-boolean('is_dns_validation_enabled')->default(true);
- $table->string('custom_dns_servers')->nullable()->default('1.1.1.1');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('is_dns_validation_enabled');
- $table->dropColumn('custom_dns_servers');
- });
- }
-};
diff --git a/database/migrations/2024_01_16_115005_add_build_server_enable.php b/database/migrations/2024_01_16_115005_add_build_server_enable.php
deleted file mode 100644
index 771c0e4ee2..0000000000
--- a/database/migrations/2024_01_16_115005_add_build_server_enable.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_build_server_enabled')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_build_server_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_01_21_130328_add_docker_network_to_services.php b/database/migrations/2024_01_21_130328_add_docker_network_to_services.php
deleted file mode 100644
index 78ea10e3a8..0000000000
--- a/database/migrations/2024_01_21_130328_add_docker_network_to_services.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('connect_to_docker_network')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('services', function (Blueprint $table) {
- $table->dropColumn('connect_to_docker_network');
- });
- }
-};
diff --git a/database/migrations/2024_01_23_095832_add_manual_webhook_secret_bitbucket.php b/database/migrations/2024_01_23_095832_add_manual_webhook_secret_bitbucket.php
deleted file mode 100755
index 74917a049a..0000000000
--- a/database/migrations/2024_01_23_095832_add_manual_webhook_secret_bitbucket.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('manual_webhook_secret_bitbucket')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('manual_webhook_secret_bitbucket');
- });
- }
-};
diff --git a/database/migrations/2024_01_23_113129_create_shared_environment_variables_table.php b/database/migrations/2024_01_23_113129_create_shared_environment_variables_table.php
deleted file mode 100644
index 994a02a407..0000000000
--- a/database/migrations/2024_01_23_113129_create_shared_environment_variables_table.php
+++ /dev/null
@@ -1,37 +0,0 @@
-id();
- $table->string('key');
- $table->string('value')->nullable();
- $table->boolean('is_shown_once')->default(false);
- $table->enum('type', ['team', 'project', 'environment'])->default('team');
-
- $table->foreignId('team_id')->constrained()->onDelete('cascade');
- $table->foreignId('project_id')->nullable()->constrained()->onDelete('cascade');
- $table->foreignId('environment_id')->nullable()->constrained()->onDelete('cascade');
- $table->unique(['key', 'project_id', 'team_id']);
- $table->unique(['key', 'environment_id', 'team_id']);
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('shared_environment_variables');
- }
-};
diff --git a/database/migrations/2024_01_24_095449_add_concurrent_number_of_builds_per_server.php b/database/migrations/2024_01_24_095449_add_concurrent_number_of_builds_per_server.php
deleted file mode 100644
index f5d87d13df..0000000000
--- a/database/migrations/2024_01_24_095449_add_concurrent_number_of_builds_per_server.php
+++ /dev/null
@@ -1,28 +0,0 @@
-integer('concurrent_builds')->default(2);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('concurrent_builds');
- });
- }
-};
diff --git a/database/migrations/2024_01_25_073212_add_server_id_to_queues.php b/database/migrations/2024_01_25_073212_add_server_id_to_queues.php
deleted file mode 100644
index 1441ad19fd..0000000000
--- a/database/migrations/2024_01_25_073212_add_server_id_to_queues.php
+++ /dev/null
@@ -1,28 +0,0 @@
-integer('server_id')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('server_id');
- });
- }
-};
diff --git a/database/migrations/2024_01_27_164724_add_application_name_and_deployment_url_to_queue.php b/database/migrations/2024_01_27_164724_add_application_name_and_deployment_url_to_queue.php
deleted file mode 100644
index 9d4f24a327..0000000000
--- a/database/migrations/2024_01_27_164724_add_application_name_and_deployment_url_to_queue.php
+++ /dev/null
@@ -1,32 +0,0 @@
-string('application_name')->nullable();
- $table->string('server_name')->nullable();
- $table->string('deployment_url')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('application_name');
- $table->dropColumn('server_name');
- $table->dropColumn('deployment_url');
- });
- }
-};
diff --git a/database/migrations/2024_01_29_072322_change_env_variable_length.php b/database/migrations/2024_01_29_072322_change_env_variable_length.php
deleted file mode 100644
index 65194954fc..0000000000
--- a/database/migrations/2024_01_29_072322_change_env_variable_length.php
+++ /dev/null
@@ -1,28 +0,0 @@
-text('value')->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('shared_environment_variables', function (Blueprint $table) {
- $table->string('value')->change();
- });
- }
-};
diff --git a/database/migrations/2024_01_29_145200_add_custom_docker_run_options.php b/database/migrations/2024_01_29_145200_add_custom_docker_run_options.php
deleted file mode 100644
index 30949ea808..0000000000
--- a/database/migrations/2024_01_29_145200_add_custom_docker_run_options.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('custom_docker_run_options')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('custom_docker_run_options');
- });
- }
-};
diff --git a/database/migrations/2024_02_01_111228_create_tags_table.php b/database/migrations/2024_02_01_111228_create_tags_table.php
deleted file mode 100644
index 259a0c30db..0000000000
--- a/database/migrations/2024_02_01_111228_create_tags_table.php
+++ /dev/null
@@ -1,38 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name')->unique();
- $table->foreignId('team_id')->nullable()->constrained()->onDelete('cascade');
- $table->timestamps();
- });
- Schema::create('taggables', function (Blueprint $table) {
- $table->unsignedBigInteger('tag_id');
- $table->unsignedBigInteger('taggable_id');
- $table->string('taggable_type');
- $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
- $table->unique(['tag_id', 'taggable_id', 'taggable_type'], 'taggable_unique'); // Composite unique index
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('taggables');
- Schema::dropIfExists('tags');
- }
-};
diff --git a/database/migrations/2024_02_05_105215_add_destination_to_app_deployments.php b/database/migrations/2024_02_05_105215_add_destination_to_app_deployments.php
deleted file mode 100644
index 29f43dd3fc..0000000000
--- a/database/migrations/2024_02_05_105215_add_destination_to_app_deployments.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('destination_id')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('destination_id');
- });
- }
-};
diff --git a/database/migrations/2024_02_06_132748_add_additional_destinations.php b/database/migrations/2024_02_06_132748_add_additional_destinations.php
deleted file mode 100644
index 32e7f5b188..0000000000
--- a/database/migrations/2024_02_06_132748_add_additional_destinations.php
+++ /dev/null
@@ -1,37 +0,0 @@
-id();
- $table->foreignId('application_id')->constrained()->onDelete('cascade');
- $table->foreignId('server_id')->constrained()->onDelete('cascade');
- $table->string('status')->default('exited');
- $table->foreignId('standalone_docker_id')->constrained()->onDelete('cascade');
- $table->timestamps();
- });
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('additional_destinations');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('additional_destinations');
- Schema::table('applications', function (Blueprint $table) {
- $table->string('additional_destinations')->nullable()->after('destination');
- });
- }
-};
diff --git a/database/migrations/2024_02_08_075523_add_post_deployment_to_applications.php b/database/migrations/2024_02_08_075523_add_post_deployment_to_applications.php
deleted file mode 100644
index 6d3a748969..0000000000
--- a/database/migrations/2024_02_08_075523_add_post_deployment_to_applications.php
+++ /dev/null
@@ -1,34 +0,0 @@
-string('post_deployment_command')->nullable();
- $table->string('post_deployment_command_container')->nullable();
- $table->string('pre_deployment_command')->nullable();
- $table->string('pre_deployment_command_container')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('post_deployment_command');
- $table->dropColumn('post_deployment_command_container');
- $table->dropColumn('pre_deployment_command');
- $table->dropColumn('pre_deployment_command_container');
- });
- }
-};
diff --git a/database/migrations/2024_02_08_112304_add_dynamic_timeout_for_deployments.php b/database/migrations/2024_02_08_112304_add_dynamic_timeout_for_deployments.php
deleted file mode 100644
index f45bd7a2a4..0000000000
--- a/database/migrations/2024_02_08_112304_add_dynamic_timeout_for_deployments.php
+++ /dev/null
@@ -1,28 +0,0 @@
-integer('dynamic_timeout')->default(3600);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('dynamic_timeout');
- });
- }
-};
diff --git a/database/migrations/2024_02_15_101921_add_consistent_application_container_name.php b/database/migrations/2024_02_15_101921_add_consistent_application_container_name.php
deleted file mode 100644
index 827b4c426d..0000000000
--- a/database/migrations/2024_02_15_101921_add_consistent_application_container_name.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_consistent_container_name_enabled')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_consistent_container_name_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_02_15_192025_add_is_gzip_enabled_to_services.php b/database/migrations/2024_02_15_192025_add_is_gzip_enabled_to_services.php
deleted file mode 100644
index 5f724e5cea..0000000000
--- a/database/migrations/2024_02_15_192025_add_is_gzip_enabled_to_services.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_gzip_enabled')->default(true);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('service_applications', function (Blueprint $table) {
- $table->dropColumn('is_gzip_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_02_20_165045_add_permissions_to_github_app.php b/database/migrations/2024_02_20_165045_add_permissions_to_github_app.php
deleted file mode 100644
index fedb7395f3..0000000000
--- a/database/migrations/2024_02_20_165045_add_permissions_to_github_app.php
+++ /dev/null
@@ -1,34 +0,0 @@
-string('contents')->nullable();
- $table->string('metadata')->nullable();
- $table->string('pull_requests')->nullable();
- $table->string('administration')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('github_apps', function (Blueprint $table) {
- $table->dropColumn('contents');
- $table->dropColumn('metadata');
- $table->dropColumn('pull_requests');
- $table->dropColumn('administration');
- });
- }
-};
diff --git a/database/migrations/2024_02_22_090900_add_only_this_server_deployment.php b/database/migrations/2024_02_22_090900_add_only_this_server_deployment.php
deleted file mode 100644
index 8dd9e10313..0000000000
--- a/database/migrations/2024_02_22_090900_add_only_this_server_deployment.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('only_this_server')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('only_this_server');
- });
- }
-};
diff --git a/database/migrations/2024_02_23_143119_add_custom_server_limits_to_teams_ultimate.php b/database/migrations/2024_02_23_143119_add_custom_server_limits_to_teams_ultimate.php
deleted file mode 100644
index 7e1fe67f51..0000000000
--- a/database/migrations/2024_02_23_143119_add_custom_server_limits_to_teams_ultimate.php
+++ /dev/null
@@ -1,28 +0,0 @@
-integer('custom_server_limit')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn('custom_server_limit');
- });
- }
-};
diff --git a/database/migrations/2024_02_25_222150_add_server_force_disabled_field.php b/database/migrations/2024_02_25_222150_add_server_force_disabled_field.php
deleted file mode 100644
index 8509a99098..0000000000
--- a/database/migrations/2024_02_25_222150_add_server_force_disabled_field.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('force_disabled')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('force_disabled');
- });
- }
-};
diff --git a/database/migrations/2024_03_04_092244_add_gzip_enabled_and_stripprefix_settings.php b/database/migrations/2024_03_04_092244_add_gzip_enabled_and_stripprefix_settings.php
deleted file mode 100644
index 5d23da60e8..0000000000
--- a/database/migrations/2024_03_04_092244_add_gzip_enabled_and_stripprefix_settings.php
+++ /dev/null
@@ -1,44 +0,0 @@
-boolean('is_gzip_enabled')->default(true);
- $table->boolean('is_stripprefix_enabled')->default(true);
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->boolean('is_stripprefix_enabled')->default(true);
- });
- Schema::table('service_databases', function (Blueprint $table) {
- $table->boolean('is_gzip_enabled')->default(true);
- $table->boolean('is_stripprefix_enabled')->default(true);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_gzip_enabled');
- $table->dropColumn('is_stripprefix_enabled');
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->dropColumn('is_stripprefix_enabled');
- });
- Schema::table('service_databases', function (Blueprint $table) {
- $table->dropColumn('is_gzip_enabled');
- $table->dropColumn('is_stripprefix_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_03_07_115054_add_notifications_notification_disable.php b/database/migrations/2024_03_07_115054_add_notifications_notification_disable.php
deleted file mode 100644
index 8633b971ef..0000000000
--- a/database/migrations/2024_03_07_115054_add_notifications_notification_disable.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_notification_notifications_enabled')->default(true);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('users', function (Blueprint $table) {
- $table->dropColumn('is_notification_notifications_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_03_08_180457_nullable_password.php b/database/migrations/2024_03_08_180457_nullable_password.php
deleted file mode 100644
index 3bd91b0bea..0000000000
--- a/database/migrations/2024_03_08_180457_nullable_password.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('password')->nullable()->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('users', function (Blueprint $table) {
- $table->string('password')->nullable(false)->change();
- });
- }
-};
diff --git a/database/migrations/2024_03_11_150013_create_oauth_settings.php b/database/migrations/2024_03_11_150013_create_oauth_settings.php
deleted file mode 100644
index c2178426d7..0000000000
--- a/database/migrations/2024_03_11_150013_create_oauth_settings.php
+++ /dev/null
@@ -1,33 +0,0 @@
-id();
- $table->string('provider')->unique();
- $table->boolean('enabled')->default(false);
- $table->string('client_id')->nullable();
- $table->text('client_secret')->nullable();
- $table->string('redirect_uri')->nullable();
- $table->string('tenant')->nullable();
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('oauth_settings');
- }
-};
diff --git a/database/migrations/2024_03_14_214402_add_multiline_envs.php b/database/migrations/2024_03_14_214402_add_multiline_envs.php
deleted file mode 100644
index b3e869bc37..0000000000
--- a/database/migrations/2024_03_14_214402_add_multiline_envs.php
+++ /dev/null
@@ -1,34 +0,0 @@
-boolean('is_multiline')->default(false);
- });
- Schema::table('shared_environment_variables', function (Blueprint $table) {
- $table->boolean('is_multiline')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('is_multiline');
- });
- Schema::table('shared_environment_variables', function (Blueprint $table) {
- $table->dropColumn('is_multiline');
- });
- }
-};
diff --git a/database/migrations/2024_03_18_101440_add_version_of_envs.php b/database/migrations/2024_03_18_101440_add_version_of_envs.php
deleted file mode 100644
index 9973f88bd0..0000000000
--- a/database/migrations/2024_03_18_101440_add_version_of_envs.php
+++ /dev/null
@@ -1,34 +0,0 @@
-string('version')->default('4.0.0-beta.239');
- });
- Schema::table('shared_environment_variables', function (Blueprint $table) {
- $table->string('version')->default('4.0.0-beta.239');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('version');
- });
- Schema::table('shared_environment_variables', function (Blueprint $table) {
- $table->dropColumn('version');
- });
- }
-};
diff --git a/database/migrations/2024_03_22_080914_remove_popup_notifications.php b/database/migrations/2024_03_22_080914_remove_popup_notifications.php
deleted file mode 100644
index ccb270093f..0000000000
--- a/database/migrations/2024_03_22_080914_remove_popup_notifications.php
+++ /dev/null
@@ -1,30 +0,0 @@
-dropColumn('is_notification_sponsorship_enabled');
- $table->dropColumn('is_notification_notifications_enabled');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('users', function (Blueprint $table) {
- $table->boolean('is_notification_sponsorship_enabled')->default(true);
- $table->boolean('is_notification_notifications_enabled')->default(true);
- });
- }
-};
diff --git a/database/migrations/2024_03_26_122110_remove_realtime_notifications.php b/database/migrations/2024_03_26_122110_remove_realtime_notifications.php
deleted file mode 100644
index 6d5d0e0413..0000000000
--- a/database/migrations/2024_03_26_122110_remove_realtime_notifications.php
+++ /dev/null
@@ -1,28 +0,0 @@
-dropColumn('is_notification_realtime_enabled');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('users', function (Blueprint $table) {
- $table->boolean('is_notification_realtime_enabled')->default(true);
- });
- }
-};
diff --git a/database/migrations/2024_03_28_114620_add_watch_paths_to_apps.php b/database/migrations/2024_03_28_114620_add_watch_paths_to_apps.php
deleted file mode 100644
index d58adcd623..0000000000
--- a/database/migrations/2024_03_28_114620_add_watch_paths_to_apps.php
+++ /dev/null
@@ -1,28 +0,0 @@
-longText('watch_paths')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('watch_paths');
- });
- }
-};
diff --git a/database/migrations/2024_04_09_095517_make_custom_docker_commands_longer.php b/database/migrations/2024_04_09_095517_make_custom_docker_commands_longer.php
deleted file mode 100644
index b3f2c1920c..0000000000
--- a/database/migrations/2024_04_09_095517_make_custom_docker_commands_longer.php
+++ /dev/null
@@ -1,28 +0,0 @@
-text('custom_docker_run_options')->nullable()->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->string('custom_docker_run_options')->nullable()->change();
- });
- }
-};
diff --git a/database/migrations/2024_04_10_071920_create_standalone_keydbs_table.php b/database/migrations/2024_04_10_071920_create_standalone_keydbs_table.php
deleted file mode 100644
index 4cea931218..0000000000
--- a/database/migrations/2024_04_10_071920_create_standalone_keydbs_table.php
+++ /dev/null
@@ -1,64 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('description')->nullable();
-
- $table->text('keydb_password');
- $table->longText('keydb_conf')->nullable();
-
- $table->boolean('is_log_drain_enabled')->default(false);
- $table->boolean('is_include_timestamps')->default(false);
- $table->softDeletes();
-
- $table->string('status')->default('exited');
-
- $table->string('image')->default('eqalpha/keydb:latest');
-
- $table->boolean('is_public')->default(false);
- $table->integer('public_port')->nullable();
- $table->text('ports_mappings')->nullable();
-
- $table->string('limits_memory')->default('0');
- $table->string('limits_memory_swap')->default('0');
- $table->integer('limits_memory_swappiness')->default(60);
- $table->string('limits_memory_reservation')->default('0');
-
- $table->string('limits_cpus')->default('0');
- $table->string('limits_cpuset')->nullable()->default(null);
- $table->integer('limits_cpu_shares')->default(1024);
-
- $table->timestamp('started_at')->nullable();
- $table->morphs('destination');
- $table->foreignId('environment_id')->nullable();
- $table->timestamps();
- });
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->foreignId('standalone_keydb_id')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('standalone_keydbs');
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('standalone_keydb_id');
- });
- }
-};
diff --git a/database/migrations/2024_04_10_082220_create_standalone_dragonflies_table.php b/database/migrations/2024_04_10_082220_create_standalone_dragonflies_table.php
deleted file mode 100644
index 84bd6ea6f5..0000000000
--- a/database/migrations/2024_04_10_082220_create_standalone_dragonflies_table.php
+++ /dev/null
@@ -1,63 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('description')->nullable();
-
- $table->text('dragonfly_password');
-
- $table->boolean('is_log_drain_enabled')->default(false);
- $table->boolean('is_include_timestamps')->default(false);
- $table->softDeletes();
-
- $table->string('status')->default('exited');
-
- $table->string('image')->default('docker.dragonflydb.io/dragonflydb/dragonfly');
-
- $table->boolean('is_public')->default(false);
- $table->integer('public_port')->nullable();
- $table->text('ports_mappings')->nullable();
-
- $table->string('limits_memory')->default('0');
- $table->string('limits_memory_swap')->default('0');
- $table->integer('limits_memory_swappiness')->default(60);
- $table->string('limits_memory_reservation')->default('0');
-
- $table->string('limits_cpus')->default('0');
- $table->string('limits_cpuset')->nullable()->default(null);
- $table->integer('limits_cpu_shares')->default(1024);
-
- $table->timestamp('started_at')->nullable();
- $table->morphs('destination');
- $table->foreignId('environment_id')->nullable();
- $table->timestamps();
- });
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->foreignId('standalone_dragonfly_id')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('standalone_dragonflies');
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('standalone_dragonfly_id');
- });
- }
-};
diff --git a/database/migrations/2024_04_10_091519_create_standalone_clickhouses_table.php b/database/migrations/2024_04_10_091519_create_standalone_clickhouses_table.php
deleted file mode 100644
index 7433948b99..0000000000
--- a/database/migrations/2024_04_10_091519_create_standalone_clickhouses_table.php
+++ /dev/null
@@ -1,64 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->string('name');
- $table->string('description')->nullable();
-
- $table->string('clickhouse_admin_user')->default('default');
- $table->text('clickhouse_admin_password');
-
- $table->boolean('is_log_drain_enabled')->default(false);
- $table->boolean('is_include_timestamps')->default(false);
- $table->softDeletes();
-
- $table->string('status')->default('exited');
-
- $table->string('image')->default('bitnami/clickhouse');
-
- $table->boolean('is_public')->default(false);
- $table->integer('public_port')->nullable();
- $table->text('ports_mappings')->nullable();
-
- $table->string('limits_memory')->default('0');
- $table->string('limits_memory_swap')->default('0');
- $table->integer('limits_memory_swappiness')->default(60);
- $table->string('limits_memory_reservation')->default('0');
-
- $table->string('limits_cpus')->default('0');
- $table->string('limits_cpuset')->nullable()->default(null);
- $table->integer('limits_cpu_shares')->default(1024);
-
- $table->timestamp('started_at')->nullable();
- $table->morphs('destination');
- $table->foreignId('environment_id')->nullable();
- $table->timestamps();
- });
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->foreignId('standalone_clickhouse_id')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('standalone_clickhouses');
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('standalone_clickhouse_id');
- });
- }
-};
diff --git a/database/migrations/2024_04_10_124015_add_permission_local_file_volumes.php b/database/migrations/2024_04_10_124015_add_permission_local_file_volumes.php
deleted file mode 100644
index a2487ccd6c..0000000000
--- a/database/migrations/2024_04_10_124015_add_permission_local_file_volumes.php
+++ /dev/null
@@ -1,30 +0,0 @@
-string('chown')->nullable();
- $table->string('chmod')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('local_file_volumes', function (Blueprint $table) {
- $table->dropColumn('chown');
- $table->dropColumn('chmod');
- });
- }
-};
diff --git a/database/migrations/2024_04_12_092337_add_config_hash_to_other_resources.php b/database/migrations/2024_04_12_092337_add_config_hash_to_other_resources.php
deleted file mode 100644
index 83365f69e5..0000000000
--- a/database/migrations/2024_04_12_092337_add_config_hash_to_other_resources.php
+++ /dev/null
@@ -1,76 +0,0 @@
-string('config_hash')->nullable();
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->string('config_hash')->nullable();
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->string('config_hash')->nullable();
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->string('config_hash')->nullable();
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->string('config_hash')->nullable();
- });
- Schema::table('standalone_keydbs', function (Blueprint $table) {
- $table->string('config_hash')->nullable();
- });
- Schema::table('standalone_dragonflies', function (Blueprint $table) {
- $table->string('config_hash')->nullable();
- });
- Schema::table('standalone_clickhouses', function (Blueprint $table) {
- $table->string('config_hash')->nullable();
- });
- Schema::table('services', function (Blueprint $table) {
- $table->string('config_hash')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->dropColumn('config_hash');
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->dropColumn('config_hash');
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->dropColumn('config_hash');
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->dropColumn('config_hash');
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->dropColumn('config_hash');
- });
- Schema::table('standalone_keydbs', function (Blueprint $table) {
- $table->dropColumn('config_hash');
- });
- Schema::table('standalone_dragonflies', function (Blueprint $table) {
- $table->dropColumn('config_hash');
- });
- Schema::table('standalone_clickhouses', function (Blueprint $table) {
- $table->dropColumn('config_hash');
- });
- Schema::table('services', function (Blueprint $table) {
- $table->dropColumn('config_hash');
- });
- }
-};
diff --git a/database/migrations/2024_04_15_094703_add_literal_variables.php b/database/migrations/2024_04_15_094703_add_literal_variables.php
deleted file mode 100644
index c03194975c..0000000000
--- a/database/migrations/2024_04_15_094703_add_literal_variables.php
+++ /dev/null
@@ -1,34 +0,0 @@
-boolean('is_literal')->default(false);
- });
- Schema::table('shared_environment_variables', function (Blueprint $table) {
- $table->boolean('is_literal')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('is_literal');
- });
- Schema::table('shared_environment_variables', function (Blueprint $table) {
- $table->dropColumn('is_literal');
- });
- }
-};
diff --git a/database/migrations/2024_04_16_083919_add_service_type_on_creation.php b/database/migrations/2024_04_16_083919_add_service_type_on_creation.php
deleted file mode 100644
index ce91bddbb5..0000000000
--- a/database/migrations/2024_04_16_083919_add_service_type_on_creation.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('service_type')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('services', function (Blueprint $table) {
- $table->dropColumn('service_type');
- });
- }
-};
diff --git a/database/migrations/2024_04_17_132541_add_rollback_queues.php b/database/migrations/2024_04_17_132541_add_rollback_queues.php
deleted file mode 100644
index 27865cf0db..0000000000
--- a/database/migrations/2024_04_17_132541_add_rollback_queues.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('rollback')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('rollback');
- });
- }
-};
diff --git a/database/migrations/2024_04_25_073615_add_docker_network_to_application_settings.php b/database/migrations/2024_04_25_073615_add_docker_network_to_application_settings.php
deleted file mode 100644
index bea410eab1..0000000000
--- a/database/migrations/2024_04_25_073615_add_docker_network_to_application_settings.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('connect_to_docker_network')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('connect_to_docker_network');
- });
- }
-};
diff --git a/database/migrations/2024_04_29_111956_add_custom_hc_indicator_apps.php b/database/migrations/2024_04_29_111956_add_custom_hc_indicator_apps.php
deleted file mode 100644
index b5a97f0ebd..0000000000
--- a/database/migrations/2024_04_29_111956_add_custom_hc_indicator_apps.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('custom_healthcheck_found')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('custom_healthcheck_found');
- });
- }
-};
diff --git a/database/migrations/2024_05_06_093236_add_custom_name_to_application_settings.php b/database/migrations/2024_05_06_093236_add_custom_name_to_application_settings.php
deleted file mode 100644
index e2d68d2401..0000000000
--- a/database/migrations/2024_05_06_093236_add_custom_name_to_application_settings.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('custom_internal_name')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('custom_internal_name');
- });
- }
-};
diff --git a/database/migrations/2024_05_07_124019_add_server_metrics.php b/database/migrations/2024_05_07_124019_add_server_metrics.php
deleted file mode 100644
index 40c74850bb..0000000000
--- a/database/migrations/2024_05_07_124019_add_server_metrics.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_metrics_enabled')->default(true);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('servers', function (Blueprint $table) {
- $table->dropColumn('is_metrics_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_05_10_085215_make_stripe_comment_longer.php b/database/migrations/2024_05_10_085215_make_stripe_comment_longer.php
deleted file mode 100644
index a51896f42d..0000000000
--- a/database/migrations/2024_05_10_085215_make_stripe_comment_longer.php
+++ /dev/null
@@ -1,28 +0,0 @@
-longText('stripe_comment')->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('subscriptions', function (Blueprint $table) {
- $table->string('stripe_comment')->change();
- });
- }
-};
diff --git a/database/migrations/2024_05_15_091757_add_commit_message_to_app_deployment_queue.php b/database/migrations/2024_05_15_091757_add_commit_message_to_app_deployment_queue.php
deleted file mode 100644
index 78608f5038..0000000000
--- a/database/migrations/2024_05_15_091757_add_commit_message_to_app_deployment_queue.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('commit_message', 50)->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('commit_message');
- });
- }
-};
diff --git a/database/migrations/2024_05_15_151236_add_container_escape_toggle.php b/database/migrations/2024_05_15_151236_add_container_escape_toggle.php
deleted file mode 100644
index aa1384518b..0000000000
--- a/database/migrations/2024_05_15_151236_add_container_escape_toggle.php
+++ /dev/null
@@ -1,34 +0,0 @@
-boolean('is_container_label_escape_enabled')->default(true);
- });
- Schema::table('services', function (Blueprint $table) {
- $table->boolean('is_container_label_escape_enabled')->default(true);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_container_label_escape_enabled');
- });
- Schema::table('services', function (Blueprint $table) {
- $table->dropColumn('is_container_label_escape_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_05_17_082012_add_env_sorting_toggle.php b/database/migrations/2024_05_17_082012_add_env_sorting_toggle.php
deleted file mode 100644
index d4e120e2b4..0000000000
--- a/database/migrations/2024_05_17_082012_add_env_sorting_toggle.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_env_sorting_enabled')->default(true);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_env_sorting_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_05_21_125739_add_scheduled_tasks_notification_to_teams.php b/database/migrations/2024_05_21_125739_add_scheduled_tasks_notification_to_teams.php
deleted file mode 100644
index 0fcbb06550..0000000000
--- a/database/migrations/2024_05_21_125739_add_scheduled_tasks_notification_to_teams.php
+++ /dev/null
@@ -1,34 +0,0 @@
-boolean('telegram_notifications_scheduled_tasks')->default(true);
- $table->boolean('smtp_notifications_scheduled_tasks')->default(false)->after('smtp_notifications_status_changes');
- $table->boolean('discord_notifications_scheduled_tasks')->default(true)->after('discord_notifications_status_changes');
- $table->text('telegram_notifications_scheduled_tasks_thread_id')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn('telegram_notifications_scheduled_tasks');
- $table->dropColumn('smtp_notifications_scheduled_tasks');
- $table->dropColumn('discord_notifications_scheduled_tasks');
- $table->dropColumn('telegram_notifications_scheduled_tasks_thread_id');
- });
- }
-};
diff --git a/database/migrations/2024_05_22_103942_change_pre_post_deployment_commands_length_in_applications.php b/database/migrations/2024_05_22_103942_change_pre_post_deployment_commands_length_in_applications.php
deleted file mode 100644
index 0803c97788..0000000000
--- a/database/migrations/2024_05_22_103942_change_pre_post_deployment_commands_length_in_applications.php
+++ /dev/null
@@ -1,30 +0,0 @@
-text('post_deployment_command')->nullable()->change();
- $table->text('pre_deployment_command')->nullable()->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->string('post_deployment_command')->nullable()->change();
- $table->string('pre_deployment_command')->nullable()->change();
- });
- }
-};
diff --git a/database/migrations/2024_05_23_091713_add_gitea_webhook_to_applications.php b/database/migrations/2024_05_23_091713_add_gitea_webhook_to_applications.php
deleted file mode 100644
index b46a072033..0000000000
--- a/database/migrations/2024_05_23_091713_add_gitea_webhook_to_applications.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('manual_webhook_secret_gitea')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('manual_webhook_secret_gitea');
- });
- }
-};
diff --git a/database/migrations/2024_06_05_101019_add_docker_compose_pr_domains.php b/database/migrations/2024_06_05_101019_add_docker_compose_pr_domains.php
deleted file mode 100644
index a4b8ea35b8..0000000000
--- a/database/migrations/2024_06_05_101019_add_docker_compose_pr_domains.php
+++ /dev/null
@@ -1,28 +0,0 @@
-text('docker_compose_domains')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_previews', function (Blueprint $table) {
- $table->dropColumn('docker_compose_domains');
- });
- }
-};
diff --git a/database/migrations/2024_06_06_103938_change_pr_issue_commend_id_type.php b/database/migrations/2024_06_06_103938_change_pr_issue_commend_id_type.php
deleted file mode 100644
index c7d71203b8..0000000000
--- a/database/migrations/2024_06_06_103938_change_pr_issue_commend_id_type.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('pull_request_issue_comment_id')->nullable()->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_previews', function (Blueprint $table) {
- $table->integer('pull_request_issue_comment_id')->nullable()->change();
- });
- }
-};
diff --git a/database/migrations/2024_06_11_081614_add_www_non_www_redirect.php b/database/migrations/2024_06_11_081614_add_www_non_www_redirect.php
deleted file mode 100644
index 231c09ceba..0000000000
--- a/database/migrations/2024_06_11_081614_add_www_non_www_redirect.php
+++ /dev/null
@@ -1,28 +0,0 @@
-enum('redirect', ['www', 'non-www', 'both'])->default('both')->after('domain');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('redirect');
- });
- }
-};
diff --git a/database/migrations/2024_06_18_105948_move_server_metrics.php b/database/migrations/2024_06_18_105948_move_server_metrics.php
deleted file mode 100644
index a6bccd16a1..0000000000
--- a/database/migrations/2024_06_18_105948_move_server_metrics.php
+++ /dev/null
@@ -1,40 +0,0 @@
-dropColumn('is_metrics_enabled');
- });
- Schema::table('server_settings', function (Blueprint $table) {
- $table->boolean('is_metrics_enabled')->default(false);
- $table->integer('metrics_refresh_rate_seconds')->default(5);
- $table->integer('metrics_history_days')->default(30);
- $table->string('metrics_token')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('servers', function (Blueprint $table) {
- $table->boolean('is_metrics_enabled')->default(true);
- });
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('is_metrics_enabled');
- $table->dropColumn('metrics_refresh_rate_seconds');
- $table->dropColumn('metrics_history_days');
- $table->dropColumn('metrics_token');
- });
- }
-};
diff --git a/database/migrations/2024_06_20_102551_add_server_api_sentinel.php b/database/migrations/2024_06_20_102551_add_server_api_sentinel.php
deleted file mode 100644
index b840195af6..0000000000
--- a/database/migrations/2024_06_20_102551_add_server_api_sentinel.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_server_api_enabled')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('is_server_api_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_06_21_143358_add_api_deployment_type.php b/database/migrations/2024_06_21_143358_add_api_deployment_type.php
deleted file mode 100644
index 03f4d47963..0000000000
--- a/database/migrations/2024_06_21_143358_add_api_deployment_type.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_api')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('is_api');
- });
- }
-};
diff --git a/database/migrations/2024_06_22_081140_alter_instance_settings_add_instance_name.php b/database/migrations/2024_06_22_081140_alter_instance_settings_add_instance_name.php
deleted file mode 100644
index 1687e047c0..0000000000
--- a/database/migrations/2024_06_22_081140_alter_instance_settings_add_instance_name.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('instance_name')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('instance_name');
- });
- }
-};
diff --git a/database/migrations/2024_06_25_184323_update_db.php b/database/migrations/2024_06_25_184323_update_db.php
deleted file mode 100644
index d9cddb15f9..0000000000
--- a/database/migrations/2024_06_25_184323_update_db.php
+++ /dev/null
@@ -1,95 +0,0 @@
-dropColumn('docker_compose_pr_location');
- $table->dropColumn('docker_compose_pr');
- $table->dropColumn('docker_compose_pr_raw');
- });
- Schema::table('subscriptions', function (Blueprint $table) {
- $table->dropColumn('lemon_subscription_id');
- $table->dropColumn('lemon_order_id');
- $table->dropColumn('lemon_product_id');
- $table->dropColumn('lemon_variant_id');
- $table->dropColumn('lemon_variant_name');
- $table->dropColumn('lemon_customer_id');
- $table->dropColumn('lemon_status');
- $table->dropColumn('lemon_renews_at');
- $table->dropColumn('lemon_update_payment_menthod_url');
- $table->dropColumn('lemon_trial_ends_at');
- $table->dropColumn('lemon_ends_at');
- });
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->string('uuid')->nullable()->after('id');
- });
-
- EnvironmentVariable::all()->each(function (EnvironmentVariable $environmentVariable) {
- $environmentVariable->update([
- 'uuid' => (string) new Cuid2,
- ]);
- });
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->string('uuid')->nullable(false)->change();
- });
- Schema::table('server_settings', function (Blueprint $table) {
- $table->integer('metrics_history_days')->default(7)->change();
- });
-
- DB::table('server_settings')->update(['metrics_history_days' => 7]);
- } catch (\Exception $e) {
- Log::error('Error updating db: '.$e->getMessage());
- }
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->string('docker_compose_pr_location')->nullable()->default('/docker-compose.yaml')->after('docker_compose_location');
- $table->longText('docker_compose_pr')->nullable()->after('docker_compose_location');
- $table->longText('docker_compose_pr_raw')->nullable()->after('docker_compose');
- });
- Schema::table('subscriptions', function (Blueprint $table) {
- $table->string('lemon_subscription_id')->nullable()->after('stripe_subscription_id');
- $table->string('lemon_order_id')->nullable()->after('lemon_subscription_id');
- $table->string('lemon_product_id')->nullable()->after('lemon_order_id');
- $table->string('lemon_variant_id')->nullable()->after('lemon_product_id');
- $table->string('lemon_variant_name')->nullable()->after('lemon_variant_id');
- $table->string('lemon_customer_id')->nullable()->after('lemon_variant_name');
- $table->string('lemon_status')->nullable()->after('lemon_customer_id');
- $table->timestamp('lemon_renews_at')->nullable()->after('lemon_status');
- $table->string('lemon_update_payment_menthod_url')->nullable()->after('lemon_renews_at');
- $table->timestamp('lemon_trial_ends_at')->nullable()->after('lemon_update_payment_menthod_url');
- $table->timestamp('lemon_ends_at')->nullable()->after('lemon_trial_ends_at');
- });
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('uuid');
- });
- Schema::table('server_settings', function (Blueprint $table) {
- $table->integer('metrics_history_days')->default(30)->change();
- });
- Server::all()->each(function (Server $server) {
- $server->settings->update([
- 'metrics_history_days' => 30,
- ]);
- });
- }
-};
diff --git a/database/migrations/2024_07_01_115528_add_is_api_allowed_and_iplist.php b/database/migrations/2024_07_01_115528_add_is_api_allowed_and_iplist.php
deleted file mode 100644
index b319adb70e..0000000000
--- a/database/migrations/2024_07_01_115528_add_is_api_allowed_and_iplist.php
+++ /dev/null
@@ -1,24 +0,0 @@
-boolean('is_api_enabled')->default(true);
- $table->text('allowed_ips')->nullable();
- });
- }
-
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('is_api_enabled');
- $table->dropColumn('allowed_ips');
- });
- }
-};
diff --git a/database/migrations/2024_07_05_120217_remove_unique_from_tag_names.php b/database/migrations/2024_07_05_120217_remove_unique_from_tag_names.php
deleted file mode 100644
index 301de814bc..0000000000
--- a/database/migrations/2024_07_05_120217_remove_unique_from_tag_names.php
+++ /dev/null
@@ -1,28 +0,0 @@
-dropUnique(['name']);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('tags', function (Blueprint $table) {
- $table->unique(['name']);
- });
- }
-};
diff --git a/database/migrations/2024_07_11_083719_application_compose_versions.php b/database/migrations/2024_07_11_083719_application_compose_versions.php
deleted file mode 100644
index 9cdbb98d70..0000000000
--- a/database/migrations/2024_07_11_083719_application_compose_versions.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('compose_parsing_version')->default('1');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('compose_parsing_version');
- });
- }
-};
diff --git a/database/migrations/2024_07_17_123828_add_is_container_labels_readonly.php b/database/migrations/2024_07_17_123828_add_is_container_labels_readonly.php
deleted file mode 100644
index eb36946a48..0000000000
--- a/database/migrations/2024_07_17_123828_add_is_container_labels_readonly.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_container_label_readonly_enabled')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_container_label_readonly_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_07_18_110424_create_application_settings_is_preserve_repository_enabled.php b/database/migrations/2024_07_18_110424_create_application_settings_is_preserve_repository_enabled.php
deleted file mode 100644
index 25dd0ef162..0000000000
--- a/database/migrations/2024_07_18_110424_create_application_settings_is_preserve_repository_enabled.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_preserve_repository_enabled')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('is_preserve_repository_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_07_18_123458_add_force_cleanup_server.php b/database/migrations/2024_07_18_123458_add_force_cleanup_server.php
deleted file mode 100644
index ea3695b3f5..0000000000
--- a/database/migrations/2024_07_18_123458_add_force_cleanup_server.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_force_cleanup_enabled')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('is_force_cleanup_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_07_19_132617_disable_healtcheck_by_default.php b/database/migrations/2024_07_19_132617_disable_healtcheck_by_default.php
deleted file mode 100644
index 5de50de0c1..0000000000
--- a/database/migrations/2024_07_19_132617_disable_healtcheck_by_default.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('health_check_enabled')->default(false)->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->boolean('health_check_enabled')->default(true)->change();
- });
- }
-};
diff --git a/database/migrations/2024_07_23_112710_add_validation_logs_to_servers.php b/database/migrations/2024_07_23_112710_add_validation_logs_to_servers.php
deleted file mode 100644
index d3293620ba..0000000000
--- a/database/migrations/2024_07_23_112710_add_validation_logs_to_servers.php
+++ /dev/null
@@ -1,28 +0,0 @@
-text('validation_logs')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('servers', function (Blueprint $table) {
- $table->dropColumn('validation_logs');
- });
- }
-};
diff --git a/database/migrations/2024_08_05_142659_add_update_frequency_settings.php b/database/migrations/2024_08_05_142659_add_update_frequency_settings.php
deleted file mode 100644
index 0060b8d1d8..0000000000
--- a/database/migrations/2024_08_05_142659_add_update_frequency_settings.php
+++ /dev/null
@@ -1,32 +0,0 @@
-string('auto_update_frequency')->default('0 0 * * *');
- $table->string('update_check_frequency')->default('0 * * * *');
- $table->boolean('new_version_available')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('update_check_frequency');
- $table->dropColumn('auto_update_frequency');
- $table->dropColumn('new_version_available');
- });
- }
-};
diff --git a/database/migrations/2024_08_07_155324_add_proxy_label_chooser.php b/database/migrations/2024_08_07_155324_add_proxy_label_chooser.php
deleted file mode 100644
index 7bc8a06572..0000000000
--- a/database/migrations/2024_08_07_155324_add_proxy_label_chooser.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('generate_exact_labels')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('generate_exact_labels');
- });
- }
-};
diff --git a/database/migrations/2024_08_09_215659_add_server_cleanup_fields_to_server_settings_table.php b/database/migrations/2024_08_09_215659_add_server_cleanup_fields_to_server_settings_table.php
deleted file mode 100644
index e3bdc68c60..0000000000
--- a/database/migrations/2024_08_09_215659_add_server_cleanup_fields_to_server_settings_table.php
+++ /dev/null
@@ -1,59 +0,0 @@
-boolean('force_docker_cleanup')->default(false);
- $table->string('docker_cleanup_frequency')->default('*/10 * * * *');
- $table->integer('docker_cleanup_threshold')->default(80);
-
- // Remove old columns
- $table->dropColumn('cleanup_after_percentage');
- $table->dropColumn('is_force_cleanup_enabled');
- });
- foreach ($serverSettings as $serverSetting) {
- $serverSetting->force_docker_cleanup = $serverSetting->is_force_cleanup_enabled;
- $serverSetting->docker_cleanup_threshold = $serverSetting->cleanup_after_percentage;
- $serverSetting->save();
- }
- }
-
- /**
- * Reverse the migrations.
- *
- * @return void
- */
- public function down()
- {
- $serverSettings = ServerSetting::all();
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('force_docker_cleanup');
- $table->dropColumn('docker_cleanup_frequency');
- $table->dropColumn('docker_cleanup_threshold');
-
- // Add back old columns
- $table->integer('cleanup_after_percentage')->default(80);
- $table->boolean('force_server_cleanup')->default(false);
- $table->boolean('is_force_cleanup_enabled')->default(false);
- });
- foreach ($serverSettings as $serverSetting) {
- $serverSetting->is_force_cleanup_enabled = $serverSetting->force_docker_cleanup;
- $serverSetting->cleanup_after_percentage = $serverSetting->docker_cleanup_threshold;
- $serverSetting->save();
- }
- }
-}
diff --git a/database/migrations/2024_08_12_131659_add_local_file_volume_based_on_git.php b/database/migrations/2024_08_12_131659_add_local_file_volume_based_on_git.php
deleted file mode 100644
index d180c7ec23..0000000000
--- a/database/migrations/2024_08_12_131659_add_local_file_volume_based_on_git.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_based_on_git')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('local_file_volumes', function (Blueprint $table) {
- $table->dropColumn('is_based_on_git');
- });
- }
-};
diff --git a/database/migrations/2024_08_12_155023_add_timezone_to_server_and_instance_settings.php b/database/migrations/2024_08_12_155023_add_timezone_to_server_and_instance_settings.php
deleted file mode 100644
index 5bc73a54ee..0000000000
--- a/database/migrations/2024_08_12_155023_add_timezone_to_server_and_instance_settings.php
+++ /dev/null
@@ -1,30 +0,0 @@
-string('server_timezone')->default('');
- });
-
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->string('instance_timezone')->default('UTC');
- });
- }
-
- public function down()
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('server_timezone');
- });
-
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('instance_timezone');
- });
- }
-}
diff --git a/database/migrations/2024_08_14_183120_add_order_to_environment_variables_table.php b/database/migrations/2024_08_14_183120_add_order_to_environment_variables_table.php
deleted file mode 100644
index 5275358275..0000000000
--- a/database/migrations/2024_08_14_183120_add_order_to_environment_variables_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-integer('order')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('order');
- });
- }
-};
diff --git a/database/migrations/2024_08_15_115907_add_build_server_id_to_deployment_queue.php b/database/migrations/2024_08_15_115907_add_build_server_id_to_deployment_queue.php
deleted file mode 100644
index da5f065a6b..0000000000
--- a/database/migrations/2024_08_15_115907_add_build_server_id_to_deployment_queue.php
+++ /dev/null
@@ -1,28 +0,0 @@
-integer('build_server_id')->nullable()->after('server_id');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('build_server_id');
- });
- }
-};
diff --git a/database/migrations/2024_08_16_105649_add_custom_docker_options_to_dbs.php b/database/migrations/2024_08_16_105649_add_custom_docker_options_to_dbs.php
deleted file mode 100644
index dbca8c10ab..0000000000
--- a/database/migrations/2024_08_16_105649_add_custom_docker_options_to_dbs.php
+++ /dev/null
@@ -1,70 +0,0 @@
-text('custom_docker_run_options')->nullable();
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->text('custom_docker_run_options')->nullable();
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->text('custom_docker_run_options')->nullable();
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->text('custom_docker_run_options')->nullable();
- });
- Schema::table('standalone_clickhouses', function (Blueprint $table) {
- $table->text('custom_docker_run_options')->nullable();
- });
- Schema::table('standalone_dragonflies', function (Blueprint $table) {
- $table->text('custom_docker_run_options')->nullable();
- });
- Schema::table('standalone_keydbs', function (Blueprint $table) {
- $table->text('custom_docker_run_options')->nullable();
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->text('custom_docker_run_options')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->dropColumn('custom_docker_run_options');
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->dropColumn('custom_docker_run_options');
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->dropColumn('custom_docker_run_options');
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->dropColumn('custom_docker_run_options');
- });
- Schema::table('standalone_clickhouses', function (Blueprint $table) {
- $table->dropColumn('custom_docker_run_options');
- });
- Schema::table('standalone_dragonflies', function (Blueprint $table) {
- $table->dropColumn('custom_docker_run_options');
- });
- Schema::table('standalone_keydbs', function (Blueprint $table) {
- $table->dropColumn('custom_docker_run_options');
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->dropColumn('custom_docker_run_options');
- });
- }
-};
diff --git a/database/migrations/2024_08_27_090528_add_compose_parsing_version_to_services.php b/database/migrations/2024_08_27_090528_add_compose_parsing_version_to_services.php
deleted file mode 100644
index e8c0474d22..0000000000
--- a/database/migrations/2024_08_27_090528_add_compose_parsing_version_to_services.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('compose_parsing_version')->default('2');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('services', function (Blueprint $table) {
- $table->dropColumn('compose_parsing_version');
- });
- }
-};
diff --git a/database/migrations/2024_09_05_085700_add_helper_version_to_instance_settings.php b/database/migrations/2024_09_05_085700_add_helper_version_to_instance_settings.php
deleted file mode 100644
index 53ecce0f1d..0000000000
--- a/database/migrations/2024_09_05_085700_add_helper_version_to_instance_settings.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('helper_version')->default('1.0.0');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('helper_version');
- });
- }
-};
diff --git a/database/migrations/2024_09_06_062534_change_server_cleanup_to_forced.php b/database/migrations/2024_09_06_062534_change_server_cleanup_to_forced.php
deleted file mode 100644
index ad6e5bd9e3..0000000000
--- a/database/migrations/2024_09_06_062534_change_server_cleanup_to_forced.php
+++ /dev/null
@@ -1,37 +0,0 @@
-boolean('force_docker_cleanup')->default(true)->change();
- });
- $serverSettings = ServerSetting::all();
- foreach ($serverSettings as $serverSetting) {
- if ($serverSetting->force_docker_cleanup === false) {
- $serverSetting->force_docker_cleanup = true;
- $serverSetting->docker_cleanup_frequency = '*/10 * * * *';
- $serverSetting->save();
- }
- }
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->boolean('force_docker_cleanup')->default(false)->change();
- });
- }
-};
diff --git a/database/migrations/2024_09_07_185402_change_cleanup_schedule.php b/database/migrations/2024_09_07_185402_change_cleanup_schedule.php
deleted file mode 100644
index ea8861f9b5..0000000000
--- a/database/migrations/2024_09_07_185402_change_cleanup_schedule.php
+++ /dev/null
@@ -1,37 +0,0 @@
-string('docker_cleanup_frequency')->default('0 0 * * *')->change();
- });
-
- $serverSettings = ServerSetting::all();
- foreach ($serverSettings as $serverSetting) {
- if ($serverSetting->force_docker_cleanup && $serverSetting->docker_cleanup_frequency === '*/10 * * * *') {
- $serverSetting->docker_cleanup_frequency = '0 0 * * *';
- $serverSetting->save();
- }
- }
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->string('docker_cleanup_frequency')->default('*/10 * * * *')->change();
- });
- }
-};
diff --git a/database/migrations/2024_09_08_130756_update_server_settings_default_timezone.php b/database/migrations/2024_09_08_130756_update_server_settings_default_timezone.php
deleted file mode 100644
index 109bc40ef1..0000000000
--- a/database/migrations/2024_09_08_130756_update_server_settings_default_timezone.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('server_timezone')->default('UTC')->change();
- });
-
- DB::table('server_settings')
- ->whereNull('server_timezone')
- ->orWhere('server_timezone', '')
- ->update(['server_timezone' => 'UTC']);
- }
-
- public function down()
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->string('server_timezone')->default('')->change();
- });
- }
-}
diff --git a/database/migrations/2024_09_16_111428_encrypt_existing_private_keys.php b/database/migrations/2024_09_16_111428_encrypt_existing_private_keys.php
deleted file mode 100644
index e16181ac7e..0000000000
--- a/database/migrations/2024_09_16_111428_encrypt_existing_private_keys.php
+++ /dev/null
@@ -1,24 +0,0 @@
-chunkById(100, function ($keys) {
- foreach ($keys as $key) {
- DB::table('private_keys')
- ->where('id', $key->id)
- ->update(['private_key' => Crypt::encryptString($key->private_key)]);
- }
- });
- } catch (\Exception $e) {
- echo 'Encrypting private keys failed.';
- echo $e->getMessage();
- }
- }
-}
diff --git a/database/migrations/2024_09_17_111226_add_ssh_key_fingerprint_to_private_keys_table.php b/database/migrations/2024_09_17_111226_add_ssh_key_fingerprint_to_private_keys_table.php
deleted file mode 100644
index dfce5682a4..0000000000
--- a/database/migrations/2024_09_17_111226_add_ssh_key_fingerprint_to_private_keys_table.php
+++ /dev/null
@@ -1,39 +0,0 @@
-string('fingerprint')->after('private_key')->nullable();
- });
-
- try {
- DB::table('private_keys')->chunkById(100, function ($keys) {
- foreach ($keys as $key) {
- $fingerprint = PrivateKey::generateFingerprint($key->private_key);
- if ($fingerprint) {
- $key->fingerprint = $fingerprint;
- $key->save();
- }
- }
- });
- } catch (\Exception $e) {
- echo 'Generating fingerprints failed.';
- echo $e->getMessage();
- }
- }
-
- public function down()
- {
- Schema::table('private_keys', function (Blueprint $table) {
- $table->dropColumn('fingerprint');
- });
- }
-}
diff --git a/database/migrations/2024_09_22_165240_add_advanced_options_to_cleanup_options_to_servers_settings_table.php b/database/migrations/2024_09_22_165240_add_advanced_options_to_cleanup_options_to_servers_settings_table.php
deleted file mode 100644
index b3c58afe33..0000000000
--- a/database/migrations/2024_09_22_165240_add_advanced_options_to_cleanup_options_to_servers_settings_table.php
+++ /dev/null
@@ -1,24 +0,0 @@
-boolean('delete_unused_volumes')->default(false);
- $table->boolean('delete_unused_networks')->default(false);
- });
- }
-
- public function down()
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('delete_unused_volumes');
- $table->dropColumn('delete_unused_networks');
- });
- }
-};
diff --git a/database/migrations/2024_09_26_083441_disable_api_by_default.php b/database/migrations/2024_09_26_083441_disable_api_by_default.php
deleted file mode 100644
index d0803f751d..0000000000
--- a/database/migrations/2024_09_26_083441_disable_api_by_default.php
+++ /dev/null
@@ -1,18 +0,0 @@
-boolean('is_api_enabled')->default(false)->change();
- });
- }
-};
diff --git a/database/migrations/2024_10_03_095427_add_dump_all_to_standalone_postgresqls.php b/database/migrations/2024_10_03_095427_add_dump_all_to_standalone_postgresqls.php
deleted file mode 100644
index b1f301bd38..0000000000
--- a/database/migrations/2024_10_03_095427_add_dump_all_to_standalone_postgresqls.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('dump_all')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('scheduled_database_backups', function (Blueprint $table) {
- $table->dropColumn('dump_all');
- });
- }
-};
diff --git a/database/migrations/2024_10_10_081444_remove_constraint_from_service_applications_fqdn.php b/database/migrations/2024_10_10_081444_remove_constraint_from_service_applications_fqdn.php
deleted file mode 100644
index feb144de68..0000000000
--- a/database/migrations/2024_10_10_081444_remove_constraint_from_service_applications_fqdn.php
+++ /dev/null
@@ -1,34 +0,0 @@
-dropUnique(['fqdn']);
- });
- Schema::table('applications', function (Blueprint $table) {
- $table->dropUnique(['fqdn']);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('service_applications', function (Blueprint $table) {
- $table->unique('fqdn');
- });
- Schema::table('applications', function (Blueprint $table) {
- $table->unique('fqdn');
- });
- }
-};
diff --git a/database/migrations/2024_10_11_114331_add_required_env_variables.php b/database/migrations/2024_10_11_114331_add_required_env_variables.php
deleted file mode 100644
index 4fde0c2bbf..0000000000
--- a/database/migrations/2024_10_11_114331_add_required_env_variables.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_required')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('is_required');
- });
- }
-};
diff --git a/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php b/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php
deleted file mode 100644
index d5c38501f1..0000000000
--- a/database/migrations/2024_10_14_090416_update_metrics_token_in_server_settings.php
+++ /dev/null
@@ -1,54 +0,0 @@
-dropColumn('metrics_token');
- $table->dropColumn('metrics_refresh_rate_seconds');
- $table->dropColumn('metrics_history_days');
- $table->dropColumn('is_server_api_enabled');
-
- $table->boolean('is_sentinel_enabled')->default(false);
- $table->text('sentinel_token')->nullable();
- $table->integer('sentinel_metrics_refresh_rate_seconds')->default(10);
- $table->integer('sentinel_metrics_history_days')->default(7);
- $table->integer('sentinel_push_interval_seconds')->default(60);
- $table->string('sentinel_custom_url')->nullable();
- });
- Schema::table('servers', function (Blueprint $table) {
- $table->dateTime('sentinel_updated_at')->default(now());
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->string('metrics_token')->nullable();
- $table->integer('metrics_refresh_rate_seconds')->default(5);
- $table->integer('metrics_history_days')->default(30);
- $table->boolean('is_server_api_enabled')->default(false);
-
- $table->dropColumn('is_sentinel_enabled');
- $table->dropColumn('sentinel_token');
- $table->dropColumn('sentinel_metrics_refresh_rate_seconds');
- $table->dropColumn('sentinel_metrics_history_days');
- $table->dropColumn('sentinel_push_interval_seconds');
- $table->dropColumn('sentinel_custom_url');
- });
- Schema::table('servers', function (Blueprint $table) {
- $table->dropColumn('sentinel_updated_at');
- });
- }
-};
diff --git a/database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php b/database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php
deleted file mode 100644
index eb878e2f6b..0000000000
--- a/database/migrations/2024_10_15_172139_add_is_shared_to_environment_variables.php
+++ /dev/null
@@ -1,22 +0,0 @@
-boolean('is_shared')->default(false);
- });
- }
-
- public function down()
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn('is_shared');
- });
- }
-}
diff --git a/database/migrations/2024_10_16_120026_move_redis_password_to_envs.php b/database/migrations/2024_10_16_120026_move_redis_password_to_envs.php
deleted file mode 100644
index fa01e8e85b..0000000000
--- a/database/migrations/2024_10_16_120026_move_redis_password_to_envs.php
+++ /dev/null
@@ -1,41 +0,0 @@
-where('id', $redis->id)->value('redis_password');
- EnvironmentVariable::create([
- 'standalone_redis_id' => $redis->id,
- 'key' => 'REDIS_PASSWORD',
- 'value' => $redis_password,
- ]);
- EnvironmentVariable::create([
- 'standalone_redis_id' => $redis->id,
- 'key' => 'REDIS_USERNAME',
- 'value' => 'default',
- ]);
- }
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->dropColumn('redis_password');
- });
- } catch (\Exception $e) {
- echo 'Moving Redis passwords to envs failed.';
- echo $e->getMessage();
- }
- }
-}
diff --git a/database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php b/database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php
deleted file mode 100644
index 7040daf44a..0000000000
--- a/database/migrations/2024_10_16_192133_add_confirmation_settings_to_instance_settings_table.php
+++ /dev/null
@@ -1,22 +0,0 @@
-boolean('disable_two_step_confirmation')->default(false);
- });
- }
-
- public function down()
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->dropColumn('disable_two_step_confirmation');
- });
- }
-};
diff --git a/database/migrations/2024_10_17_093722_add_soft_delete_to_servers.php b/database/migrations/2024_10_17_093722_add_soft_delete_to_servers.php
deleted file mode 100644
index 7a7f28e249..0000000000
--- a/database/migrations/2024_10_17_093722_add_soft_delete_to_servers.php
+++ /dev/null
@@ -1,28 +0,0 @@
-softDeletes();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('servers', function (Blueprint $table) {
- $table->dropSoftDeletes();
- });
- }
-};
diff --git a/database/migrations/2024_10_22_105745_add_server_disk_usage_threshold.php b/database/migrations/2024_10_22_105745_add_server_disk_usage_threshold.php
deleted file mode 100644
index 76ccd13529..0000000000
--- a/database/migrations/2024_10_22_105745_add_server_disk_usage_threshold.php
+++ /dev/null
@@ -1,28 +0,0 @@
-integer('server_disk_usage_notification_threshold')->default(80)->after('docker_cleanup_threshold');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('server_disk_usage_notification_threshold');
- });
- }
-};
diff --git a/database/migrations/2024_10_22_121223_add_server_disk_usage_notification.php b/database/migrations/2024_10_22_121223_add_server_disk_usage_notification.php
deleted file mode 100644
index a2aa381b7e..0000000000
--- a/database/migrations/2024_10_22_121223_add_server_disk_usage_notification.php
+++ /dev/null
@@ -1,32 +0,0 @@
-boolean('discord_notifications_server_disk_usage')->default(true)->after('discord_enabled');
- $table->boolean('smtp_notifications_server_disk_usage')->default(true)->after('smtp_enabled');
- $table->boolean('telegram_notifications_server_disk_usage')->default(true)->after('telegram_enabled');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn('discord_notifications_server_disk_usage');
- $table->dropColumn('smtp_notifications_server_disk_usage');
- $table->dropColumn('telegram_notifications_server_disk_usage');
- });
- }
-};
diff --git a/database/migrations/2024_10_29_093927_add_is_sentinel_debug_enabled_to_server_settings.php b/database/migrations/2024_10_29_093927_add_is_sentinel_debug_enabled_to_server_settings.php
deleted file mode 100644
index d8ab1313bf..0000000000
--- a/database/migrations/2024_10_29_093927_add_is_sentinel_debug_enabled_to_server_settings.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('is_sentinel_debug_enabled')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('is_sentinel_debug_enabled');
- });
- }
-};
diff --git a/database/migrations/2024_10_30_074601_rename_token_permissions.php b/database/migrations/2024_10_30_074601_rename_token_permissions.php
deleted file mode 100644
index 69d774d7f7..0000000000
--- a/database/migrations/2024_10_30_074601_rename_token_permissions.php
+++ /dev/null
@@ -1,60 +0,0 @@
-abilities)) {
- $abilities->push('root');
- }
- if (in_array('read-only', $token->abilities)) {
- $abilities->push('read');
- }
- if (in_array('view:sensitive', $token->abilities)) {
- $abilities->push('read', 'read:sensitive');
- }
- $token->abilities = $abilities->unique()->values()->all();
- $token->save();
- }
- } catch (\Exception $e) {
- \Log::error('Error renaming token permissions: '.$e->getMessage());
- }
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- try {
- $tokens = PersonalAccessToken::all();
- foreach ($tokens as $token) {
- $abilities = collect();
- if (in_array('root', $token->abilities)) {
- $abilities->push('*');
- } else {
- if (in_array('read', $token->abilities)) {
- $abilities->push('read-only');
- }
- if (in_array('read:sensitive', $token->abilities)) {
- $abilities->push('view:sensitive');
- }
- }
- $token->abilities = $abilities->unique()->values()->all();
- $token->save();
- }
- } catch (\Exception $e) {
- \Log::error('Error renaming token permissions: '.$e->getMessage());
- }
- }
-};
diff --git a/database/migrations/2024_11_02_213214_add_last_online_at_to_resources.php b/database/migrations/2024_11_02_213214_add_last_online_at_to_resources.php
deleted file mode 100644
index 51b8fb3ba8..0000000000
--- a/database/migrations/2024_11_02_213214_add_last_online_at_to_resources.php
+++ /dev/null
@@ -1,96 +0,0 @@
-timestamp('last_online_at')->default(now())->after('updated_at');
- });
- Schema::table('application_previews', function (Blueprint $table) {
- $table->timestamp('last_online_at')->default(now())->after('updated_at');
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->timestamp('last_online_at')->default(now())->after('updated_at');
- });
- Schema::table('service_databases', function (Blueprint $table) {
- $table->timestamp('last_online_at')->default(now())->after('updated_at');
- });
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->timestamp('last_online_at')->default(now())->after('updated_at');
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->timestamp('last_online_at')->default(now())->after('updated_at');
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->timestamp('last_online_at')->default(now())->after('updated_at');
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->timestamp('last_online_at')->default(now())->after('updated_at');
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->timestamp('last_online_at')->default(now())->after('updated_at');
- });
- Schema::table('standalone_keydbs', function (Blueprint $table) {
- $table->timestamp('last_online_at')->default(now())->after('updated_at');
- });
- Schema::table('standalone_dragonflies', function (Blueprint $table) {
- $table->timestamp('last_online_at')->default(now())->after('updated_at');
- });
- Schema::table('standalone_clickhouses', function (Blueprint $table) {
- $table->timestamp('last_online_at')->default(now())->after('updated_at');
- });
-
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
- Schema::table('application_previews', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
- Schema::table('service_applications', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
- Schema::table('service_databases', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
- Schema::table('standalone_postgresqls', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
- Schema::table('standalone_redis', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
- Schema::table('standalone_mongodbs', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
- Schema::table('standalone_mysqls', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
- Schema::table('standalone_mariadbs', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
- Schema::table('standalone_keydbs', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
- Schema::table('standalone_dragonflies', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
- Schema::table('standalone_clickhouses', function (Blueprint $table) {
- $table->dropColumn('last_online_at');
- });
-
- }
-};
diff --git a/database/migrations/2024_11_11_125335_add_custom_nginx_configuration_to_static.php b/database/migrations/2024_11_11_125335_add_custom_nginx_configuration_to_static.php
deleted file mode 100644
index 1c6e2daa02..0000000000
--- a/database/migrations/2024_11_11_125335_add_custom_nginx_configuration_to_static.php
+++ /dev/null
@@ -1,28 +0,0 @@
-longText('custom_nginx_configuration')->nullable()->after('static_image');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('applications', function (Blueprint $table) {
- $table->dropColumn('custom_nginx_configuration');
- });
- }
-};
diff --git a/database/migrations/2024_11_11_125366_add_index_to_activity_log.php b/database/migrations/2024_11_11_125366_add_index_to_activity_log.php
deleted file mode 100644
index 0c281ff402..0000000000
--- a/database/migrations/2024_11_11_125366_add_index_to_activity_log.php
+++ /dev/null
@@ -1,28 +0,0 @@
-getMessage());
- }
- }
-
- public function down()
- {
- try {
- DB::statement('DROP INDEX IF EXISTS idx_activity_type_uuid');
- DB::statement('ALTER TABLE activity_log ALTER COLUMN properties TYPE json USING properties::json');
- } catch (\Exception $e) {
- Log::error('Error dropping index from activity_log: '.$e->getMessage());
- }
- }
-}
diff --git a/database/migrations/2024_11_22_124742_add_uuid_to_environments_table.php b/database/migrations/2024_11_22_124742_add_uuid_to_environments_table.php
deleted file mode 100644
index b106427afe..0000000000
--- a/database/migrations/2024_11_22_124742_add_uuid_to_environments_table.php
+++ /dev/null
@@ -1,38 +0,0 @@
-string('uuid')->after('id')->nullable()->unique();
- });
-
- DB::table('environments')
- ->whereNull('uuid')
- ->chunkById(100, function ($environments) {
- foreach ($environments as $environment) {
- DB::table('environments')
- ->where('id', $environment->id)
- ->update(['uuid' => (string) new Cuid2]);
- }
- });
-
- Schema::table('environments', function (Blueprint $table) {
- $table->string('uuid')->nullable(false)->change();
- });
- }
-
- public function down(): void
- {
- Schema::table('environments', function (Blueprint $table) {
- $table->dropColumn('uuid');
- });
- }
-};
diff --git a/database/migrations/2024_12_05_091823_add_disable_build_cache_advanced_option.php b/database/migrations/2024_12_05_091823_add_disable_build_cache_advanced_option.php
deleted file mode 100644
index 751342302d..0000000000
--- a/database/migrations/2024_12_05_091823_add_disable_build_cache_advanced_option.php
+++ /dev/null
@@ -1,22 +0,0 @@
-boolean('disable_build_cache')->default(false);
- });
- }
-
- public function down(): void
- {
- Schema::table('application_settings', function (Blueprint $table) {
- $table->dropColumn('disable_build_cache');
- });
- }
-};
diff --git a/database/migrations/2024_12_05_212355_create_email_notification_settings_table.php b/database/migrations/2024_12_05_212355_create_email_notification_settings_table.php
deleted file mode 100644
index 7338a8d0d2..0000000000
--- a/database/migrations/2024_12_05_212355_create_email_notification_settings_table.php
+++ /dev/null
@@ -1,58 +0,0 @@
-id();
- $table->foreignId('team_id')->constrained()->cascadeOnDelete();
-
- $table->boolean('smtp_enabled')->default(false);
- $table->text('smtp_from_address')->nullable();
- $table->text('smtp_from_name')->nullable();
- $table->text('smtp_recipients')->nullable();
- $table->text('smtp_host')->nullable();
- $table->integer('smtp_port')->nullable();
- $table->string('smtp_encryption')->nullable();
- $table->text('smtp_username')->nullable();
- $table->text('smtp_password')->nullable();
- $table->integer('smtp_timeout')->nullable();
-
- $table->boolean('resend_enabled')->default(false);
- $table->text('resend_api_key')->nullable();
-
- $table->boolean('use_instance_email_settings')->default(false);
-
- $table->boolean('deployment_success_email_notifications')->default(false);
- $table->boolean('deployment_failure_email_notifications')->default(true);
- $table->boolean('status_change_email_notifications')->default(false);
- $table->boolean('backup_success_email_notifications')->default(false);
- $table->boolean('backup_failure_email_notifications')->default(true);
- $table->boolean('scheduled_task_success_email_notifications')->default(false);
- $table->boolean('scheduled_task_failure_email_notifications')->default(true);
- $table->boolean('docker_cleanup_success_email_notifications')->default(false);
- $table->boolean('docker_cleanup_failure_email_notifications')->default(true);
- $table->boolean('server_disk_usage_email_notifications')->default(true);
- $table->boolean('server_reachable_email_notifications')->default(false);
- $table->boolean('server_unreachable_email_notifications')->default(true);
-
- $table->unique(['team_id']);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('email_notification_settings');
- }
-};
diff --git a/database/migrations/2024_12_05_212416_create_discord_notification_settings_table.php b/database/migrations/2024_12_05_212416_create_discord_notification_settings_table.php
deleted file mode 100644
index 0f2ced67f0..0000000000
--- a/database/migrations/2024_12_05_212416_create_discord_notification_settings_table.php
+++ /dev/null
@@ -1,45 +0,0 @@
-id();
- $table->foreignId('team_id')->constrained()->cascadeOnDelete();
-
- $table->boolean('discord_enabled')->default(false);
- $table->text('discord_webhook_url')->nullable();
-
- $table->boolean('deployment_success_discord_notifications')->default(false);
- $table->boolean('deployment_failure_discord_notifications')->default(true);
- $table->boolean('status_change_discord_notifications')->default(false);
- $table->boolean('backup_success_discord_notifications')->default(false);
- $table->boolean('backup_failure_discord_notifications')->default(true);
- $table->boolean('scheduled_task_success_discord_notifications')->default(false);
- $table->boolean('scheduled_task_failure_discord_notifications')->default(true);
- $table->boolean('docker_cleanup_success_discord_notifications')->default(false);
- $table->boolean('docker_cleanup_failure_discord_notifications')->default(true);
- $table->boolean('server_disk_usage_discord_notifications')->default(true);
- $table->boolean('server_reachable_discord_notifications')->default(false);
- $table->boolean('server_unreachable_discord_notifications')->default(true);
-
- $table->unique(['team_id']);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('discord_notification_settings');
- }
-};
diff --git a/database/migrations/2024_12_05_212440_create_telegram_notification_settings_table.php b/database/migrations/2024_12_05_212440_create_telegram_notification_settings_table.php
deleted file mode 100644
index db4d998e37..0000000000
--- a/database/migrations/2024_12_05_212440_create_telegram_notification_settings_table.php
+++ /dev/null
@@ -1,59 +0,0 @@
-id();
- $table->foreignId('team_id')->constrained()->cascadeOnDelete();
-
- $table->boolean('telegram_enabled')->default(false);
- $table->text('telegram_token')->nullable();
- $table->text('telegram_chat_id')->nullable();
-
- $table->boolean('deployment_success_telegram_notifications')->default(false);
- $table->boolean('deployment_failure_telegram_notifications')->default(true);
- $table->boolean('status_change_telegram_notifications')->default(false);
- $table->boolean('backup_success_telegram_notifications')->default(false);
- $table->boolean('backup_failure_telegram_notifications')->default(true);
- $table->boolean('scheduled_task_success_telegram_notifications')->default(false);
- $table->boolean('scheduled_task_failure_telegram_notifications')->default(true);
- $table->boolean('docker_cleanup_success_telegram_notifications')->default(false);
- $table->boolean('docker_cleanup_failure_telegram_notifications')->default(true);
- $table->boolean('server_disk_usage_telegram_notifications')->default(true);
- $table->boolean('server_reachable_telegram_notifications')->default(false);
- $table->boolean('server_unreachable_telegram_notifications')->default(true);
-
- $table->text('telegram_notifications_deployment_success_thread_id')->nullable();
- $table->text('telegram_notifications_deployment_failure_thread_id')->nullable();
- $table->text('telegram_notifications_status_change_thread_id')->nullable();
- $table->text('telegram_notifications_backup_success_thread_id')->nullable();
- $table->text('telegram_notifications_backup_failure_thread_id')->nullable();
- $table->text('telegram_notifications_scheduled_task_success_thread_id')->nullable();
- $table->text('telegram_notifications_scheduled_task_failure_thread_id')->nullable();
- $table->text('telegram_notifications_docker_cleanup_success_thread_id')->nullable();
- $table->text('telegram_notifications_docker_cleanup_failure_thread_id')->nullable();
- $table->text('telegram_notifications_server_disk_usage_thread_id')->nullable();
- $table->text('telegram_notifications_server_reachable_thread_id')->nullable();
- $table->text('telegram_notifications_server_unreachable_thread_id')->nullable();
-
- $table->unique(['team_id']);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('telegram_notification_settings');
- }
-};
diff --git a/database/migrations/2024_12_05_212546_migrate_email_notification_settings_from_teams_table.php b/database/migrations/2024_12_05_212546_migrate_email_notification_settings_from_teams_table.php
deleted file mode 100644
index 384f62f065..0000000000
--- a/database/migrations/2024_12_05_212546_migrate_email_notification_settings_from_teams_table.php
+++ /dev/null
@@ -1,135 +0,0 @@
-get();
-
- foreach ($teams as $team) {
- try {
- DB::table('email_notification_settings')->updateOrInsert(
- ['team_id' => $team->id],
- [
- 'smtp_enabled' => $team->smtp_enabled ?? false,
- 'smtp_from_address' => $team->smtp_from_address ? Crypt::encryptString($team->smtp_from_address) : null,
- 'smtp_from_name' => $team->smtp_from_name ? Crypt::encryptString($team->smtp_from_name) : null,
- 'smtp_recipients' => $team->smtp_recipients ? Crypt::encryptString($team->smtp_recipients) : null,
- 'smtp_host' => $team->smtp_host ? Crypt::encryptString($team->smtp_host) : null,
- 'smtp_port' => $team->smtp_port,
- 'smtp_encryption' => $team->smtp_encryption,
- 'smtp_username' => $team->smtp_username ? Crypt::encryptString($team->smtp_username) : null,
- 'smtp_password' => $team->smtp_password,
- 'smtp_timeout' => $team->smtp_timeout,
-
- 'use_instance_email_settings' => $team->use_instance_email_settings ?? false,
-
- 'resend_enabled' => $team->resend_enabled ?? false,
- 'resend_api_key' => $team->resend_api_key,
-
- 'deployment_success_email_notifications' => $team->smtp_notifications_deployments ?? false,
- 'deployment_failure_email_notifications' => $team->smtp_notifications_deployments ?? true,
- 'backup_success_email_notifications' => $team->smtp_notifications_database_backups ?? false,
- 'backup_failure_email_notifications' => $team->smtp_notifications_database_backups ?? true,
- 'scheduled_task_success_email_notifications' => $team->smtp_notifications_scheduled_tasks ?? false,
- 'scheduled_task_failure_email_notifications' => $team->smtp_notifications_scheduled_tasks ?? true,
- 'status_change_email_notifications' => $team->smtp_notifications_status_changes ?? false,
- 'server_disk_usage_email_notifications' => $team->smtp_notifications_server_disk_usage ?? true,
- ]
- );
- } catch (Exception $e) {
- \Log::error('Error migrating email notification settings from teams table: '.$e->getMessage());
- }
- }
-
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn([
- 'smtp_enabled',
- 'smtp_from_address',
- 'smtp_from_name',
- 'smtp_recipients',
- 'smtp_host',
- 'smtp_port',
- 'smtp_encryption',
- 'smtp_username',
- 'smtp_password',
- 'smtp_timeout',
- 'use_instance_email_settings',
- 'resend_enabled',
- 'resend_api_key',
- 'smtp_notifications_test',
- 'smtp_notifications_deployments',
- 'smtp_notifications_database_backups',
- 'smtp_notifications_scheduled_tasks',
- 'smtp_notifications_status_changes',
- 'smtp_notifications_server_disk_usage',
- ]);
- });
- }
-
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->boolean('smtp_enabled')->default(false);
- $table->string('smtp_from_address')->nullable();
- $table->string('smtp_from_name')->nullable();
- $table->string('smtp_recipients')->nullable();
- $table->string('smtp_host')->nullable();
- $table->integer('smtp_port')->nullable();
- $table->string('smtp_encryption')->nullable();
- $table->text('smtp_username')->nullable();
- $table->text('smtp_password')->nullable();
- $table->integer('smtp_timeout')->nullable();
-
- $table->boolean('use_instance_email_settings')->default(false);
- $table->boolean('resend_enabled')->default(false);
-
- $table->text('resend_api_key')->nullable();
-
- $table->boolean('smtp_notifications_test')->default(false);
- $table->boolean('smtp_notifications_deployments')->default(false);
- $table->boolean('smtp_notifications_database_backups')->default(true);
- $table->boolean('smtp_notifications_scheduled_tasks')->default(false);
- $table->boolean('smtp_notifications_status_changes')->default(false);
- $table->boolean('smtp_notifications_server_disk_usage')->default(true);
- });
-
- $settings = DB::table('email_notification_settings')->get();
- foreach ($settings as $setting) {
- try {
- DB::table('teams')
- ->where('id', $setting->team_id)
- ->update([
- 'smtp_enabled' => $setting->smtp_enabled,
- 'smtp_from_address' => $setting->smtp_from_address ? Crypt::decryptString($setting->smtp_from_address) : null,
- 'smtp_from_name' => $setting->smtp_from_name ? Crypt::decryptString($setting->smtp_from_name) : null,
- 'smtp_recipients' => $setting->smtp_recipients ? Crypt::decryptString($setting->smtp_recipients) : null,
- 'smtp_host' => $setting->smtp_host ? Crypt::decryptString($setting->smtp_host) : null,
- 'smtp_port' => $setting->smtp_port,
- 'smtp_encryption' => $setting->smtp_encryption,
- 'smtp_username' => $setting->smtp_username ? Crypt::decryptString($setting->smtp_username) : null,
- 'smtp_password' => $setting->smtp_password,
- 'smtp_timeout' => $setting->smtp_timeout,
-
- 'use_instance_email_settings' => $setting->use_instance_email_settings,
-
- 'resend_enabled' => $setting->resend_enabled,
- 'resend_api_key' => $setting->resend_api_key,
-
- 'smtp_notifications_deployments' => $setting->deployment_success_email_notifications || $setting->deployment_failure_email_notifications,
- 'smtp_notifications_database_backups' => $setting->backup_success_email_notifications || $setting->backup_failure_email_notifications,
- 'smtp_notifications_scheduled_tasks' => $setting->scheduled_task_success_email_notifications || $setting->scheduled_task_failure_email_notifications,
- 'smtp_notifications_status_changes' => $setting->status_change_email_notifications,
- ]);
- } catch (Exception $e) {
- \Log::error('Error migrating email notification settings from teams table: '.$e->getMessage());
- }
- }
- }
-};
diff --git a/database/migrations/2024_12_05_212631_migrate_discord_notification_settings_from_teams_table.php b/database/migrations/2024_12_05_212631_migrate_discord_notification_settings_from_teams_table.php
deleted file mode 100644
index ed9e9af82a..0000000000
--- a/database/migrations/2024_12_05_212631_migrate_discord_notification_settings_from_teams_table.php
+++ /dev/null
@@ -1,92 +0,0 @@
-get();
-
- foreach ($teams as $team) {
- try {
- DB::table('discord_notification_settings')->updateOrInsert(
- ['team_id' => $team->id],
- [
- 'discord_enabled' => $team->discord_enabled ?? false,
- 'discord_webhook_url' => $team->discord_webhook_url ? Crypt::encryptString($team->discord_webhook_url) : null,
-
- 'deployment_success_discord_notifications' => $team->discord_notifications_deployments ?? false,
- 'deployment_failure_discord_notifications' => $team->discord_notifications_deployments ?? true,
- 'backup_success_discord_notifications' => $team->discord_notifications_database_backups ?? false,
- 'backup_failure_discord_notifications' => $team->discord_notifications_database_backups ?? true,
- 'scheduled_task_success_discord_notifications' => $team->discord_notifications_scheduled_tasks ?? false,
- 'scheduled_task_failure_discord_notifications' => $team->discord_notifications_scheduled_tasks ?? true,
- 'status_change_discord_notifications' => $team->discord_notifications_status_changes ?? false,
- 'server_disk_usage_discord_notifications' => $team->discord_notifications_server_disk_usage ?? true,
- ]
- );
- } catch (Exception $e) {
- \Log::error('Error migrating discord notification settings from teams table: '.$e->getMessage());
- }
- }
-
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn([
- 'discord_enabled',
- 'discord_webhook_url',
- 'discord_notifications_test',
- 'discord_notifications_deployments',
- 'discord_notifications_status_changes',
- 'discord_notifications_database_backups',
- 'discord_notifications_scheduled_tasks',
- 'discord_notifications_server_disk_usage',
- ]);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->boolean('discord_enabled')->default(false);
- $table->string('discord_webhook_url')->nullable();
-
- $table->boolean('discord_notifications_test')->default(true);
- $table->boolean('discord_notifications_deployments')->default(true);
- $table->boolean('discord_notifications_status_changes')->default(true);
- $table->boolean('discord_notifications_database_backups')->default(true);
- $table->boolean('discord_notifications_scheduled_tasks')->default(true);
- $table->boolean('discord_notifications_server_disk_usage')->default(true);
- });
-
- $settings = DB::table('discord_notification_settings')->get();
- foreach ($settings as $setting) {
- try {
- DB::table('teams')
- ->where('id', $setting->team_id)
- ->update([
- 'discord_enabled' => $setting->discord_enabled,
- 'discord_webhook_url' => Crypt::decryptString($setting->discord_webhook_url),
-
- 'discord_notifications_deployments' => $setting->deployment_success_discord_notifications || $setting->deployment_failure_discord_notifications,
- 'discord_notifications_status_changes' => $setting->status_change_discord_notifications,
- 'discord_notifications_database_backups' => $setting->backup_success_discord_notifications || $setting->backup_failure_discord_notifications,
- 'discord_notifications_scheduled_tasks' => $setting->scheduled_task_success_discord_notifications || $setting->scheduled_task_failure_discord_notifications,
- 'discord_notifications_server_disk_usage' => $setting->server_disk_usage_discord_notifications,
- ]);
- } catch (Exception $e) {
- \Log::error('Error migrating discord notification settings from teams table: '.$e->getMessage());
- }
- }
- }
-};
diff --git a/database/migrations/2024_12_05_212705_migrate_telegram_notification_settings_from_teams_table.php b/database/migrations/2024_12_05_212705_migrate_telegram_notification_settings_from_teams_table.php
deleted file mode 100644
index df120e2733..0000000000
--- a/database/migrations/2024_12_05_212705_migrate_telegram_notification_settings_from_teams_table.php
+++ /dev/null
@@ -1,115 +0,0 @@
-get();
-
- foreach ($teams as $team) {
- try {
- DB::table('telegram_notification_settings')->updateOrInsert(
- ['team_id' => $team->id],
- [
- 'telegram_enabled' => $team->telegram_enabled ?? false,
- 'telegram_token' => $team->telegram_token ? Crypt::encryptString($team->telegram_token) : null,
- 'telegram_chat_id' => $team->telegram_chat_id ? Crypt::encryptString($team->telegram_chat_id) : null,
-
- 'deployment_success_telegram_notifications' => $team->telegram_notifications_deployments ?? false,
- 'deployment_failure_telegram_notifications' => $team->telegram_notifications_deployments ?? true,
- 'backup_success_telegram_notifications' => $team->telegram_notifications_database_backups ?? false,
- 'backup_failure_telegram_notifications' => $team->telegram_notifications_database_backups ?? true,
- 'scheduled_task_success_telegram_notifications' => $team->telegram_notifications_scheduled_tasks ?? false,
- 'scheduled_task_failure_telegram_notifications' => $team->telegram_notifications_scheduled_tasks ?? true,
- 'status_change_telegram_notifications' => $team->telegram_notifications_status_changes ?? false,
- 'server_disk_usage_telegram_notifications' => $team->telegram_notifications_server_disk_usage ?? true,
-
- 'telegram_notifications_deployment_success_thread_id' => $team->telegram_notifications_deployments_message_thread_id ? Crypt::encryptString($team->telegram_notifications_deployments_message_thread_id) : null,
- 'telegram_notifications_deployment_failure_thread_id' => $team->telegram_notifications_deployments_message_thread_id ? Crypt::encryptString($team->telegram_notifications_deployments_message_thread_id) : null,
- 'telegram_notifications_backup_success_thread_id' => $team->telegram_notifications_database_backups_message_thread_id ? Crypt::encryptString($team->telegram_notifications_database_backups_message_thread_id) : null,
- 'telegram_notifications_backup_failure_thread_id' => $team->telegram_notifications_database_backups_message_thread_id ? Crypt::encryptString($team->telegram_notifications_database_backups_message_thread_id) : null,
- 'telegram_notifications_scheduled_task_success_thread_id' => $team->telegram_notifications_scheduled_tasks_thread_id ? Crypt::encryptString($team->telegram_notifications_scheduled_tasks_thread_id) : null,
- 'telegram_notifications_scheduled_task_failure_thread_id' => $team->telegram_notifications_scheduled_tasks_thread_id ? Crypt::encryptString($team->telegram_notifications_scheduled_tasks_thread_id) : null,
- 'telegram_notifications_status_change_thread_id' => $team->telegram_notifications_status_changes_message_thread_id ? Crypt::encryptString($team->telegram_notifications_status_changes_message_thread_id) : null,
- ]
- );
- } catch (Exception $e) {
- Log::error('Error migrating telegram notification settings from teams table: '.$e->getMessage());
- }
- }
-
- Schema::table('teams', function (Blueprint $table) {
- $table->dropColumn([
- 'telegram_enabled',
- 'telegram_token',
- 'telegram_chat_id',
- 'telegram_notifications_test',
- 'telegram_notifications_deployments',
- 'telegram_notifications_status_changes',
- 'telegram_notifications_database_backups',
- 'telegram_notifications_scheduled_tasks',
- 'telegram_notifications_server_disk_usage',
- 'telegram_notifications_test_message_thread_id',
- 'telegram_notifications_deployments_message_thread_id',
- 'telegram_notifications_status_changes_message_thread_id',
- 'telegram_notifications_database_backups_message_thread_id',
- 'telegram_notifications_scheduled_tasks_thread_id',
- ]);
- });
- }
-
- public function down(): void
- {
- Schema::table('teams', function (Blueprint $table) {
- $table->boolean('telegram_enabled')->default(false);
- $table->text('telegram_token')->nullable();
- $table->text('telegram_chat_id')->nullable();
-
- $table->boolean('telegram_notifications_test')->default(true);
- $table->boolean('telegram_notifications_deployments')->default(true);
- $table->boolean('telegram_notifications_status_changes')->default(true);
- $table->boolean('telegram_notifications_database_backups')->default(true);
- $table->boolean('telegram_notifications_scheduled_tasks')->default(true);
- $table->boolean('telegram_notifications_server_disk_usage')->default(true);
-
- $table->text('telegram_notifications_test_message_thread_id')->nullable();
- $table->text('telegram_notifications_deployments_message_thread_id')->nullable();
- $table->text('telegram_notifications_status_changes_message_thread_id')->nullable();
- $table->text('telegram_notifications_database_backups_message_thread_id')->nullable();
- $table->text('telegram_notifications_scheduled_tasks_thread_id')->nullable();
- });
-
- $settings = DB::table('telegram_notification_settings')->get();
- foreach ($settings as $setting) {
- try {
- DB::table('teams')
- ->where('id', $setting->team_id)
- ->update([
- 'telegram_enabled' => $setting->telegram_enabled,
- 'telegram_token' => $setting->telegram_token ? Crypt::decryptString($setting->telegram_token) : null,
- 'telegram_chat_id' => $setting->telegram_chat_id ? Crypt::decryptString($setting->telegram_chat_id) : null,
-
- 'telegram_notifications_deployments' => $setting->deployment_success_telegram_notifications || $setting->deployment_failure_telegram_notifications,
- 'telegram_notifications_status_changes' => $setting->status_change_telegram_notifications,
- 'telegram_notifications_database_backups' => $setting->backup_success_telegram_notifications || $setting->backup_failure_telegram_notifications,
- 'telegram_notifications_scheduled_tasks' => $setting->scheduled_task_success_telegram_notifications || $setting->scheduled_task_failure_telegram_notifications,
- 'telegram_notifications_server_disk_usage' => $setting->server_disk_usage_telegram_notifications,
-
- 'telegram_notifications_deployments_message_thread_id' => $setting->telegram_notifications_deployment_success_thread_id ? Crypt::decryptString($setting->telegram_notifications_deployment_success_thread_id) : null,
- 'telegram_notifications_status_changes_message_thread_id' => $setting->telegram_notifications_status_change_thread_id ? Crypt::decryptString($setting->telegram_notifications_status_change_thread_id) : null,
- 'telegram_notifications_database_backups_message_thread_id' => $setting->telegram_notifications_backup_success_thread_id ? Crypt::decryptString($setting->telegram_notifications_backup_success_thread_id) : null,
- 'telegram_notifications_scheduled_tasks_thread_id' => $setting->telegram_notifications_scheduled_task_success_thread_id ? Crypt::decryptString($setting->telegram_notifications_scheduled_task_success_thread_id) : null,
- ]);
- } catch (Exception $e) {
- Log::error('Error migrating telegram notification settings from teams table: '.$e->getMessage());
- }
- }
- }
-};
diff --git a/database/migrations/2024_12_06_142014_create_slack_notification_settings_table.php b/database/migrations/2024_12_06_142014_create_slack_notification_settings_table.php
deleted file mode 100644
index 8aee40d87f..0000000000
--- a/database/migrations/2024_12_06_142014_create_slack_notification_settings_table.php
+++ /dev/null
@@ -1,58 +0,0 @@
-id();
- $table->foreignId('team_id')->constrained()->cascadeOnDelete();
-
- $table->boolean('slack_enabled')->default(false);
- $table->text('slack_webhook_url')->nullable();
-
- $table->boolean('deployment_success_slack_notifications')->default(false);
- $table->boolean('deployment_failure_slack_notifications')->default(true);
- $table->boolean('status_change_slack_notifications')->default(false);
- $table->boolean('backup_success_slack_notifications')->default(false);
- $table->boolean('backup_failure_slack_notifications')->default(true);
- $table->boolean('scheduled_task_success_slack_notifications')->default(false);
- $table->boolean('scheduled_task_failure_slack_notifications')->default(true);
- $table->boolean('docker_cleanup_success_slack_notifications')->default(false);
- $table->boolean('docker_cleanup_failure_slack_notifications')->default(true);
- $table->boolean('server_disk_usage_slack_notifications')->default(true);
- $table->boolean('server_reachable_slack_notifications')->default(false);
- $table->boolean('server_unreachable_slack_notifications')->default(true);
-
- $table->unique(['team_id']);
- });
- $teams = DB::table('teams')->get();
-
- foreach ($teams as $team) {
- try {
- DB::table('slack_notification_settings')->insert([
- 'team_id' => $team->id,
- ]);
- } catch (\Throwable $e) {
- Log::error('Error creating slack notification settings for existing teams: '.$e->getMessage());
- }
- }
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('slack_notification_settings');
- }
-};
diff --git a/database/migrations/2024_12_09_105711_drop_waitlists_table.php b/database/migrations/2024_12_09_105711_drop_waitlists_table.php
deleted file mode 100644
index 0e319369d0..0000000000
--- a/database/migrations/2024_12_09_105711_drop_waitlists_table.php
+++ /dev/null
@@ -1,31 +0,0 @@
-id();
- $table->string('uuid');
- $table->string('type');
- $table->string('email')->unique();
- $table->boolean('verified')->default(false);
- $table->timestamps();
- });
- }
-};
diff --git a/database/migrations/2024_12_10_122142_encrypt_instance_settings_email_columns.php b/database/migrations/2024_12_10_122142_encrypt_instance_settings_email_columns.php
deleted file mode 100644
index 83540ca3ce..0000000000
--- a/database/migrations/2024_12_10_122142_encrypt_instance_settings_email_columns.php
+++ /dev/null
@@ -1,72 +0,0 @@
-text('smtp_from_address')->nullable()->change();
- $table->text('smtp_from_name')->nullable()->change();
- $table->text('smtp_recipients')->nullable()->change();
- $table->text('smtp_host')->nullable()->change();
- $table->text('smtp_username')->nullable()->change();
- });
-
- if (DB::table('instance_settings')->exists()) {
- $settings = DB::table('instance_settings')->get();
- foreach ($settings as $setting) {
- try {
- DB::table('instance_settings')->where('id', $setting->id)->update([
- 'smtp_from_address' => $setting->smtp_from_address ? Crypt::encryptString($setting->smtp_from_address) : null,
- 'smtp_from_name' => $setting->smtp_from_name ? Crypt::encryptString($setting->smtp_from_name) : null,
- 'smtp_recipients' => $setting->smtp_recipients ? Crypt::encryptString($setting->smtp_recipients) : null,
- 'smtp_host' => $setting->smtp_host ? Crypt::encryptString($setting->smtp_host) : null,
- 'smtp_username' => $setting->smtp_username ? Crypt::encryptString($setting->smtp_username) : null,
- ]);
- } catch (Exception $e) {
- \Log::error('Error encrypting instance settings email columns: '.$e->getMessage());
- }
- }
- }
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->string('smtp_from_address')->nullable()->change();
- $table->string('smtp_from_name')->nullable()->change();
- $table->string('smtp_recipients')->nullable()->change();
- $table->string('smtp_host')->nullable()->change();
- $table->string('smtp_username')->nullable()->change();
- });
-
- if (DB::table('instance_settings')->exists()) {
- $settings = DB::table('instance_settings')->get();
- foreach ($settings as $setting) {
- try {
- DB::table('instance_settings')->where('id', $setting->id)->update([
- 'smtp_from_address' => $setting->smtp_from_address ? Crypt::decryptString($setting->smtp_from_address) : null,
- 'smtp_from_name' => $setting->smtp_from_name ? Crypt::decryptString($setting->smtp_from_name) : null,
- 'smtp_recipients' => $setting->smtp_recipients ? Crypt::decryptString($setting->smtp_recipients) : null,
- 'smtp_host' => $setting->smtp_host ? Crypt::decryptString($setting->smtp_host) : null,
- 'smtp_username' => $setting->smtp_username ? Crypt::decryptString($setting->smtp_username) : null,
- ]);
- } catch (Exception $e) {
- \Log::error('Error decrypting instance settings email columns: '.$e->getMessage());
- }
- }
- }
- }
-};
diff --git a/database/migrations/2024_12_10_122143_drop_resale_license.php b/database/migrations/2024_12_10_122143_drop_resale_license.php
deleted file mode 100644
index aaf498c3bd..0000000000
--- a/database/migrations/2024_12_10_122143_drop_resale_license.php
+++ /dev/null
@@ -1,30 +0,0 @@
-dropColumn('is_resale_license_active');
- $table->dropColumn('resale_license');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('instance_settings', function (Blueprint $table) {
- $table->boolean('is_resale_license_active')->default(false);
- $table->longText('resale_license')->nullable();
- });
- }
-};
diff --git a/database/migrations/2024_12_11_135026_create_pushover_notification_settings_table.php b/database/migrations/2024_12_11_135026_create_pushover_notification_settings_table.php
deleted file mode 100644
index ad4215a075..0000000000
--- a/database/migrations/2024_12_11_135026_create_pushover_notification_settings_table.php
+++ /dev/null
@@ -1,59 +0,0 @@
-id();
- $table->foreignId('team_id')->constrained()->cascadeOnDelete();
-
- $table->boolean('pushover_enabled')->default(false);
- $table->text('pushover_user_key')->nullable();
- $table->text('pushover_api_token')->nullable();
-
- $table->boolean('deployment_success_pushover_notifications')->default(false);
- $table->boolean('deployment_failure_pushover_notifications')->default(true);
- $table->boolean('status_change_pushover_notifications')->default(false);
- $table->boolean('backup_success_pushover_notifications')->default(false);
- $table->boolean('backup_failure_pushover_notifications')->default(true);
- $table->boolean('scheduled_task_success_pushover_notifications')->default(false);
- $table->boolean('scheduled_task_failure_pushover_notifications')->default(true);
- $table->boolean('docker_cleanup_success_pushover_notifications')->default(false);
- $table->boolean('docker_cleanup_failure_pushover_notifications')->default(true);
- $table->boolean('server_disk_usage_pushover_notifications')->default(true);
- $table->boolean('server_reachable_pushover_notifications')->default(false);
- $table->boolean('server_unreachable_pushover_notifications')->default(true);
-
- $table->unique(['team_id']);
- });
- $teams = DB::table('teams')->get();
-
- foreach ($teams as $team) {
- try {
- DB::table('pushover_notification_settings')->insert([
- 'team_id' => $team->id,
- ]);
- } catch (\Throwable $e) {
- Log::error('Error creating pushover notification settings for existing teams: '.$e->getMessage());
- }
- }
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('pushover_notification_settings');
- }
-};
diff --git a/database/migrations/2024_12_11_161418_add_authentik_base_url_to_oauth_settings_table.php b/database/migrations/2024_12_11_161418_add_authentik_base_url_to_oauth_settings_table.php
deleted file mode 100644
index 44ecb0cde3..0000000000
--- a/database/migrations/2024_12_11_161418_add_authentik_base_url_to_oauth_settings_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('base_url')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('oauth_settings', function (Blueprint $table) {
- $table->dropColumn('base_url');
- });
- }
-};
diff --git a/database/migrations/2024_12_13_103007_encrypt_resend_api_key_in_instance_settings.php b/database/migrations/2024_12_13_103007_encrypt_resend_api_key_in_instance_settings.php
deleted file mode 100644
index ab9b3416a5..0000000000
--- a/database/migrations/2024_12_13_103007_encrypt_resend_api_key_in_instance_settings.php
+++ /dev/null
@@ -1,46 +0,0 @@
-exists()) {
- $settings = DB::table('instance_settings')->get();
- foreach ($settings as $setting) {
- try {
- DB::table('instance_settings')->where('id', $setting->id)->update([
- 'resend_api_key' => $setting->resend_api_key ? Crypt::encryptString($setting->resend_api_key) : null,
- ]);
- } catch (Exception $e) {
- \Log::error('Error encrypting resend_api_key: '.$e->getMessage());
- }
- }
- }
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- if (DB::table('instance_settings')->exists()) {
- $settings = DB::table('instance_settings')->get();
- foreach ($settings as $setting) {
- try {
- DB::table('instance_settings')->where('id', $setting->id)->update([
- 'resend_api_key' => $setting->resend_api_key ? Crypt::decryptString($setting->resend_api_key) : null,
- ]);
- } catch (Exception $e) {
- \Log::error('Error decrypting resend_api_key: '.$e->getMessage());
- }
- }
- }
- }
-};
diff --git a/database/migrations/2024_12_16_134437_add_resourceable_columns_to_environment_variables_table.php b/database/migrations/2024_12_16_134437_add_resourceable_columns_to_environment_variables_table.php
deleted file mode 100644
index c4b7186380..0000000000
--- a/database/migrations/2024_12_16_134437_add_resourceable_columns_to_environment_variables_table.php
+++ /dev/null
@@ -1,165 +0,0 @@
-string('resourceable_type')->nullable();
- $table->unsignedBigInteger('resourceable_id')->nullable();
- $table->index(['resourceable_type', 'resourceable_id']);
- });
-
- // Populate the new columns
- DB::table('environment_variables')->whereNotNull('application_id')
- ->update([
- 'resourceable_type' => 'App\\Models\\Application',
- 'resourceable_id' => DB::raw('application_id'),
- ]);
-
- DB::table('environment_variables')->whereNotNull('service_id')
- ->update([
- 'resourceable_type' => 'App\\Models\\Service',
- 'resourceable_id' => DB::raw('service_id'),
- ]);
-
- DB::table('environment_variables')->whereNotNull('standalone_postgresql_id')
- ->update([
- 'resourceable_type' => 'App\\Models\\StandalonePostgresql',
- 'resourceable_id' => DB::raw('standalone_postgresql_id'),
- ]);
-
- DB::table('environment_variables')->whereNotNull('standalone_redis_id')
- ->update([
- 'resourceable_type' => 'App\\Models\\StandaloneRedis',
- 'resourceable_id' => DB::raw('standalone_redis_id'),
- ]);
-
- DB::table('environment_variables')->whereNotNull('standalone_mongodb_id')
- ->update([
- 'resourceable_type' => 'App\\Models\\StandaloneMongodb',
- 'resourceable_id' => DB::raw('standalone_mongodb_id'),
- ]);
-
- DB::table('environment_variables')->whereNotNull('standalone_mysql_id')
- ->update([
- 'resourceable_type' => 'App\\Models\\StandaloneMysql',
- 'resourceable_id' => DB::raw('standalone_mysql_id'),
- ]);
-
- DB::table('environment_variables')->whereNotNull('standalone_mariadb_id')
- ->update([
- 'resourceable_type' => 'App\\Models\\StandaloneMariadb',
- 'resourceable_id' => DB::raw('standalone_mariadb_id'),
- ]);
-
- DB::table('environment_variables')->whereNotNull('standalone_keydb_id')
- ->update([
- 'resourceable_type' => 'App\\Models\\StandaloneKeydb',
- 'resourceable_id' => DB::raw('standalone_keydb_id'),
- ]);
-
- DB::table('environment_variables')->whereNotNull('standalone_dragonfly_id')
- ->update([
- 'resourceable_type' => 'App\\Models\\StandaloneDragonfly',
- 'resourceable_id' => DB::raw('standalone_dragonfly_id'),
- ]);
-
- DB::table('environment_variables')->whereNotNull('standalone_clickhouse_id')
- ->update([
- 'resourceable_type' => 'App\\Models\\StandaloneClickhouse',
- 'resourceable_id' => DB::raw('standalone_clickhouse_id'),
- ]);
-
- // After successful migration, we can drop the old foreign key columns
- Schema::table('environment_variables', function (Blueprint $table) {
- $table->dropColumn([
- 'application_id',
- 'service_id',
- 'standalone_postgresql_id',
- 'standalone_redis_id',
- 'standalone_mongodb_id',
- 'standalone_mysql_id',
- 'standalone_mariadb_id',
- 'standalone_keydb_id',
- 'standalone_dragonfly_id',
- 'standalone_clickhouse_id',
- ]);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('environment_variables', function (Blueprint $table) {
- // Restore the old columns
- $table->unsignedBigInteger('application_id')->nullable();
- $table->unsignedBigInteger('service_id')->nullable();
- $table->unsignedBigInteger('standalone_postgresql_id')->nullable();
- $table->unsignedBigInteger('standalone_redis_id')->nullable();
- $table->unsignedBigInteger('standalone_mongodb_id')->nullable();
- $table->unsignedBigInteger('standalone_mysql_id')->nullable();
- $table->unsignedBigInteger('standalone_mariadb_id')->nullable();
- $table->unsignedBigInteger('standalone_keydb_id')->nullable();
- $table->unsignedBigInteger('standalone_dragonfly_id')->nullable();
- $table->unsignedBigInteger('standalone_clickhouse_id')->nullable();
- });
-
- Schema::table('environment_variables', function (Blueprint $table) {
- // Restore data from polymorphic relationship
- DB::table('environment_variables')
- ->where('resourceable_type', 'App\\Models\\Application')
- ->update(['application_id' => DB::raw('resourceable_id')]);
-
- DB::table('environment_variables')
- ->where('resourceable_type', 'App\\Models\\Service')
- ->update(['service_id' => DB::raw('resourceable_id')]);
-
- DB::table('environment_variables')
- ->where('resourceable_type', 'App\\Models\\StandalonePostgresql')
- ->update(['standalone_postgresql_id' => DB::raw('resourceable_id')]);
-
- DB::table('environment_variables')
- ->where('resourceable_type', 'App\\Models\\StandaloneRedis')
- ->update(['standalone_redis_id' => DB::raw('resourceable_id')]);
-
- DB::table('environment_variables')
- ->where('resourceable_type', 'App\\Models\\StandaloneMongodb')
- ->update(['standalone_mongodb_id' => DB::raw('resourceable_id')]);
-
- DB::table('environment_variables')
- ->where('resourceable_type', 'App\\Models\\StandaloneMysql')
- ->update(['standalone_mysql_id' => DB::raw('resourceable_id')]);
-
- DB::table('environment_variables')
- ->where('resourceable_type', 'App\\Models\\StandaloneMariadb')
- ->update(['standalone_mariadb_id' => DB::raw('resourceable_id')]);
-
- DB::table('environment_variables')
- ->where('resourceable_type', 'App\\Models\\StandaloneKeydb')
- ->update(['standalone_keydb_id' => DB::raw('resourceable_id')]);
-
- DB::table('environment_variables')
- ->where('resourceable_type', 'App\\Models\\StandaloneDragonfly')
- ->update(['standalone_dragonfly_id' => DB::raw('resourceable_id')]);
-
- DB::table('environment_variables')
- ->where('resourceable_type', 'App\\Models\\StandaloneClickhouse')
- ->update(['standalone_clickhouse_id' => DB::raw('resourceable_id')]);
-
- // Drop the polymorphic columns
- $table->dropIndex(['resourceable_type', 'resourceable_id']);
- $table->dropColumn(['resourceable_type', 'resourceable_id']);
- });
- }
-};
diff --git a/database/migrations/2024_12_17_140637_add_server_disk_usage_check_frequency_to_server_settings_table.php b/database/migrations/2024_12_17_140637_add_server_disk_usage_check_frequency_to_server_settings_table.php
deleted file mode 100644
index be0f4bc0f4..0000000000
--- a/database/migrations/2024_12_17_140637_add_server_disk_usage_check_frequency_to_server_settings_table.php
+++ /dev/null
@@ -1,28 +0,0 @@
-string('server_disk_usage_check_frequency')->default('0 23 * * *');
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('server_settings', function (Blueprint $table) {
- $table->dropColumn('server_disk_usage_check_frequency');
- });
- }
-};
diff --git a/database/migrations/2024_12_23_142402_update_email_encryption_values.php b/database/migrations/2024_12_23_142402_update_email_encryption_values.php
deleted file mode 100644
index dfb5b4a7c6..0000000000
--- a/database/migrations/2024_12_23_142402_update_email_encryption_values.php
+++ /dev/null
@@ -1,114 +0,0 @@
- 'starttls',
- 'ssl' => 'tls',
- '' => 'none',
- ];
-
- /**
- * Run the migrations.
- */
- public function up(): void
- {
- try {
- DB::beginTransaction();
-
- $instanceSettings = DB::table('instance_settings')->get();
- foreach ($instanceSettings as $setting) {
- try {
- if (array_key_exists($setting->smtp_encryption, $this->encryptionMappings)) {
- DB::table('instance_settings')
- ->where('id', $setting->id)
- ->update([
- 'smtp_encryption' => $this->encryptionMappings[$setting->smtp_encryption],
- ]);
- }
- } catch (\Exception $e) {
- \Log::error('Failed to update instance settings: '.$e->getMessage());
- }
- }
-
- $emailSettings = DB::table('email_notification_settings')->get();
- foreach ($emailSettings as $setting) {
- try {
- if (array_key_exists($setting->smtp_encryption, $this->encryptionMappings)) {
- DB::table('email_notification_settings')
- ->where('id', $setting->id)
- ->update([
- 'smtp_encryption' => $this->encryptionMappings[$setting->smtp_encryption],
- ]);
- }
- } catch (\Exception $e) {
- \Log::error('Failed to update email settings: '.$e->getMessage());
- }
- }
-
- DB::commit();
- } catch (\Exception $e) {
- DB::rollBack();
- \Log::error('Failed to update email encryption: '.$e->getMessage());
- throw $e;
- }
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- try {
- DB::beginTransaction();
-
- $reverseMapping = [
- 'starttls' => 'tls',
- 'tls' => 'ssl',
- 'none' => '',
- ];
-
- $instanceSettings = DB::table('instance_settings')->get();
- foreach ($instanceSettings as $setting) {
- try {
- if (array_key_exists($setting->smtp_encryption, $reverseMapping)) {
- DB::table('instance_settings')
- ->where('id', $setting->id)
- ->update([
- 'smtp_encryption' => $reverseMapping[$setting->smtp_encryption],
- ]);
- }
- } catch (\Exception $e) {
- \Log::error('Failed to reverse instance settings: '.$e->getMessage());
- }
- }
-
- $emailSettings = DB::table('email_notification_settings')->get();
- foreach ($emailSettings as $setting) {
- try {
- if (array_key_exists($setting->smtp_encryption, $reverseMapping)) {
- DB::table('email_notification_settings')
- ->where('id', $setting->id)
- ->update([
- 'smtp_encryption' => $reverseMapping[$setting->smtp_encryption],
- ]);
- }
- } catch (\Exception $e) {
- \Log::error('Failed to reverse email settings: '.$e->getMessage());
- }
- }
-
- DB::commit();
- } catch (\Exception $e) {
- DB::rollBack();
- \Log::error('Failed to reverse email encryption: '.$e->getMessage());
- throw $e;
- }
- }
-}
diff --git a/database/migrations/2025_01_08_154008_switch_up_readonly_labels.php b/database/migrations/2025_01_08_154008_switch_up_readonly_labels.php
deleted file mode 100644
index aae089d9e5..0000000000
--- a/database/migrations/2025_01_08_154008_switch_up_readonly_labels.php
+++ /dev/null
@@ -1,39 +0,0 @@
-update([
- 'is_container_label_readonly_enabled' => DB::raw('NOT is_container_label_readonly_enabled'),
- ]);
-
- Schema::table('application_settings', function (Blueprint $table) {
- $table->boolean('is_container_label_readonly_enabled')->default(true)->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- DB::table('application_settings')
- ->update([
- 'is_container_label_readonly_enabled' => DB::raw('NOT is_container_label_readonly_enabled'),
- ]);
-
- Schema::table('application_settings', function (Blueprint $table) {
- $table->boolean('is_container_label_readonly_enabled')->default(false)->change();
- });
- }
-};
diff --git a/database/migrations/2025_01_10_135244_add_horizon_job_details_to_queue.php b/database/migrations/2025_01_10_135244_add_horizon_job_details_to_queue.php
deleted file mode 100644
index 8ce5821efe..0000000000
--- a/database/migrations/2025_01_10_135244_add_horizon_job_details_to_queue.php
+++ /dev/null
@@ -1,30 +0,0 @@
-string('horizon_job_id')->nullable();
- $table->string('horizon_job_worker')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('horizon_job_id');
- $table->dropColumn('horizon_job_worker');
- });
- }
-};
diff --git a/database/migrations/2025_01_13_130238_add_backup_retention_fields_to_scheduled_database_backups_table.php b/database/migrations/2025_01_13_130238_add_backup_retention_fields_to_scheduled_database_backups_table.php
deleted file mode 100644
index f06bc367eb..0000000000
--- a/database/migrations/2025_01_13_130238_add_backup_retention_fields_to_scheduled_database_backups_table.php
+++ /dev/null
@@ -1,36 +0,0 @@
-renameColumn('number_of_backups_locally', 'database_backup_retention_amount_locally');
- $table->integer('database_backup_retention_amount_locally')->default(0)->nullable(false)->change();
- $table->integer('database_backup_retention_days_locally')->default(0)->nullable(false);
- $table->decimal('database_backup_retention_max_storage_locally', 17, 7)->default(0)->nullable(false);
-
- $table->integer('database_backup_retention_amount_s3')->default(0)->nullable(false);
- $table->integer('database_backup_retention_days_s3')->default(0)->nullable(false);
- $table->decimal('database_backup_retention_max_storage_s3', 17, 7)->default(0)->nullable(false);
- });
- }
-
- public function down()
- {
- Schema::table('scheduled_database_backups', function (Blueprint $table) {
- $table->renameColumn('database_backup_retention_amount_locally', 'number_of_backups_locally')->nullable(true)->change();
- $table->dropColumn([
- 'database_backup_retention_days_locally',
- 'database_backup_retention_max_storage_locally',
- 'database_backup_retention_amount_s3',
- 'database_backup_retention_days_s3',
- 'database_backup_retention_max_storage_s3',
- ]);
- });
- }
-};
diff --git a/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php b/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php
deleted file mode 100644
index c962131254..0000000000
--- a/database/migrations/2025_01_15_130416_create_docker_cleanup_executions_table.php
+++ /dev/null
@@ -1,33 +0,0 @@
-id();
- $table->string('uuid')->unique();
- $table->enum('status', ['success', 'failed', 'running'])->default('running');
- $table->text('message')->nullable();
- $table->json('cleanup_log')->nullable();
- $table->foreignId('server_id');
- $table->timestamps();
- $table->timestamp('finished_at')->nullable();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('docker_cleanup_executions');
- }
-};
diff --git a/database/migrations/2025_01_16_110406_change_commit_message_to_text_in_application_deployment_queues.php b/database/migrations/2025_01_16_110406_change_commit_message_to_text_in_application_deployment_queues.php
deleted file mode 100644
index 6c64bf38d4..0000000000
--- a/database/migrations/2025_01_16_110406_change_commit_message_to_text_in_application_deployment_queues.php
+++ /dev/null
@@ -1,28 +0,0 @@
-text('commit_message')->nullable()->change();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->string('commit_message', 50)->nullable()->change();
- });
- }
-};
diff --git a/database/migrations/2025_01_16_130238_add_finished_at_to_executions_tables.php b/database/migrations/2025_01_16_130238_add_finished_at_to_executions_tables.php
deleted file mode 100644
index 0b78c89982..0000000000
--- a/database/migrations/2025_01_16_130238_add_finished_at_to_executions_tables.php
+++ /dev/null
@@ -1,38 +0,0 @@
-timestamp('finished_at')->nullable();
- });
- Schema::table('scheduled_database_backup_executions', function (Blueprint $table) {
- $table->timestamp('finished_at')->nullable();
- });
-
- Schema::table('scheduled_task_executions', function (Blueprint $table) {
- $table->timestamp('finished_at')->nullable();
- });
-
- }
-
- public function down()
- {
- Schema::table('application_deployment_queues', function (Blueprint $table) {
- $table->dropColumn('finished_at');
- });
-
- Schema::table('scheduled_database_backup_executions', function (Blueprint $table) {
- $table->dropColumn('finished_at');
- });
-
- Schema::table('scheduled_task_executions', function (Blueprint $table) {
- $table->dropColumn('finished_at');
- });
- }
-};
diff --git a/database/migrations/2025_01_21_125205_update_finished_at_timestamps_if_not_set.php b/database/migrations/2025_01_21_125205_update_finished_at_timestamps_if_not_set.php
deleted file mode 100644
index 050e8f1ae6..0000000000
--- a/database/migrations/2025_01_21_125205_update_finished_at_timestamps_if_not_set.php
+++ /dev/null
@@ -1,37 +0,0 @@
-whereNull('finished_at')
- ->update(['finished_at' => DB::raw('updated_at')]);
- } catch (\Exception $e) {
- \Log::error('Failed to update not set finished_at timestamps for application_deployment_queues: '.$e->getMessage());
- }
-
- try {
- DB::table('scheduled_database_backup_executions')
- ->whereNull('finished_at')
- ->update(['finished_at' => DB::raw('updated_at')]);
- } catch (\Exception $e) {
- \Log::error('Failed to update not set finished_at timestamps for scheduled_database_backup_executions: '.$e->getMessage());
- }
-
- try {
- DB::table('scheduled_task_executions')
- ->whereNull('finished_at')
- ->update(['finished_at' => DB::raw('updated_at')]);
- } catch (\Exception $e) {
- \Log::error('Failed to update not set finished_at timestamps for scheduled_task_executions: '.$e->getMessage());
- }
- }
-};
diff --git a/database/migrations/2025_01_22_101105_remove_wrongly_created_envs.php b/database/migrations/2025_01_22_101105_remove_wrongly_created_envs.php
deleted file mode 100644
index cb1b3cbe6d..0000000000
--- a/database/migrations/2025_01_22_101105_remove_wrongly_created_envs.php
+++ /dev/null
@@ -1,19 +0,0 @@
-each(function (EnvironmentVariable $environmentVariable) {
- $environmentVariable->delete();
- });
- } catch (\Exception $e) {
- Log::error('Failed to delete wrongly created environment variables: '.$e->getMessage());
- }
- }
-};
diff --git a/database/migrations/2025_02_27_125249_add_index_to_scheduled_task_executions.php b/database/migrations/2025_02_27_125249_add_index_to_scheduled_task_executions.php
deleted file mode 100644
index 45c6b581d6..0000000000
--- a/database/migrations/2025_02_27_125249_add_index_to_scheduled_task_executions.php
+++ /dev/null
@@ -1,38 +0,0 @@
-index(['scheduled_task_id', 'created_at'], 'scheduled_task_executions_task_id_created_at_index');
- });
-
- Schema::table('scheduled_database_backup_executions', function (Blueprint $table) {
- $table->index(
- ['scheduled_database_backup_id', 'created_at'],
- 'scheduled_db_backup_executions_backup_id_created_at_index'
- );
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('scheduled_task_executions', function (Blueprint $table) {
- $table->dropIndex('scheduled_task_executions_task_id_created_at_index');
- });
- Schema::table('scheduled_database_backup_executions', function (Blueprint $table) {
- $table->dropIndex('scheduled_db_backup_executions_backup_id_created_at_index');
- });
- }
-};
diff --git a/database/migrations/2025_03_01_112617_add_stripe_past_due.php b/database/migrations/2025_03_01_112617_add_stripe_past_due.php
deleted file mode 100644
index 6edb4f698b..0000000000
--- a/database/migrations/2025_03_01_112617_add_stripe_past_due.php
+++ /dev/null
@@ -1,28 +0,0 @@
-boolean('stripe_past_due')->default(false);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::table('subscriptions', function (Blueprint $table) {
- $table->dropColumn('stripe_past_due');
- });
- }
-};
diff --git a/database/migrations/2025_03_14_140150_add_storage_deletion_tracking_to_backup_executions.php b/database/migrations/2025_03_14_140150_add_storage_deletion_tracking_to_backup_executions.php
deleted file mode 100644
index c6af6fc490..0000000000
--- a/database/migrations/2025_03_14_140150_add_storage_deletion_tracking_to_backup_executions.php
+++ /dev/null
@@ -1,19 +0,0 @@
-boolean('local_storage_deleted')->default(false);
- $table->boolean('s3_storage_deleted')->default(false);
- });
- }
-};
diff --git a/database/seeders/ApplicationSeeder.php b/database/seeders/ApplicationSeeder.php
deleted file mode 100644
index f75400ce90..0000000000
--- a/database/seeders/ApplicationSeeder.php
+++ /dev/null
@@ -1,66 +0,0 @@
- 'NodeJS Fastify Example',
- 'fqdn' => 'http://nodejs.127.0.0.1.sslip.io',
- 'repository_project_id' => 603035348,
- 'git_repository' => 'coollabsio/coolify-examples',
- 'git_branch' => 'main',
- 'base_directory' => '/nodejs',
- 'build_pack' => 'nixpacks',
- 'ports_exposes' => '3000',
- 'environment_id' => 1,
- 'destination_id' => 0,
- 'destination_type' => StandaloneDocker::class,
- 'source_id' => 1,
- 'source_type' => GithubApp::class,
- ]);
- Application::create([
- 'name' => 'Dockerfile Example',
- 'fqdn' => 'http://dockerfile.127.0.0.1.sslip.io',
- 'repository_project_id' => 603035348,
- 'git_repository' => 'coollabsio/coolify-examples',
- 'git_branch' => 'main',
- 'base_directory' => '/dockerfile',
- 'build_pack' => 'dockerfile',
- 'ports_exposes' => '80',
- 'environment_id' => 1,
- 'destination_id' => 0,
- 'destination_type' => StandaloneDocker::class,
- 'source_id' => 0,
- 'source_type' => GithubApp::class,
- ]);
- Application::create([
- 'name' => 'Pure Dockerfile Example',
- 'fqdn' => 'http://pure-dockerfile.127.0.0.1.sslip.io',
- 'git_repository' => 'coollabsio/coolify',
- 'git_branch' => 'main',
- 'git_commit_sha' => 'HEAD',
- 'build_pack' => 'dockerfile',
- 'ports_exposes' => '80',
- 'environment_id' => 1,
- 'destination_id' => 0,
- 'destination_type' => StandaloneDocker::class,
- 'source_id' => 0,
- 'source_type' => GithubApp::class,
- 'dockerfile' => 'FROM nginx
-EXPOSE 80
-CMD ["nginx", "-g", "daemon off;"]
-',
- ]);
- }
-}
diff --git a/database/seeders/ApplicationSettingsSeeder.php b/database/seeders/ApplicationSettingsSeeder.php
deleted file mode 100644
index 8e439fd169..0000000000
--- a/database/seeders/ApplicationSettingsSeeder.php
+++ /dev/null
@@ -1,19 +0,0 @@
-load(['settings']);
- $application_1->settings->is_debug_enabled = false;
- $application_1->settings->save();
- }
-}
diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php
deleted file mode 100644
index 6e66c64f4a..0000000000
--- a/database/seeders/DatabaseSeeder.php
+++ /dev/null
@@ -1,33 +0,0 @@
-call([
- InstanceSettingsSeeder::class,
- UserSeeder::class,
- TeamSeeder::class,
- PrivateKeySeeder::class,
- PopulateSshKeysDirectorySeeder::class,
- ServerSeeder::class,
- ServerSettingSeeder::class,
- ProjectSeeder::class,
- StandaloneDockerSeeder::class,
- GithubAppSeeder::class,
- GitlabAppSeeder::class,
- ApplicationSeeder::class,
- ApplicationSettingsSeeder::class,
- LocalPersistentVolumeSeeder::class,
- S3StorageSeeder::class,
- StandalonePostgresqlSeeder::class,
- OauthSettingSeeder::class,
- DisableTwoStepConfirmationSeeder::class,
- SentinelSeeder::class,
- ]);
- }
-}
diff --git a/database/seeders/DisableTwoStepConfirmationSeeder.php b/database/seeders/DisableTwoStepConfirmationSeeder.php
deleted file mode 100644
index c43bf1b015..0000000000
--- a/database/seeders/DisableTwoStepConfirmationSeeder.php
+++ /dev/null
@@ -1,20 +0,0 @@
-updateOrInsert(
- [],
- ['disable_two_step_confirmation' => true]
- );
- }
-}
diff --git a/database/seeders/GithubAppSeeder.php b/database/seeders/GithubAppSeeder.php
deleted file mode 100644
index b34c004736..0000000000
--- a/database/seeders/GithubAppSeeder.php
+++ /dev/null
@@ -1,39 +0,0 @@
- 0,
- 'name' => 'Public GitHub',
- 'api_url' => 'https://api.github.com',
- 'html_url' => 'https://github.com',
- 'is_public' => true,
- 'team_id' => 0,
- ]);
- GithubApp::create([
- 'name' => 'coolify-laravel-dev-public',
- 'uuid' => '69420',
- 'organization' => 'coollabsio',
- 'api_url' => 'https://api.github.com',
- 'html_url' => 'https://github.com',
- 'is_public' => false,
- 'app_id' => 292941,
- 'installation_id' => 37267016,
- 'client_id' => 'Iv1.220e564d2b0abd8c',
- 'client_secret' => '116d1d80289f378410dd70ab4e4b81dd8d2c52b6',
- 'webhook_secret' => '326a47b49054f03288f800d81247ec9414d0abf3',
- 'private_key_id' => 2,
- 'team_id' => 0,
- ]);
- }
-}
diff --git a/database/seeders/GitlabAppSeeder.php b/database/seeders/GitlabAppSeeder.php
deleted file mode 100644
index ec2b7ec5e1..0000000000
--- a/database/seeders/GitlabAppSeeder.php
+++ /dev/null
@@ -1,24 +0,0 @@
- 1,
- 'name' => 'Public GitLab',
- 'api_url' => 'https://gitlab.com/api/v4',
- 'html_url' => 'https://gitlab.com',
- 'is_public' => true,
- 'team_id' => 0,
- ]);
- }
-}
diff --git a/database/seeders/InstanceSettingsSeeder.php b/database/seeders/InstanceSettingsSeeder.php
deleted file mode 100644
index 7f2deb3a6b..0000000000
--- a/database/seeders/InstanceSettingsSeeder.php
+++ /dev/null
@@ -1,44 +0,0 @@
- 0,
- 'is_registration_enabled' => true,
- 'smtp_enabled' => true,
- 'smtp_host' => 'coolify-mail',
- 'smtp_port' => 1025,
- 'smtp_from_address' => 'hi@localhost.com',
- 'smtp_from_name' => 'Coolify',
- ]);
- try {
- $ipv4 = Process::run('curl -4s https://ifconfig.io')->output();
- $ipv4 = trim($ipv4);
- $ipv4 = filter_var($ipv4, FILTER_VALIDATE_IP);
- $settings = instanceSettings();
- if (is_null($settings->public_ipv4) && $ipv4) {
- $settings->update(['public_ipv4' => $ipv4]);
- }
- $ipv6 = Process::run('curl -6s https://ifconfig.io')->output();
- $ipv6 = trim($ipv6);
- $ipv6 = filter_var($ipv6, FILTER_VALIDATE_IP);
- $settings = instanceSettings();
- if (is_null($settings->public_ipv6) && $ipv6) {
- $settings->update(['public_ipv6' => $ipv6]);
- }
- } catch (\Throwable $e) {
- echo "Error: {$e->getMessage()}\n";
- }
- }
-}
diff --git a/database/seeders/LocalPersistentVolumeSeeder.php b/database/seeders/LocalPersistentVolumeSeeder.php
deleted file mode 100644
index 79c105ed36..0000000000
--- a/database/seeders/LocalPersistentVolumeSeeder.php
+++ /dev/null
@@ -1,23 +0,0 @@
- 'test-pv',
- 'mount_path' => '/data',
- 'resource_id' => 1,
- 'resource_type' => Application::class,
- ]);
- }
-}
diff --git a/database/seeders/OauthSettingSeeder.php b/database/seeders/OauthSettingSeeder.php
deleted file mode 100644
index fa692d2dc6..0000000000
--- a/database/seeders/OauthSettingSeeder.php
+++ /dev/null
@@ -1,66 +0,0 @@
- 0;
-
- // We changed how providers are defined in the database, so we authentik does not exists, we need to recreate all of the auth providers
- // Before authentik was a provider, providers started with 0 id
-
- $isOauthAuthentik = OauthSetting::where('provider', 'authentik')->exists();
- if (! $isOauthSeeded || $isOauthAuthentik) {
- foreach ($providers as $provider) {
- OauthSetting::updateOrCreate([
- 'provider' => $provider,
- ]);
- }
-
- return;
- }
-
- $allProviders = OauthSetting::all();
- $notFoundProviders = $providers->diff($allProviders->pluck('provider'));
-
- $allProviders->each(function ($provider) {
- $provider->delete();
- });
- $allProviders->each(function ($provider) {
- $provider = new OauthSetting;
- $provider->provider = $provider->provider;
- unset($provider->id);
- $provider->save();
- });
-
- foreach ($notFoundProviders as $provider) {
- OauthSetting::create([
- 'provider' => $provider,
- ]);
- }
-
- } catch (\Exception $e) {
- Log::error($e->getMessage());
- }
- }
-}
diff --git a/database/seeders/PopulateSshKeysDirectorySeeder.php b/database/seeders/PopulateSshKeysDirectorySeeder.php
deleted file mode 100644
index 87984769ca..0000000000
--- a/database/seeders/PopulateSshKeysDirectorySeeder.php
+++ /dev/null
@@ -1,37 +0,0 @@
-deleteDirectory('');
- Storage::disk('ssh-keys')->makeDirectory('');
- Storage::disk('ssh-mux')->deleteDirectory('');
- Storage::disk('ssh-mux')->makeDirectory('');
-
- PrivateKey::chunk(100, function ($keys) {
- foreach ($keys as $key) {
- $key->storeInFileSystem();
- }
- });
-
- if (isDev()) {
- Process::run('chown -R 9999:9999 '.storage_path('app/ssh/keys'));
- Process::run('chown -R 9999:9999 '.storage_path('app/ssh/mux'));
- } else {
- Process::run('chown -R 9999:root '.storage_path('app/ssh/keys'));
- Process::run('chown -R 9999:root '.storage_path('app/ssh/mux'));
- }
- } catch (\Throwable $e) {
- echo "Error: {$e->getMessage()}\n";
- }
- }
-}
diff --git a/database/seeders/PrivateKeySeeder.php b/database/seeders/PrivateKeySeeder.php
deleted file mode 100644
index 6b44d0867d..0000000000
--- a/database/seeders/PrivateKeySeeder.php
+++ /dev/null
@@ -1,63 +0,0 @@
- 0,
- 'name' => 'Testing Host Key',
- 'description' => 'This is a test docker container',
- 'private_key' => '-----BEGIN OPENSSH PRIVATE KEY-----
-b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
-QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk
-hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA
-AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV
-uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
------END OPENSSH PRIVATE KEY-----
-',
- ]);
-
- PrivateKey::create([
- 'team_id' => 0,
- 'name' => 'development-github-app',
- 'description' => 'This is the key for using the development GitHub app',
- 'private_key' => '-----BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEAstJo/SfYh3tquc2BA29a1X3pdPpXazRgtKsb5fHOwQs1rE04
-VyJYW6QCToSH4WS1oKt6iI4ma4uivn8rnkZFdw3mpcLp2ofcoeV3YPKX6pN/RiJC
-if+g8gCaFywOxy2pjXOLPZeFJSXFqc4UOymbhESUyDnMfk4/RvnubMiv3jINo4Ow
-4Tv7tRzAdMlMrx3hEhi142oQuyl1kc4WQOM9cAV0bd+62ga3EYSnsWTnC9AaFtWk
-eGC5w/7knHJ5QZ9tKApkG3/29vJXY7WwCRUROEHqkvQhRDP0uqRPBdR48iG87Dwq
-ePa6TodkFaVfyHS/OUZzRiTn6MOSyQQFg0QIIwIDAQABAoIBAQCsmGebSJU2lwl4
-0oAeZ6E9hG0LagFsSL66QpkHxO9w5bflWRbzCwRLVy6eyE46XzDrJfd7y/ALR1hK
-E4ZvGpY7heBDx7BdK1rprAggO6YjVD+42qJsfZ3DVo9jpDOTTWBkVcxkI1Xwd9ej
-wHNIcy1WabdM1nSoyC9M+ziEKOOOShXc5Q6e+zEzSBbwjc1fvvXZOH4VXZZ1DllE
-xGu0jFS23TLnXATxh8SdfYgnvfZgB5n72P9m/lj3FmkuJq57DLZhBwN3Zd4wom03
-K7/J4K2Ssnjdv/HjVgrRgpMv7oMxfclN/Aiq878Ue4Mav6LjnLENyHbyR0WxQjY6
-lZ7UMEeJAoGBAOCGepk3rCMFa3a6GagN6lYzAkLxB5y0PsefiDo6w+PeEj1tUvSd
-aQkiP7uvUC7a5GNp9yE8W79/O1jJXYJq15kMBpUshzfgdzyzDDCj+qvm6nbTWtP9
-rP30h81R+NGdOStgs0OVZSjMWnIoii3Rv3UV4+iQXZd67+wd/kbTWtWVAoGBAMvj
-xv4wjt7OwtK/6oAhcNd2V9EUQp6PPpMkUyPicWdsLsoNOcuTpWvEc0AomdIGGjgI
-AIor1ggCxjEhbCDaZucOFUghciUup+PjyQyQT+3bjvCWuUmi0Vt51G7RE0jjZjQt
-2+W9V4yDcJ5R5ow6veYvT0ZOjVTScDYowTBulgjXAoGBALFxVl7UotQiqmVwempY
-ZQSu13C0MIHl6V+2cuEiJEJn9R5a0h7EcIhpatkXmlUNZUY0Lr0ziIb1NJ/ctGwn
-qDAqUuF+CXddjJ6KGm4uiiNlIZO7QaMcbqVdph3cVLrEeLQRfltBLGtr5WcnJt1D
-UP5lyHK59V2MKSUAJz8uNjFpAoGAL5fR4Y/wKa5V5+AImzQzJPho81MpYd3KG4rF
-JYE8O4oTOfLwZMboPEm1JWrUzSPDhwTHK3mkEmajYOCOXvTcRF8TNK0p+ef0JMwN
-KDOflMRFj39/bOLmv9Wmct+3ArKiLtftlqkmAJTF+w7fJCiqH0s31A+OChi9PMcy
-oV2PBC0CgYAXOm08kFOQA+bPBdLAte8Ga89frh6asH/Z8ucfsz9/zMMG/hhq5nF3
-7TItY9Pblc2Fp805J13G96zWLX4YGyLwXXkYs+Ae7QoqjonTw7/mUDARY1Zxs9m/
-a1C8EDKapCw5hAhizEFOUQKOygL8Ipn+tmEUkORYdZ8Q8cWFCv9nIw==
------END RSA PRIVATE KEY-----',
- 'is_git_related' => true,
- ]);
- }
-}
diff --git a/database/seeders/ProductionSeeder.php b/database/seeders/ProductionSeeder.php
deleted file mode 100644
index bbb9fcb752..0000000000
--- a/database/seeders/ProductionSeeder.php
+++ /dev/null
@@ -1,197 +0,0 @@
-where('user_id', 0)->first() === null) {
- DB::table('team_user')->insert([
- 'user_id' => 0,
- 'team_id' => 0,
- 'role' => 'owner',
- 'created_at' => now(),
- 'updated_at' => now(),
- ]);
- }
- }
-
- if (InstanceSettings::find(0) == null) {
- InstanceSettings::create([
- 'id' => 0,
- ]);
- }
-
- if (GithubApp::find(0) == null) {
- GithubApp::create([
- 'id' => 0,
- 'name' => 'Public GitHub',
- 'api_url' => 'https://api.github.com',
- 'html_url' => 'https://github.com',
- 'is_public' => true,
- 'team_id' => 0,
- ]);
- }
-
- if (GitlabApp::find(0) == null) {
- GitlabApp::create([
- 'id' => 0,
- 'name' => 'Public GitLab',
- 'api_url' => 'https://gitlab.com/api/v4',
- 'html_url' => 'https://gitlab.com',
- 'is_public' => true,
- 'team_id' => 0,
- ]);
- }
-
- if (! isCloud() && config('constants.coolify.is_windows_docker_desktop') == false) {
- $coolify_key_name = '@host.docker.internal';
- $ssh_keys_directory = Storage::disk('ssh-keys')->files();
- $coolify_key = collect($ssh_keys_directory)->firstWhere(fn ($item) => str($item)->contains($coolify_key_name));
-
- $private_key_found = PrivateKey::find(0);
- if (! $private_key_found) {
- if ($coolify_key) {
- $user = str($coolify_key)->before('@')->after('id.');
- $coolify_key = Storage::disk('ssh-keys')->get($coolify_key);
- PrivateKey::create([
- 'id' => 0,
- 'team_id' => 0,
- 'name' => 'localhost\'s key',
- 'description' => 'The private key for the Coolify host machine (localhost).',
- 'private_key' => $coolify_key,
- ]);
- echo "SSH key found for the Coolify host machine (localhost).\n";
- } else {
- echo "No SSH key found for the Coolify host machine (localhost).\n";
- echo "Please read the following documentation (point 3) to fix it: https://coolify.
- io/docs/knowledge-base/server/openssh/\n";
- echo "Your localhost connection won't work until then.";
- }
- }
- }
-
- if (! isCloud()) {
- if (Server::find(0) == null) {
- $server_details = [
- 'id' => 0,
- 'name' => 'localhost',
- 'description' => "This is the server where Coolify is running on. Don't delete this!",
- 'user' => $user,
- 'ip' => 'host.docker.internal',
- 'team_id' => 0,
- 'private_key_id' => 0,
- ];
- $server_details['proxy'] = ServerMetadata::from([
- 'type' => ProxyTypes::TRAEFIK->value,
- 'status' => ProxyStatus::EXITED->value,
- ]);
- $server = Server::create($server_details);
- $server->settings->is_reachable = true;
- $server->settings->is_usable = true;
- $server->settings->save();
- } else {
- $server = Server::find(0);
- $server->settings->is_reachable = true;
- $server->settings->is_usable = true;
- $server->settings->save();
- }
-
- if (StandaloneDocker::find(0) == null) {
- StandaloneDocker::create([
- 'id' => 0,
- 'name' => 'localhost-coolify',
- 'network' => 'coolify',
- 'server_id' => 0,
- ]);
- }
- }
-
- if (config('constants.coolify.is_windows_docker_desktop')) {
- PrivateKey::updateOrCreate(
- [
- 'id' => 0,
- 'team_id' => 0,
- ],
- [
- 'name' => 'Testing-host',
- 'description' => 'This is a a docker container with SSH access',
- 'private_key' => '-----BEGIN OPENSSH PRIVATE KEY-----
-b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
-QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk
-hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA
-AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV
-uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
------END OPENSSH PRIVATE KEY-----
-',
- ]
- );
- if (Server::find(0) == null) {
- $server_details = [
- 'id' => 0,
- 'uuid' => 'coolify-testing-host',
- 'name' => 'localhost',
- 'description' => "This is the server where Coolify is running on. Don't delete this!",
- 'user' => 'root',
- 'ip' => 'coolify-testing-host',
- 'team_id' => 0,
- 'private_key_id' => 0,
- ];
- $server_details['proxy'] = ServerMetadata::from([
- 'type' => ProxyTypes::TRAEFIK->value,
- 'status' => ProxyStatus::EXITED->value,
- ]);
- $server = Server::create($server_details);
- $server->settings->is_reachable = true;
- $server->settings->is_usable = true;
- $server->settings->save();
- } else {
- $server = Server::find(0);
- $server->settings->is_reachable = true;
- $server->settings->is_usable = true;
- $server->settings->save();
- }
-
- if (StandaloneDocker::find(0) == null) {
- StandaloneDocker::create([
- 'id' => 0,
- 'name' => 'localhost-coolify',
- 'network' => 'coolify',
- 'server_id' => 0,
- ]);
- }
- }
-
- get_public_ips();
-
- $this->call(OauthSettingSeeder::class);
- $this->call(PopulateSshKeysDirectorySeeder::class);
- $this->call(SentinelSeeder::class);
- $this->call(RootUserSeeder::class);
- }
-}
diff --git a/database/seeders/ProjectSeeder.php b/database/seeders/ProjectSeeder.php
deleted file mode 100644
index 33cd8cd06f..0000000000
--- a/database/seeders/ProjectSeeder.php
+++ /dev/null
@@ -1,18 +0,0 @@
- 'My first project',
- 'description' => 'This is a test project in development',
- 'team_id' => 0,
- ]);
- }
-}
diff --git a/database/seeders/RootUserSeeder.php b/database/seeders/RootUserSeeder.php
deleted file mode 100644
index e3968a1c9c..0000000000
--- a/database/seeders/RootUserSeeder.php
+++ /dev/null
@@ -1,74 +0,0 @@
-exists()) {
- echo "\n INFO Root user already exists. Skipping creation.\n\n";
-
- return;
- }
-
- if (! env('ROOT_USER_EMAIL') || ! env('ROOT_USER_PASSWORD')) {
- return;
- }
-
- $validator = Validator::make([
- 'email' => env('ROOT_USER_EMAIL'),
- 'username' => env('ROOT_USERNAME', 'Root User'),
- 'password' => env('ROOT_USER_PASSWORD'),
- ], [
- 'email' => ['required', 'email:rfc,dns', 'max:255'],
- 'username' => ['required', 'string', 'min:3', 'max:255', 'regex:/^[\w\s-]+$/'],
- 'password' => ['required', 'string', 'min:8', Password::min(8)->mixedCase()->letters()->numbers()->symbols()->uncompromised()],
- ]);
-
- if ($validator->fails()) {
- echo "\n ERROR Invalid Root User Environment Variables\n";
- foreach ($validator->errors()->all() as $error) {
- echo " → {$error}\n";
- }
- echo "\n";
-
- return;
- }
-
- try {
- User::create([
- 'id' => 0,
- 'name' => env('ROOT_USERNAME', 'Root User'),
- 'email' => env('ROOT_USER_EMAIL'),
- 'password' => Hash::make(env('ROOT_USER_PASSWORD')),
- ]);
- echo "\n SUCCESS Root user created successfully.\n\n";
- } catch (\Exception $e) {
- echo "\n ERROR Failed to create root user: {$e->getMessage()}\n\n";
-
- return;
- }
-
- try {
- InstanceSettings::updateOrCreate(
- ['id' => 0],
- ['is_registration_enabled' => false]
- );
- echo "\n SUCCESS Registration has been disabled successfully.\n\n";
- } catch (\Exception $e) {
- echo "\n ERROR Failed to update instance settings: {$e->getMessage()}\n\n";
- }
- } catch (\Exception $e) {
- echo "\n ERROR An unexpected error occurred: {$e->getMessage()}\n\n";
- }
- }
-}
diff --git a/database/seeders/S3StorageSeeder.php b/database/seeders/S3StorageSeeder.php
deleted file mode 100644
index de7cef6dc5..0000000000
--- a/database/seeders/S3StorageSeeder.php
+++ /dev/null
@@ -1,25 +0,0 @@
- 'Local MinIO',
- 'description' => 'Local MinIO S3 Storage',
- 'key' => 'minioadmin',
- 'secret' => 'minioadmin',
- 'bucket' => 'local',
- 'endpoint' => 'http://coolify-minio:9000',
- 'team_id' => 0,
- ]);
- }
-}
diff --git a/database/seeders/SentinelSeeder.php b/database/seeders/SentinelSeeder.php
deleted file mode 100644
index 3cf9139333..0000000000
--- a/database/seeders/SentinelSeeder.php
+++ /dev/null
@@ -1,32 +0,0 @@
-settings->sentinel_token)->isEmpty()) {
- $server->settings->generateSentinelToken(ignoreEvent: true);
- }
- if (str($server->settings->sentinel_custom_url)->isEmpty()) {
- $url = $server->settings->generateSentinelUrl(ignoreEvent: true);
- if (str($url)->isEmpty()) {
- $server->settings->is_sentinel_enabled = false;
- $server->settings->save();
- }
- }
- } catch (\Throwable $e) {
- Log::error('Error seeding sentinel: '.$e->getMessage());
- }
- }
- });
- }
-}
diff --git a/database/seeders/ServerSeeder.php b/database/seeders/ServerSeeder.php
deleted file mode 100644
index d328431071..0000000000
--- a/database/seeders/ServerSeeder.php
+++ /dev/null
@@ -1,27 +0,0 @@
- 0,
- 'name' => 'localhost',
- 'description' => 'This is a test docker container in development mode',
- 'ip' => 'coolify-testing-host',
- 'team_id' => 0,
- 'private_key_id' => 1,
- 'proxy' => [
- 'type' => ProxyTypes::TRAEFIK->value,
- 'status' => ProxyStatus::EXITED->value,
- ],
- ]);
- }
-}
diff --git a/database/seeders/ServerSettingSeeder.php b/database/seeders/ServerSettingSeeder.php
deleted file mode 100644
index af4a2694b6..0000000000
--- a/database/seeders/ServerSettingSeeder.php
+++ /dev/null
@@ -1,22 +0,0 @@
-load(['settings']);
- $server_2->settings->wildcard_domain = 'http://127.0.0.1.sslip.io';
- $server_2->settings->is_build_server = false;
- $server_2->settings->is_usable = true;
- $server_2->settings->is_reachable = true;
- $server_2->settings->save();
- }
-}
diff --git a/database/seeders/SharedEnvironmentVariableSeeder.php b/database/seeders/SharedEnvironmentVariableSeeder.php
deleted file mode 100644
index 54643fe3b9..0000000000
--- a/database/seeders/SharedEnvironmentVariableSeeder.php
+++ /dev/null
@@ -1,36 +0,0 @@
- 'NODE_ENV',
- 'value' => 'team_env',
- 'type' => 'team',
- 'team_id' => 0,
- ]);
- SharedEnvironmentVariable::create([
- 'key' => 'NODE_ENV',
- 'value' => 'env_env',
- 'type' => 'environment',
- 'environment_id' => 1,
- 'team_id' => 0,
- ]);
- SharedEnvironmentVariable::create([
- 'key' => 'NODE_ENV',
- 'value' => 'project_env',
- 'type' => 'project',
- 'project_id' => 1,
- 'team_id' => 0,
- ]);
- }
-}
diff --git a/database/seeders/StandaloneDockerSeeder.php b/database/seeders/StandaloneDockerSeeder.php
deleted file mode 100644
index a466de56bb..0000000000
--- a/database/seeders/StandaloneDockerSeeder.php
+++ /dev/null
@@ -1,24 +0,0 @@
- 0,
- 'name' => 'Standalone Docker 1',
- 'network' => 'coolify',
- 'server_id' => 0,
- ]);
- }
- }
-}
diff --git a/database/seeders/StandalonePostgresqlSeeder.php b/database/seeders/StandalonePostgresqlSeeder.php
deleted file mode 100644
index 1fc96a610a..0000000000
--- a/database/seeders/StandalonePostgresqlSeeder.php
+++ /dev/null
@@ -1,22 +0,0 @@
- 'Local PostgreSQL',
- 'description' => 'Local PostgreSQL for testing',
- 'postgres_password' => 'postgres',
- 'environment_id' => 1,
- 'destination_id' => 0,
- 'destination_type' => StandaloneDocker::class,
- ]);
- }
-}
diff --git a/database/seeders/StandaloneRedisSeeder.php b/database/seeders/StandaloneRedisSeeder.php
deleted file mode 100644
index e7bf3373eb..0000000000
--- a/database/seeders/StandaloneRedisSeeder.php
+++ /dev/null
@@ -1,22 +0,0 @@
- 'Local PostgreSQL',
- 'description' => 'Local PostgreSQL for testing',
- 'redis_password' => 'redis',
- 'environment_id' => 1,
- 'destination_id' => 0,
- 'destination_type' => StandaloneDocker::class,
- ]);
- }
-}
diff --git a/database/seeders/TeamSeeder.php b/database/seeders/TeamSeeder.php
deleted file mode 100644
index 67c5ec4897..0000000000
--- a/database/seeders/TeamSeeder.php
+++ /dev/null
@@ -1,23 +0,0 @@
-description = 'The root team';
- $root_user_personal_team->save();
-
- $normal_user_in_root_team->teams()->attach($root_user_personal_team);
- $normal_user_not_in_root_team = User::find(2);
- $normal_user_in_root_team_personal_team = Team::find(1);
- $normal_user_not_in_root_team->teams()->attach($normal_user_in_root_team_personal_team, ['role' => 'admin']);
- }
-}
diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php
deleted file mode 100644
index 2ac615cc01..0000000000
--- a/database/seeders/UserSeeder.php
+++ /dev/null
@@ -1,28 +0,0 @@
-create([
- 'id' => 0,
- 'name' => 'Root User',
- 'email' => 'test@example.com',
- ]);
- User::factory()->create([
- 'id' => 1,
- 'name' => 'Normal User (but in root team)',
- 'email' => 'test2@example.com',
- ]);
- User::factory()->create([
- 'id' => 2,
- 'name' => 'Normal User (not in root team)',
- 'email' => 'test3@example.com',
- ]);
- }
-}
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
deleted file mode 100644
index 3fadd914c1..0000000000
--- a/docker-compose.dev.yml
+++ /dev/null
@@ -1,125 +0,0 @@
-services:
- coolify:
- build:
- context: .
- dockerfile: ./docker/development/Dockerfile
- args:
- - USER_ID=${USERID:-1000}
- - GROUP_ID=${GROUPID:-1000}
- ports:
- - "${APP_PORT:-8000}:8080"
- environment:
- AUTORUN_ENABLED: false
- PUSHER_HOST: "${PUSHER_HOST}"
- PUSHER_PORT: "${PUSHER_PORT}"
- PUSHER_SCHEME: "${PUSHER_SCHEME:-http}"
- PUSHER_APP_ID: "${PUSHER_APP_ID:-coolify}"
- PUSHER_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
- PUSHER_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}"
- volumes:
- - .:/var/www/html/:cached
- - dev_backups_data:/var/www/html/storage/app/backups
- postgres:
- pull_policy: always
- ports:
- - "${FORWARD_DB_PORT:-5432}:5432"
- env_file:
- - .env
- environment:
- POSTGRES_USER: "${DB_USERNAME:-coolify}"
- POSTGRES_PASSWORD: "${DB_PASSWORD:-password}"
- POSTGRES_DB: "${DB_DATABASE:-coolify}"
- POSTGRES_HOST_AUTH_METHOD: "trust"
- volumes:
- - dev_postgres_data:/var/lib/postgresql/data
- redis:
- pull_policy: always
- ports:
- - "${FORWARD_REDIS_PORT:-6379}:6379"
- env_file:
- - .env
- volumes:
- - dev_redis_data:/data
- soketi:
- build:
- context: .
- dockerfile: ./docker/coolify-realtime/Dockerfile
- env_file:
- - .env
- ports:
- - "${FORWARD_SOKETI_PORT:-6001}:6001"
- - "6002:6002"
- volumes:
- - ./storage:/var/www/html/storage
- - ./docker/coolify-realtime/terminal-server.js:/terminal/terminal-server.js
- environment:
- SOKETI_DEBUG: "false"
- SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID:-coolify}"
- SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
- SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}"
- entrypoint: ["/bin/sh", "/soketi-entrypoint.sh"]
- vite:
- image: node:20-alpine
- pull_policy: always
- working_dir: /var/www/html
- environment:
- VITE_HOST: "${VITE_HOST:-localhost}"
- VITE_PORT: "${VITE_PORT:-5173}"
- ports:
- - "${VITE_PORT:-5173}:${VITE_PORT:-5173}"
- volumes:
- - .:/var/www/html/:cached
- command: sh -c "npm install && npm run dev"
- networks:
- - coolify
- testing-host:
- build:
- context: .
- dockerfile: ./docker/testing-host/Dockerfile
- init: true
- container_name: coolify-testing-host
- volumes:
- - /var/run/docker.sock:/var/run/docker.sock
- - dev_coolify_data:/data/coolify
- - dev_backups_data:/data/coolify/backups
- - dev_postgres_data:/data/coolify/_volumes/database
- - dev_redis_data:/data/coolify/_volumes/redis
- - dev_minio_data:/data/coolify/_volumes/minio
- networks:
- - coolify
- mailpit:
- image: axllent/mailpit:latest
- pull_policy: always
- container_name: coolify-mail
- ports:
- - "${FORWARD_MAILPIT_PORT:-1025}:1025"
- - "${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025"
- networks:
- - coolify
- minio:
- image: minio/minio:latest
- pull_policy: always
- container_name: coolify-minio
- command: server /data --console-address ":9001"
- ports:
- - "${FORWARD_MINIO_PORT:-9000}:9000"
- - "${FORWARD_MINIO_PORT_CONSOLE:-9001}:9001"
- environment:
- MINIO_ACCESS_KEY: "${MINIO_ACCESS_KEY:-minioadmin}"
- MINIO_SECRET_KEY: "${MINIO_SECRET_KEY:-minioadmin}"
- volumes:
- - dev_minio_data:/data
- networks:
- - coolify
-
-volumes:
- dev_backups_data:
- dev_postgres_data:
- dev_redis_data:
- dev_coolify_data:
- dev_minio_data:
-
-networks:
- coolify:
- name: coolify
- external: false
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
deleted file mode 100644
index 23a65cca66..0000000000
--- a/docker-compose.prod.yml
+++ /dev/null
@@ -1,90 +0,0 @@
-services:
- coolify:
- image: "ghcr.io/coollabsio/coolify:${LATEST_IMAGE:-latest}"
- volumes:
- - type: bind
- source: /data/coolify/source/.env
- target: /var/www/html/.env
- read_only: true
- - /data/coolify/ssh:/var/www/html/storage/app/ssh
- - /data/coolify/applications:/var/www/html/storage/app/applications
- - /data/coolify/databases:/var/www/html/storage/app/databases
- - /data/coolify/services:/var/www/html/storage/app/services
- - /data/coolify/backups:/var/www/html/storage/app/backups
- - /data/coolify/webhooks-during-maintenance:/var/www/html/storage/app/webhooks-during-maintenance
- environment:
- - APP_ENV=${APP_ENV:-production}
- - PHP_MEMORY_LIMIT=${PHP_MEMORY_LIMIT:-256M}
- - PHP_FPM_PM_CONTROL=${PHP_FPM_PM_CONTROL:-dynamic}
- - PHP_FPM_PM_START_SERVERS=${PHP_FPM_PM_START_SERVERS:-1}
- - PHP_FPM_PM_MIN_SPARE_SERVERS=${PHP_FPM_PM_MIN_SPARE_SERVERS:-1}
- - PHP_FPM_PM_MAX_SPARE_SERVERS=${PHP_FPM_PM_MAX_SPARE_SERVERS:-10}
- env_file:
- - /data/coolify/source/.env
- ports:
- - "${APP_PORT:-8000}:8080"
- expose:
- - "${APP_PORT:-8000}"
- healthcheck:
- test: curl --fail http://127.0.0.1:8080/api/health || exit 1
- interval: 5s
- retries: 10
- timeout: 2s
- depends_on:
- postgres:
- condition: service_healthy
- redis:
- condition: service_healthy
- soketi:
- condition: service_healthy
- postgres:
- volumes:
- - coolify-db:/var/lib/postgresql/data
- environment:
- POSTGRES_USER: "${DB_USERNAME}"
- POSTGRES_PASSWORD: "${DB_PASSWORD}"
- POSTGRES_DB: "${DB_DATABASE:-coolify}"
- healthcheck:
- test: [ "CMD-SHELL", "pg_isready -U ${DB_USERNAME}", "-d", "${DB_DATABASE:-coolify}" ]
- interval: 5s
- retries: 10
- timeout: 2s
- redis:
- command: redis-server --save 20 1 --loglevel warning --requirepass ${REDIS_PASSWORD}
- environment:
- REDIS_PASSWORD: "${REDIS_PASSWORD}"
- volumes:
- - coolify-redis:/data
- healthcheck:
- test: redis-cli ping
- interval: 5s
- retries: 10
- timeout: 2s
- soketi:
- image: 'ghcr.io/coollabsio/coolify-realtime:1.0.6'
- ports:
- - "${SOKETI_PORT:-6001}:6001"
- - "6002:6002"
- volumes:
- - /data/coolify/ssh:/var/www/html/storage/app/ssh
- environment:
- APP_NAME: "${APP_NAME:-Coolify}"
- SOKETI_DEBUG: "${SOKETI_DEBUG:-false}"
- SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID}"
- SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY}"
- SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET}"
- healthcheck:
- test: [ "CMD-SHELL", "wget -qO- http://127.0.0.1:6001/ready && wget -qO- http://127.0.0.1:6002/ready || exit 1" ]
- interval: 5s
- retries: 10
- timeout: 2s
-
-volumes:
- coolify-db:
- name: coolify-db
- coolify-redis:
- name: coolify-redis
-
-networks:
- coolify:
- external: true
diff --git a/docker-compose.windows.yml b/docker-compose.windows.yml
deleted file mode 100644
index 519309e394..0000000000
--- a/docker-compose.windows.yml
+++ /dev/null
@@ -1,133 +0,0 @@
-services:
- coolify-testing-host:
- init: true
- image: "ghcr.io/coollabsio/coolify-testing-host:latest"
- pull_policy: always
- container_name: coolify-testing-host
- volumes:
- - //var/run/docker.sock://var/run/docker.sock
- - ./:/data/coolify
- coolify:
- image: "ghcr.io/coollabsio/coolify:latest"
- pull_policy: always
- container_name: coolify
- restart: always
- working_dir: /var/www/html
- extra_hosts:
- - 'host.docker.internal:host-gateway'
- volumes:
- - type: bind
- source: .env
- target: /var/www/html/.env
- read_only: true
- - ./ssh:/var/www/html/storage/app/ssh
- - ./applications:/var/www/html/storage/app/applications
- - ./databases:/var/www/html/storage/app/databases
- - ./services:/var/www/html/storage/app/services
- - ./backups:/var/www/html/storage/app/backups
- - ./webhooks-during-maintenance:/var/www/html/storage/app/webhooks-during-maintenance
- env_file:
- - .env
- environment:
- - APP_ID
- - APP_ENV=production
- - APP_NAME
- - APP_KEY
- - DB_PASSWORD
- - REDIS_PASSWORD
- - SSL_MODE=off
- - PHP_PM_CONTROL=dynamic
- - PHP_PM_START_SERVERS=1
- - PHP_PM_MIN_SPARE_SERVERS=1
- - PHP_PM_MAX_SPARE_SERVERS=10
- - PUSHER_APP_ID
- - PUSHER_APP_KEY
- - PUSHER_APP_SECRET
- - AUTOUPDATE=true
- - SELF_HOSTED=true
- - SSH_MUX_ENABLED=false
- - IS_WINDOWS_DOCKER_DESKTOP=true
- ports:
- - "${APP_PORT:-8000}:8080"
- expose:
- - "${APP_PORT:-8000}"
- healthcheck:
- test: curl --fail http://localhost:8080/api/health || exit 1
- interval: 5s
- retries: 10
- timeout: 2s
- depends_on:
- postgres:
- condition: service_healthy
- redis:
- condition: service_healthy
- postgres:
- image: postgres:15-alpine
- pull_policy: always
- container_name: coolify-db
- restart: always
- env_file:
- - .env
- volumes:
- - coolify-db:/var/lib/postgresql/data
- environment:
- POSTGRES_USER: "${DB_USERNAME}"
- POSTGRES_PASSWORD: "${DB_PASSWORD}"
- POSTGRES_DB: "${DB_DATABASE:-coolify}"
- healthcheck:
- test:
- [
- "CMD-SHELL",
- "pg_isready -U ${DB_USERNAME}",
- "-d",
- "${DB_DATABASE:-coolify}"
- ]
- interval: 5s
- retries: 10
- timeout: 2s
- redis:
- image: redis:7-alpine
- pull_policy: always
- container_name: coolify-redis
- restart: always
- command: redis-server --save 20 1 --loglevel warning --requirepass ${REDIS_PASSWORD}
- env_file:
- - .env
- environment:
- REDIS_PASSWORD: "${REDIS_PASSWORD}"
- volumes:
- - coolify-redis:/data
- healthcheck:
- test: redis-cli ping
- interval: 5s
- retries: 10
- timeout: 2s
- soketi:
- image: 'ghcr.io/coollabsio/coolify-realtime:1.0.6'
- pull_policy: always
- container_name: coolify-realtime
- restart: always
- env_file:
- - .env
- ports:
- - "${SOKETI_PORT:-6001}:6001"
- - "6002:6002"
- volumes:
- - ./ssh:/var/www/html/storage/app/ssh
- environment:
- APP_NAME: "${APP_NAME:-Coolify}"
- SOKETI_DEBUG: "${SOKETI_DEBUG:-false}"
- SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID}"
- SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY}"
- SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET}"
- healthcheck:
- test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:6001/ready && wget -qO- http://127.0.0.1:6002/ready || exit 1"]
- interval: 5s
- retries: 10
- timeout: 2s
-
-volumes:
- coolify-db:
- name: coolify-db
- coolify-redis:
- name: coolify-redis
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index 0fd3dda070..0000000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-services:
- coolify:
- container_name: coolify
- restart: always
- working_dir: /var/www/html
- extra_hosts:
- - host.docker.internal:host-gateway
- networks:
- - coolify
- depends_on:
- - postgres
- - redis
- - soketi
- postgres:
- image: postgres:15-alpine
- container_name: coolify-db
- restart: always
- networks:
- - coolify
- redis:
- image: redis:7-alpine
- container_name: coolify-redis
- restart: always
- networks:
- - coolify
- soketi:
- container_name: coolify-realtime
- extra_hosts:
- - host.docker.internal:host-gateway
- restart: always
- networks:
- - coolify
-networks:
- coolify:
- name: coolify
- driver: bridge
- external: false
diff --git a/docker/coolify-helper/Dockerfile b/docker/coolify-helper/Dockerfile
deleted file mode 100644
index 6576100147..0000000000
--- a/docker/coolify-helper/Dockerfile
+++ /dev/null
@@ -1,54 +0,0 @@
-# Versions
-# https://hub.docker.com/_/alpine
-ARG BASE_IMAGE=alpine:3.21
-# https://download.docker.com/linux/static/stable/
-ARG DOCKER_VERSION=28.0.0
-# https://github.com/docker/compose/releases
-ARG DOCKER_COMPOSE_VERSION=2.33.1
-# https://github.com/docker/buildx/releases
-ARG DOCKER_BUILDX_VERSION=0.21.1
-# https://github.com/buildpacks/pack/releases
-ARG PACK_VERSION=0.36.4
-# https://github.com/railwayapp/nixpacks/releases
-ARG NIXPACKS_VERSION=1.33.0
-# https://github.com/minio/mc/releases
-ARG MINIO_VERSION=RELEASE.2025-02-15T10-36-16Z
-
-FROM minio/mc:${MINIO_VERSION} AS minio-client
-
-FROM ${BASE_IMAGE} AS base
-
-ARG TARGETPLATFORM
-ARG DOCKER_VERSION
-ARG DOCKER_COMPOSE_VERSION
-ARG DOCKER_BUILDX_VERSION
-ARG PACK_VERSION
-ARG NIXPACKS_VERSION
-
-USER root
-WORKDIR /artifacts
-RUN apk add --no-cache bash curl git git-lfs openssh-client tar tini
-RUN mkdir -p ~/.docker/cli-plugins
-RUN if [[ ${TARGETPLATFORM} == 'linux/amd64' ]]; then \
- curl -sSL https://github.com/docker/buildx/releases/download/v${DOCKER_BUILDX_VERSION}/buildx-v${DOCKER_BUILDX_VERSION}.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx && \
- curl -sSL https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose && \
- (curl -sSL https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz | tar -C /usr/bin/ --no-same-owner -xzv --strip-components=1 docker/docker) && \
- (curl -sSL https://github.com/buildpacks/pack/releases/download/v${PACK_VERSION}/pack-v${PACK_VERSION}-linux.tgz | tar -C /usr/local/bin/ --no-same-owner -xzv pack) && \
- curl -sSL https://nixpacks.com/install.sh | bash && \
- chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack /root/.docker/cli-plugins/docker-buildx \
- ;fi
-
-RUN if [[ ${TARGETPLATFORM} == 'linux/arm64' ]]; then \
- curl -sSL https://github.com/docker/buildx/releases/download/v${DOCKER_BUILDX_VERSION}/buildx-v${DOCKER_BUILDX_VERSION}.linux-arm64 -o ~/.docker/cli-plugins/docker-buildx && \
- curl -sSL https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-linux-aarch64 -o ~/.docker/cli-plugins/docker-compose && \
- (curl -sSL https://download.docker.com/linux/static/stable/aarch64/docker-${DOCKER_VERSION}.tgz | tar -C /usr/bin/ --no-same-owner -xzv --strip-components=1 docker/docker) && \
- (curl -sSL https://github.com/buildpacks/pack/releases/download/v${PACK_VERSION}/pack-v${PACK_VERSION}-linux-arm64.tgz | tar -C /usr/local/bin/ --no-same-owner -xzv pack) && \
- curl -sSL https://nixpacks.com/install.sh | bash && \
- chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack /root/.docker/cli-plugins/docker-buildx \
- ;fi
-
-COPY --from=minio-client /usr/bin/mc /usr/bin/mc
-RUN chmod +x /usr/bin/mc
-
-ENTRYPOINT ["/sbin/tini", "--"]
-CMD ["tail", "-f", "/dev/null"]
diff --git a/docker/coolify-realtime/Dockerfile b/docker/coolify-realtime/Dockerfile
deleted file mode 100644
index 3a53da4906..0000000000
--- a/docker/coolify-realtime/Dockerfile
+++ /dev/null
@@ -1,28 +0,0 @@
-# Versions
-# https://github.com/soketi/soketi/releases
-ARG SOKETI_VERSION=1.6-16-alpine
-# https://github.com/cloudflare/cloudflared/releases
-ARG CLOUDFLARED_VERSION=2025.2.0
-
-FROM quay.io/soketi/soketi:${SOKETI_VERSION}
-
-ARG TARGETPLATFORM
-ARG CLOUDFLARED_VERSION
-
-WORKDIR /terminal
-RUN apk add --no-cache openssh-client make g++ python3 curl
-COPY docker/coolify-realtime/package.json ./
-RUN npm i
-RUN npm rebuild node-pty --update-binary
-COPY docker/coolify-realtime/soketi-entrypoint.sh /soketi-entrypoint.sh
-COPY docker/coolify-realtime/terminal-server.js /terminal/terminal-server.js
-
-# Install Cloudflared based on architecture
-RUN if [ "${TARGETPLATFORM}" = "linux/amd64" ]; then \
- curl -sSL "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-amd64" -o /usr/local/bin/cloudflared; \
- elif [ "${TARGETPLATFORM}" = "linux/arm64" ]; then \
- curl -sSL "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-arm64" -o /usr/local/bin/cloudflared; \
- fi && \
- chmod +x /usr/local/bin/cloudflared
-
-ENTRYPOINT ["/bin/sh", "/soketi-entrypoint.sh"]
diff --git a/docker/coolify-realtime/package-lock.json b/docker/coolify-realtime/package-lock.json
deleted file mode 100644
index aea3952c03..0000000000
--- a/docker/coolify-realtime/package-lock.json
+++ /dev/null
@@ -1,369 +0,0 @@
-{
- "name": "coolify-realtime",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "dependencies": {
- "@xterm/addon-fit": "0.10.0",
- "@xterm/xterm": "5.5.0",
- "axios": "1.7.9",
- "cookie": "1.0.2",
- "dotenv": "16.4.7",
- "node-pty": "1.0.0",
- "ws": "8.18.1"
- }
- },
- "node_modules/@xterm/addon-fit": {
- "version": "0.10.0",
- "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz",
- "integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==",
- "license": "MIT",
- "peerDependencies": {
- "@xterm/xterm": "^5.0.0"
- }
- },
- "node_modules/@xterm/xterm": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
- "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==",
- "license": "MIT"
- },
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "license": "MIT"
- },
- "node_modules/axios": {
- "version": "1.7.9",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
- "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
- "license": "MIT",
- "dependencies": {
- "follow-redirects": "^1.15.6",
- "form-data": "^4.0.0",
- "proxy-from-env": "^1.1.0"
- }
- },
- "node_modules/call-bind-apply-helpers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
- "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "license": "MIT",
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/cookie": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
- "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "license": "MIT",
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/dotenv": {
- "version": "16.4.7",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
- "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://dotenvx.com"
- }
- },
- "node_modules/dunder-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
- "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.1",
- "es-errors": "^1.3.0",
- "gopd": "^1.2.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-define-property": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
- "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-errors": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
- "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-object-atoms": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
- "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-set-tostringtag": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
- "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.6",
- "has-tostringtag": "^1.0.2",
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/follow-redirects": {
- "version": "1.15.9",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
- "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/RubenVerborgh"
- }
- ],
- "license": "MIT",
- "engines": {
- "node": ">=4.0"
- },
- "peerDependenciesMeta": {
- "debug": {
- "optional": true
- }
- }
- },
- "node_modules/form-data": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
- "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
- "license": "MIT",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "es-set-tostringtag": "^2.1.0",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
- "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "es-define-property": "^1.0.1",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.1.1",
- "function-bind": "^1.1.2",
- "get-proto": "^1.0.1",
- "gopd": "^1.2.0",
- "has-symbols": "^1.1.0",
- "hasown": "^2.0.2",
- "math-intrinsics": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
- "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
- "license": "MIT",
- "dependencies": {
- "dunder-proto": "^1.0.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/gopd": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
- "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
- "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-tostringtag": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
- "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
- "license": "MIT",
- "dependencies": {
- "has-symbols": "^1.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/hasown": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
- "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "license": "MIT",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/math-intrinsics": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
- "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "license": "MIT",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/nan": {
- "version": "2.22.1",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.1.tgz",
- "integrity": "sha512-pfRR4ZcNTSm2ZFHaztuvbICf+hyiG6ecA06SfAxoPmuHjvMu0KUIae7Y8GyVkbBqeEIidsmXeYooWIX9+qjfRQ==",
- "license": "MIT"
- },
- "node_modules/node-pty": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.0.0.tgz",
- "integrity": "sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA==",
- "hasInstallScript": true,
- "license": "MIT",
- "dependencies": {
- "nan": "^2.17.0"
- }
- },
- "node_modules/proxy-from-env": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
- "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
- "license": "MIT"
- },
- "node_modules/ws": {
- "version": "8.18.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz",
- "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==",
- "license": "MIT",
- "engines": {
- "node": ">=10.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": ">=5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- }
- }
-}
diff --git a/docker/coolify-realtime/package.json b/docker/coolify-realtime/package.json
deleted file mode 100644
index 0a9b80cb52..0000000000
--- a/docker/coolify-realtime/package.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "private": true,
- "type": "module",
- "dependencies": {
- "@xterm/addon-fit": "0.10.0",
- "@xterm/xterm": "5.5.0",
- "cookie": "1.0.2",
- "axios": "1.7.9",
- "dotenv": "16.4.7",
- "node-pty": "1.0.0",
- "ws": "8.18.1"
- }
-}
diff --git a/docker/coolify-realtime/soketi-entrypoint.sh b/docker/coolify-realtime/soketi-entrypoint.sh
deleted file mode 100644
index 3bb85bdeb9..0000000000
--- a/docker/coolify-realtime/soketi-entrypoint.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh
-# Function to timestamp logs
-
-# Check if the first argument is 'watch'
-if [ "$1" = "watch" ]; then
- WATCH_MODE="--watch"
-else
- WATCH_MODE=""
-fi
-
-timestamp() {
- date "+%Y-%m-%d %H:%M:%S"
-}
-
-# Start the terminal server in the background with logging
-node $WATCH_MODE /terminal/terminal-server.js > >(while read line; do echo "$(timestamp) [TERMINAL] $line"; done) 2>&1 &
-TERMINAL_PID=$!
-
-# Start the Soketi process in the background with logging
-node /app/bin/server.js start > >(while read line; do echo "$(timestamp) [SOKETI] $line"; done) 2>&1 &
-SOKETI_PID=$!
-
-# Function to forward signals to child processes
-forward_signal() {
- kill -$1 $TERMINAL_PID $SOKETI_PID
-}
-
-# Forward SIGTERM to child processes
-trap 'forward_signal TERM' TERM
-
-# Wait for any process to exit
-wait -n
-
-# Exit with status of process that exited first
-exit $?
diff --git a/docker/coolify-realtime/terminal-server.js b/docker/coolify-realtime/terminal-server.js
deleted file mode 100755
index 6649f866cd..0000000000
--- a/docker/coolify-realtime/terminal-server.js
+++ /dev/null
@@ -1,239 +0,0 @@
-import { WebSocketServer } from 'ws';
-import http from 'http';
-import pty from 'node-pty';
-import axios from 'axios';
-import cookie from 'cookie';
-import 'dotenv/config'
-
-const server = http.createServer((req, res) => {
- if (req.url === '/ready') {
- res.writeHead(200, { 'Content-Type': 'text/plain' });
- res.end('OK');
- } else {
- res.writeHead(404, { 'Content-Type': 'text/plain' });
- res.end('Not Found');
- }
-});
-
-const verifyClient = async (info, callback) => {
- const cookies = cookie.parse(info.req.headers.cookie || '');
- // const origin = new URL(info.origin);
- // const protocol = origin.protocol;
- const xsrfToken = cookies['XSRF-TOKEN'];
-
- // Generate session cookie name based on APP_NAME
- const appName = process.env.APP_NAME || 'laravel';
- const sessionCookieName = `${appName.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase()}_session`;
- const laravelSession = cookies[sessionCookieName];
-
- // Verify presence of required tokens
- if (!laravelSession || !xsrfToken) {
- return callback(false, 401, 'Unauthorized: Missing required tokens');
- }
-
- try {
- // Authenticate with Laravel backend
- const response = await axios.post(`http://coolify:8080/terminal/auth`, null, {
- headers: {
- 'Cookie': `${sessionCookieName}=${laravelSession}`,
- 'X-XSRF-TOKEN': xsrfToken
- },
- });
-
- if (response.status === 200) {
- // Authentication successful
- callback(true);
- } else {
- callback(false, 401, 'Unauthorized: Invalid credentials');
- }
- } catch (error) {
- console.error('Authentication error:', error.message);
- callback(false, 500, 'Internal Server Error');
- }
-};
-
-
-const wss = new WebSocketServer({ server, path: '/terminal/ws', verifyClient: verifyClient });
-const userSessions = new Map();
-
-wss.on('connection', (ws) => {
- const userId = generateUserId();
- const userSession = { ws, userId, ptyProcess: null, isActive: false };
- userSessions.set(userId, userSession);
-
- ws.on('message', (message) => {
- handleMessage(userSession, message);
-
- });
- ws.on('error', (err) => handleError(err, userId));
- ws.on('close', () => handleClose(userId));
-
-});
-
-const messageHandlers = {
- message: (session, data) => session.ptyProcess.write(data),
- resize: (session, { cols, rows }) => {
- cols = cols > 0 ? cols : 80;
- rows = rows > 0 ? rows : 30;
- session.ptyProcess.resize(cols, rows)
- },
- pause: (session) => session.ptyProcess.pause(),
- resume: (session) => session.ptyProcess.resume(),
- checkActive: (session, data) => {
- if (data === 'force' && session.isActive) {
- killPtyProcess(session.userId);
- } else {
- session.ws.send(session.isActive);
- }
- },
- command: (session, data) => handleCommand(session.ws, data, session.userId)
-};
-
-function handleMessage(userSession, message) {
- const parsed = parseMessage(message);
- if (!parsed) return;
-
- Object.entries(parsed).forEach(([key, value]) => {
- const handler = messageHandlers[key];
- if (handler && (userSession.isActive || key === 'checkActive' || key === 'command')) {
- handler(userSession, value);
- }
- });
-}
-
-function parseMessage(message) {
- try {
- return JSON.parse(message);
- } catch (e) {
- console.error('Failed to parse message:', e);
- return null;
- }
-}
-
-async function handleCommand(ws, command, userId) {
- const userSession = userSessions.get(userId);
- if (userSession && userSession.isActive) {
- const result = await killPtyProcess(userId);
- if (!result) {
- // if terminal is still active, even after we tried to kill it, dont continue and show error
- ws.send('unprocessable');
- return;
- }
- }
-
- const commandString = command[0].split('\n').join(' ');
- const timeout = extractTimeout(commandString);
- const sshArgs = extractSshArgs(commandString);
- const hereDocContent = extractHereDocContent(commandString);
- const options = {
- name: 'xterm-color',
- cols: 80,
- rows: 30,
- cwd: process.env.HOME,
- env: {},
- };
-
- // NOTE: - Initiates a process within the Terminal container
- // Establishes an SSH connection to root@coolify with RequestTTY enabled
- // Executes the 'docker exec' command to connect to a specific container
- const ptyProcess = pty.spawn('ssh', sshArgs.concat([hereDocContent]), options);
-
- userSession.ptyProcess = ptyProcess;
- userSession.isActive = true;
-
- ws.send('pty-ready');
-
- ptyProcess.onData((data) => {
- ws.send(data);
- });
-
- // when parent closes
- ptyProcess.onExit(({ exitCode, signal }) => {
- console.error(`Process exited with code ${exitCode} and signal ${signal}`);
- ws.send('pty-exited');
- userSession.isActive = false;
-
- });
-
- if (timeout) {
- setTimeout(async () => {
- await killPtyProcess(userId);
- }, timeout * 1000);
- }
-}
-
-async function handleError(err, userId) {
- console.error('WebSocket error:', err);
- await killPtyProcess(userId);
-}
-
-async function handleClose(userId) {
- await killPtyProcess(userId);
- userSessions.delete(userId);
-}
-
-async function killPtyProcess(userId) {
- const session = userSessions.get(userId);
- if (!session?.ptyProcess) return false;
-
- return new Promise((resolve) => {
- // Loop to ensure terminal is killed before continuing
- let killAttempts = 0;
- const maxAttempts = 5;
-
- const attemptKill = () => {
- killAttempts++;
-
- // session.ptyProcess.kill() wont work here because of https://github.com/moby/moby/issues/9098
- // patch with https://github.com/moby/moby/issues/9098#issuecomment-189743947
- session.ptyProcess.write('set +o history\nkill -TERM -$$ && exit\nset -o history\n');
-
- setTimeout(() => {
- if (!session.isActive || !session.ptyProcess) {
- resolve(true);
- return;
- }
-
- if (killAttempts < maxAttempts) {
- attemptKill();
- } else {
- resolve(false);
- }
- }, 500);
- };
-
- attemptKill();
- });
-}
-
-function generateUserId() {
- return Math.random().toString(36).substring(2, 11);
-}
-
-function extractTimeout(commandString) {
- const timeoutMatch = commandString.match(/timeout (\d+)/);
- return timeoutMatch ? parseInt(timeoutMatch[1], 10) : null;
-}
-
-function extractSshArgs(commandString) {
- const sshCommandMatch = commandString.match(/ssh (.+?) 'bash -se'/);
- let sshArgs = sshCommandMatch ? sshCommandMatch[1].split(' ') : [];
- sshArgs = sshArgs.map(arg => arg === 'RequestTTY=no' ? 'RequestTTY=yes' : arg);
- if (!sshArgs.includes('RequestTTY=yes')) {
- sshArgs.push('-o', 'RequestTTY=yes');
- }
- return sshArgs;
-}
-
-function extractHereDocContent(commandString) {
- const delimiterMatch = commandString.match(/<< (\S+)/);
- const delimiter = delimiterMatch ? delimiterMatch[1] : null;
- const escapedDelimiter = delimiter.slice(1).trim().replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
- const hereDocRegex = new RegExp(`<< \\\\${escapedDelimiter}([\\s\\S\\.]*?)${escapedDelimiter}`);
- const hereDocMatch = commandString.match(hereDocRegex);
- return hereDocMatch ? hereDocMatch[1] : '';
-}
-
-server.listen(6002, () => {
- console.log('Coolify realtime terminal server listening on port 6002. Let the hacking begin!');
-});
diff --git a/docker/development/Dockerfile b/docker/development/Dockerfile
deleted file mode 100644
index 0946004555..0000000000
--- a/docker/development/Dockerfile
+++ /dev/null
@@ -1,81 +0,0 @@
-# Versions
-# https://hub.docker.com/r/serversideup/php/tags?name=8.4-fpm-nginx-alpine
-ARG SERVERSIDEUP_PHP_VERSION=8.4-fpm-nginx-alpine
-# https://github.com/minio/mc/releases
-ARG MINIO_VERSION=RELEASE.2025-02-15T10-36-16Z
-# https://github.com/cloudflare/cloudflared/releases
-ARG CLOUDFLARED_VERSION=2025.2.0
-# https://www.postgresql.org/support/versioning/
-ARG POSTGRES_VERSION=15
-
-# =================================================================
-# Get MinIO client
-# =================================================================
-FROM minio/mc:${MINIO_VERSION} AS minio-client
-
-# =================================================================
-# Final Stage: Production image
-# =================================================================
-FROM serversideup/php:${SERVERSIDEUP_PHP_VERSION}
-
-ARG USER_ID
-ARG GROUP_ID
-ARG TARGETPLATFORM
-ARG POSTGRES_VERSION
-ARG CLOUDFLARED_VERSION
-
-WORKDIR /var/www/html
-
-USER root
-
-RUN docker-php-serversideup-set-id www-data $USER_ID:$GROUP_ID && \
- docker-php-serversideup-set-file-permissions --owner $USER_ID:$GROUP_ID --service nginx
-
-# Install PostgreSQL repository and keys
-RUN apk add --no-cache gnupg && \
- mkdir -p /usr/share/keyrings && \
- curl -fSsL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor > /usr/share/keyrings/postgresql.gpg
-
-# Install system dependencies
-RUN apk add --no-cache \
- postgresql${POSTGRES_VERSION}-client \
- openssh-client \
- git \
- git-lfs \
- jq \
- lsof \
- vim
-
-# Configure shell aliases
-RUN echo "alias ll='ls -al'" >> /etc/profile && \
- echo "alias a='php artisan'" >> /etc/profile && \
- echo "alias logs='tail -f storage/logs/laravel.log'" >> /etc/profile
-
-# Install Cloudflared based on architecture
-RUN mkdir -p /usr/local/bin && \
- if [ "${TARGETPLATFORM}" = "linux/amd64" ]; then \
- curl -sSL "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-amd64" -o /usr/local/bin/cloudflared; \
- elif [ "${TARGETPLATFORM}" = "linux/arm64" ]; then \
- curl -sSL "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-arm64" -o /usr/local/bin/cloudflared; \
- fi && \
- chmod +x /usr/local/bin/cloudflared
-
-# Configure PHP
-COPY docker/development/etc/php/conf.d/zzz-custom-php.ini /usr/local/etc/php/conf.d/zzz-custom-php.ini
-ENV PHP_OPCACHE_ENABLE=0
-
-# Configure Nginx and S6 overlay
-COPY docker/development/etc/nginx/conf.d/custom.conf /etc/nginx/conf.d/custom.conf
-COPY docker/development/etc/nginx/site-opts.d/http.conf /etc/nginx/site-opts.d/http.conf
-COPY --chmod=755 docker/development/etc/s6-overlay/ /etc/s6-overlay/
-
-RUN mkdir -p /etc/nginx/conf.d && \
- chown -R www-data:www-data /etc/nginx && \
- chmod -R 755 /etc/nginx
-
-# Install MinIO client
-COPY --from=minio-client /usr/bin/mc /usr/bin/mc
-RUN chmod +x /usr/bin/mc
-
-# Switch to non-root user
-USER www-data
diff --git a/docker/development/etc/nginx/conf.d/custom.conf b/docker/development/etc/nginx/conf.d/custom.conf
deleted file mode 100644
index f26dc30495..0000000000
--- a/docker/development/etc/nginx/conf.d/custom.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-# Custom nginx configuration
-
-# Disable access logs
-access_log off;
diff --git a/docker/development/etc/nginx/site-opts.d/http.conf b/docker/development/etc/nginx/site-opts.d/http.conf
deleted file mode 100644
index a5bbd78a3a..0000000000
--- a/docker/development/etc/nginx/site-opts.d/http.conf
+++ /dev/null
@@ -1,43 +0,0 @@
-listen 8080 default_server;
-listen [::]:8080 default_server;
-
-root /var/www/html/public;
-
-# Set allowed "index" files
-index index.html index.htm index.php;
-
-server_name _;
-
-charset utf-8;
-
-# Set max upload to 2048M
-client_max_body_size 2048M;
-
-# Healthchecks: Set /healthcheck to be the healthcheck URL
-location /healthcheck {
- access_log off;
-
- # set max 5 seconds for healthcheck
- fastcgi_read_timeout 5s;
-
- include fastcgi_params;
- fastcgi_param SCRIPT_NAME /healthcheck;
- fastcgi_param SCRIPT_FILENAME /healthcheck;
- fastcgi_pass 127.0.0.1:9000;
-}
-
-# Have NGINX try searching for PHP files as well
-location / {
- try_files $uri $uri/ /index.php?$query_string;
-}
-
-# Pass "*.php" files to PHP-FPM
-location ~ \.php$ {
- fastcgi_pass 127.0.0.1:9000;
- fastcgi_index index.php;
- fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
- include fastcgi_params;
- fastcgi_buffers 16 16k;
- fastcgi_buffer_size 32k;
- fastcgi_read_timeout 99;
-}
diff --git a/docker/development/etc/php/conf.d/zzz-custom-php.ini b/docker/development/etc/php/conf.d/zzz-custom-php.ini
deleted file mode 100644
index e09eda5386..0000000000
--- a/docker/development/etc/php/conf.d/zzz-custom-php.ini
+++ /dev/null
@@ -1,10 +0,0 @@
-error_reporting = E_ERROR
-error_log = /dev/stderr
-log_errors = On
-log_errors_max_len = 8192
-ignore_repeated_errors = On
-ignore_repeated_source = On
-
-upload_max_filesize = 256M
-post_max_size = 256M
-memory_limit = ${PHP_MEMORY_LIMIT:-512M}
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/horizon/run b/docker/development/etc/s6-overlay/s6-rc.d/horizon/run
deleted file mode 100644
index ada19b3a30..0000000000
--- a/docker/development/etc/s6-overlay/s6-rc.d/horizon/run
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/command/execlineb -P
-
-# Use with-contenv to ensure environment variables are available
-with-contenv
-cd /var/www/html
-
-foreground {
- php
- artisan
- start:horizon
-}
-
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/horizon/type b/docker/development/etc/s6-overlay/s6-rc.d/horizon/type
deleted file mode 100644
index 5883cff0cd..0000000000
--- a/docker/development/etc/s6-overlay/s6-rc.d/horizon/type
+++ /dev/null
@@ -1 +0,0 @@
-longrun
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/init-setup/type b/docker/development/etc/s6-overlay/s6-rc.d/init-setup/type
deleted file mode 100644
index 3d92b15f2d..0000000000
--- a/docker/development/etc/s6-overlay/s6-rc.d/init-setup/type
+++ /dev/null
@@ -1 +0,0 @@
-oneshot
\ No newline at end of file
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/init-setup/up b/docker/development/etc/s6-overlay/s6-rc.d/init-setup/up
deleted file mode 100644
index 67e0f5c1a7..0000000000
--- a/docker/development/etc/s6-overlay/s6-rc.d/init-setup/up
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/command/execlineb -P
-
-# Use with-contenv to ensure environment variables are available
-with-contenv
-cd /var/www/html
-foreground {
- composer
- install
-}
-foreground {
- php
- artisan
- migrate
- --step
-}
-foreground {
- php
- artisan
- dev
- --init
-}
-
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/scheduler-worker/dependencies.d/init-setup b/docker/development/etc/s6-overlay/s6-rc.d/scheduler-worker/dependencies.d/init-setup
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/scheduler-worker/run b/docker/development/etc/s6-overlay/s6-rc.d/scheduler-worker/run
deleted file mode 100644
index b81a448338..0000000000
--- a/docker/development/etc/s6-overlay/s6-rc.d/scheduler-worker/run
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/command/execlineb -P
-
-# Use with-contenv to ensure environment variables are available
-with-contenv
-cd /var/www/html
-
-foreground {
- php
- artisan
- start:scheduler
-}
-
-
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/scheduler-worker/type b/docker/development/etc/s6-overlay/s6-rc.d/scheduler-worker/type
deleted file mode 100644
index 5883cff0cd..0000000000
--- a/docker/development/etc/s6-overlay/s6-rc.d/scheduler-worker/type
+++ /dev/null
@@ -1 +0,0 @@
-longrun
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/horizon b/docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/horizon
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/init-setup b/docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/init-setup
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/scheduler-worker b/docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/scheduler-worker
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/production/Dockerfile b/docker/production/Dockerfile
deleted file mode 100644
index 86fae4a13b..0000000000
--- a/docker/production/Dockerfile
+++ /dev/null
@@ -1,140 +0,0 @@
-# Versions
-# https://hub.docker.com/r/serversideup/php/tags?name=8.4-fpm-nginx-alpine
-ARG SERVERSIDEUP_PHP_VERSION=8.4-fpm-nginx-alpine
-# https://github.com/minio/mc/releases
-ARG MINIO_VERSION=RELEASE.2025-02-15T10-36-16Z
-# https://github.com/cloudflare/cloudflared/releases
-ARG CLOUDFLARED_VERSION=2025.2.0
-# https://www.postgresql.org/support/versioning/
-ARG POSTGRES_VERSION=15
-
-# Add user/group
-ARG USER_ID=9999
-ARG GROUP_ID=9999
-
-# =================================================================
-# Stage 1: Composer dependencies
-# =================================================================
-FROM serversideup/php:${SERVERSIDEUP_PHP_VERSION} AS base
-
-USER root
-
-ARG USER_ID
-ARG GROUP_ID
-
-RUN docker-php-serversideup-set-id www-data $USER_ID:$GROUP_ID && \
- docker-php-serversideup-set-file-permissions --owner $USER_ID:$GROUP_ID --service nginx
-
-WORKDIR /var/www/html
-COPY --chown=www-data:www-data composer.json composer.lock ./
-RUN composer install --no-dev --no-interaction --no-plugins --no-scripts --prefer-dist
-
-USER www-data
-
-# =================================================================
-# Stage 2: Frontend assets compilation
-# =================================================================
-FROM node:20-alpine AS static-assets
-
-WORKDIR /app
-COPY package*.json vite.config.js tailwind.config.js postcss.config.cjs ./
-RUN npm ci
-COPY . .
-RUN npm run build
-
-# =================================================================
-# Stage 3: Get MinIO client
-# =================================================================
-FROM minio/mc:${MINIO_VERSION} AS minio-client
-
-# =================================================================
-# Final Stage: Production image
-# =================================================================
-FROM serversideup/php:${SERVERSIDEUP_PHP_VERSION}
-
-ARG USER_ID
-ARG GROUP_ID
-ARG TARGETPLATFORM
-ARG POSTGRES_VERSION
-ARG CLOUDFLARED_VERSION
-ARG CI=true
-
-WORKDIR /var/www/html
-
-USER root
-
-RUN docker-php-serversideup-set-id www-data $USER_ID:$GROUP_ID && \
- docker-php-serversideup-set-file-permissions --owner $USER_ID:$GROUP_ID --service nginx
-
-# Install PostgreSQL repository and keys
-RUN apk add --no-cache gnupg && \
- mkdir -p /usr/share/keyrings && \
- curl -fSsL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor > /usr/share/keyrings/postgresql.gpg
-
-# Install system dependencies
-RUN apk add --no-cache \
- postgresql${POSTGRES_VERSION}-client \
- openssh-client \
- git \
- git-lfs \
- jq \
- lsof \
- vim
-
-# Configure shell aliases
-RUN echo "alias ll='ls -al'" >> /etc/profile && \
- echo "alias a='php artisan'" >> /etc/profile && \
- echo "alias logs='tail -f storage/logs/laravel.log'" >> /etc/profile
-
-# Install Cloudflared based on architecture
-RUN mkdir -p /usr/local/bin && \
- if [ "${TARGETPLATFORM}" = "linux/amd64" ]; then \
- curl -sSL "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-amd64" -o /usr/local/bin/cloudflared; \
- elif [ "${TARGETPLATFORM}" = "linux/arm64" ]; then \
- curl -sSL "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-arm64" -o /usr/local/bin/cloudflared; \
- fi && \
- chmod +x /usr/local/bin/cloudflared
-
-# Configure PHP
-COPY docker/production/etc/php/conf.d/zzz-custom-php.ini /usr/local/etc/php/conf.d/zzz-custom-php.ini
-ENV PHP_OPCACHE_ENABLE=1
-
-# Configure entrypoint
-COPY --chmod=755 docker/production/entrypoint.d/ /etc/entrypoint.d
-
-# Copy application files from previous stages
-COPY --from=base --chown=www-data:www-data /var/www/html/vendor ./vendor
-COPY --from=static-assets --chown=www-data:www-data /app/public/build ./public/build
-
-# Copy application source code
-COPY --chown=www-data:www-data composer.json composer.lock ./
-COPY --chown=www-data:www-data app ./app
-COPY --chown=www-data:www-data bootstrap ./bootstrap
-COPY --chown=www-data:www-data config ./config
-COPY --chown=www-data:www-data database ./database
-COPY --chown=www-data:www-data lang ./lang
-COPY --chown=www-data:www-data public ./public
-COPY --chown=www-data:www-data routes ./routes
-COPY --chown=www-data:www-data storage ./storage
-COPY --chown=www-data:www-data templates ./templates
-COPY --chown=www-data:www-data resources/views ./resources/views
-COPY --chown=www-data:www-data artisan artisan
-COPY --chown=www-data:www-data openapi.yaml ./openapi.yaml
-
-RUN composer dump-autoload
-
-# Configure Nginx and S6 overlay
-COPY docker/production/etc/nginx/conf.d/custom.conf /etc/nginx/conf.d/custom.conf
-COPY docker/production/etc/nginx/site-opts.d/http.conf /etc/nginx/site-opts.d/http.conf
-COPY --chmod=755 docker/production/etc/s6-overlay/ /etc/s6-overlay/
-
-RUN mkdir -p /etc/nginx/conf.d && \
- chown -R www-data:www-data /etc/nginx && \
- chmod -R 755 /etc/nginx
-
-# Install MinIO client
-COPY --from=minio-client /usr/bin/mc /usr/bin/mc
-RUN chmod +x /usr/bin/mc
-
-# Switch to non-root user
-USER www-data
diff --git a/docker/production/entrypoint.d/99-debug-mode.sh b/docker/production/entrypoint.d/99-debug-mode.sh
deleted file mode 100644
index e0a1813735..0000000000
--- a/docker/production/entrypoint.d/99-debug-mode.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-# Debug mode
-if [ "$APP_DEBUG" = "true" ]; then
- echo "Debug mode is enabled"
- echo "Installing development dependencies..."
- composer install --dev --no-scripts
- echo "Clearing optimized classes..."
- php artisan optimize:clear
-fi
diff --git a/docker/production/etc/nginx/conf.d/custom.conf b/docker/production/etc/nginx/conf.d/custom.conf
deleted file mode 100644
index f26dc30495..0000000000
--- a/docker/production/etc/nginx/conf.d/custom.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-# Custom nginx configuration
-
-# Disable access logs
-access_log off;
diff --git a/docker/production/etc/nginx/site-opts.d/http.conf b/docker/production/etc/nginx/site-opts.d/http.conf
deleted file mode 100644
index a5bbd78a3a..0000000000
--- a/docker/production/etc/nginx/site-opts.d/http.conf
+++ /dev/null
@@ -1,43 +0,0 @@
-listen 8080 default_server;
-listen [::]:8080 default_server;
-
-root /var/www/html/public;
-
-# Set allowed "index" files
-index index.html index.htm index.php;
-
-server_name _;
-
-charset utf-8;
-
-# Set max upload to 2048M
-client_max_body_size 2048M;
-
-# Healthchecks: Set /healthcheck to be the healthcheck URL
-location /healthcheck {
- access_log off;
-
- # set max 5 seconds for healthcheck
- fastcgi_read_timeout 5s;
-
- include fastcgi_params;
- fastcgi_param SCRIPT_NAME /healthcheck;
- fastcgi_param SCRIPT_FILENAME /healthcheck;
- fastcgi_pass 127.0.0.1:9000;
-}
-
-# Have NGINX try searching for PHP files as well
-location / {
- try_files $uri $uri/ /index.php?$query_string;
-}
-
-# Pass "*.php" files to PHP-FPM
-location ~ \.php$ {
- fastcgi_pass 127.0.0.1:9000;
- fastcgi_index index.php;
- fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
- include fastcgi_params;
- fastcgi_buffers 16 16k;
- fastcgi_buffer_size 32k;
- fastcgi_read_timeout 99;
-}
diff --git a/docker/production/etc/php/conf.d/zzz-custom-php.ini b/docker/production/etc/php/conf.d/zzz-custom-php.ini
deleted file mode 100644
index 4002b8f166..0000000000
--- a/docker/production/etc/php/conf.d/zzz-custom-php.ini
+++ /dev/null
@@ -1,10 +0,0 @@
-error_reporting = E_ERROR
-error_log = /var/www/html/storage/logs/php-error.log
-log_errors = Off
-log_errors_max_len = 8192
-ignore_repeated_errors = On
-ignore_repeated_source = On
-
-upload_max_filesize = 256M
-post_max_size = 256M
-memory_limit = ${PHP_MEMORY_LIMIT:-512M}
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/db-migration/type b/docker/production/etc/s6-overlay/s6-rc.d/db-migration/type
deleted file mode 100644
index bdd22a1850..0000000000
--- a/docker/production/etc/s6-overlay/s6-rc.d/db-migration/type
+++ /dev/null
@@ -1 +0,0 @@
-oneshot
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/db-migration/up b/docker/production/etc/s6-overlay/s6-rc.d/db-migration/up
deleted file mode 100644
index c2548d1360..0000000000
--- a/docker/production/etc/s6-overlay/s6-rc.d/db-migration/up
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/command/execlineb -P
-
-# Use with-contenv to ensure environment variables are available
-with-contenv
-cd /var/www/html
-foreground {
- php
- artisan
- start:migration
-}
-
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/horizon/dependencies.d/init-script b/docker/production/etc/s6-overlay/s6-rc.d/horizon/dependencies.d/init-script
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/horizon/run b/docker/production/etc/s6-overlay/s6-rc.d/horizon/run
deleted file mode 100644
index be66476079..0000000000
--- a/docker/production/etc/s6-overlay/s6-rc.d/horizon/run
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/command/execlineb -P
-
-# Use with-contenv to ensure environment variables are available
-with-contenv
-cd /var/www/html
-foreground {
- php
- artisan
- start:horizon
-}
-
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/horizon/type b/docker/production/etc/s6-overlay/s6-rc.d/horizon/type
deleted file mode 100644
index 5883cff0cd..0000000000
--- a/docker/production/etc/s6-overlay/s6-rc.d/horizon/type
+++ /dev/null
@@ -1 +0,0 @@
-longrun
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/init-script/dependencies.d/init-seeder b/docker/production/etc/s6-overlay/s6-rc.d/init-script/dependencies.d/init-seeder
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/init-script/type b/docker/production/etc/s6-overlay/s6-rc.d/init-script/type
deleted file mode 100644
index bdd22a1850..0000000000
--- a/docker/production/etc/s6-overlay/s6-rc.d/init-script/type
+++ /dev/null
@@ -1 +0,0 @@
-oneshot
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/init-script/up b/docker/production/etc/s6-overlay/s6-rc.d/init-script/up
deleted file mode 100644
index 3fad5f2c5f..0000000000
--- a/docker/production/etc/s6-overlay/s6-rc.d/init-script/up
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/command/execlineb -P
-
-# Use with-contenv to ensure environment variables are available
-with-contenv
-cd /var/www/html
-foreground {
- php
- artisan
- app:init
-}
-
-
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/init-seeder/dependencies.d/db-migration b/docker/production/etc/s6-overlay/s6-rc.d/init-seeder/dependencies.d/db-migration
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/init-seeder/type b/docker/production/etc/s6-overlay/s6-rc.d/init-seeder/type
deleted file mode 100644
index bdd22a1850..0000000000
--- a/docker/production/etc/s6-overlay/s6-rc.d/init-seeder/type
+++ /dev/null
@@ -1 +0,0 @@
-oneshot
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/init-seeder/up b/docker/production/etc/s6-overlay/s6-rc.d/init-seeder/up
deleted file mode 100644
index 007f4233e5..0000000000
--- a/docker/production/etc/s6-overlay/s6-rc.d/init-seeder/up
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/command/execlineb -P
-
-# Use with-contenv to ensure environment variables are available
-with-contenv
-cd /var/www/html
-foreground {
- php
- artisan
- start:seeder
-}
-
-
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/scheduler-worker/dependencies.d/init-script b/docker/production/etc/s6-overlay/s6-rc.d/scheduler-worker/dependencies.d/init-script
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/scheduler-worker/run b/docker/production/etc/s6-overlay/s6-rc.d/scheduler-worker/run
deleted file mode 100644
index a2ecb0a73c..0000000000
--- a/docker/production/etc/s6-overlay/s6-rc.d/scheduler-worker/run
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/command/execlineb -P
-
-# Use with-contenv to ensure environment variables are available
-with-contenv
-cd /var/www/html
-foreground {
- php
- artisan
- start:scheduler
-}
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/scheduler-worker/type b/docker/production/etc/s6-overlay/s6-rc.d/scheduler-worker/type
deleted file mode 100644
index 5883cff0cd..0000000000
--- a/docker/production/etc/s6-overlay/s6-rc.d/scheduler-worker/type
+++ /dev/null
@@ -1 +0,0 @@
-longrun
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/db-migration b/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/db-migration
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/horizon b/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/horizon
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/init-script b/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/init-script
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/init-seeder b/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/init-seeder
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/scheduler-worker b/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/scheduler-worker
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docker/testing-host/Dockerfile b/docker/testing-host/Dockerfile
deleted file mode 100644
index c6f5d800e3..0000000000
--- a/docker/testing-host/Dockerfile
+++ /dev/null
@@ -1,36 +0,0 @@
-# Versions
-# https://download.docker.com/linux/static/stable/
-ARG DOCKER_VERSION=28.0.0
-# https://github.com/docker/compose/releases
-ARG DOCKER_COMPOSE_VERSION=2.33.1
-# https://github.com/docker/buildx/releases
-ARG DOCKER_BUILDX_VERSION=0.21.1
-
-
-FROM debian:12-slim
-
-ARG TARGETPLATFORM
-ARG DOCKER_VERSION
-ARG DOCKER_COMPOSE_VERSION
-ARG DOCKER_BUILDX_VERSION
-
-USER root
-WORKDIR /root
-ENV PATH="/host/usr/local/sbin:/host/usr/local/bin:/host/usr/sbin:/host/usr/bin:/host/sbin:/host/bin:$PATH"
-
-RUN apt update && apt -y install openssh-client openssh-server curl wget git jq jc
-RUN mkdir -p ~/.docker/cli-plugins
-RUN curl -sSL https://github.com/docker/buildx/releases/download/v${DOCKER_BUILDX_VERSION}/buildx-v${DOCKER_BUILDX_VERSION}.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx
-RUN curl -sSL https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
-RUN (curl -sSL https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz | tar -C /usr/bin/ --no-same-owner -xzv --strip-components=1 docker/docker)
-RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /root/.docker/cli-plugins/docker-buildx
-
-
-# Setup sshd
-RUN ssh-keygen -A
-RUN mkdir -p /run/sshd
-RUN mkdir -p ~/.ssh
-RUN echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFuGmoeGq/pojrsyP1pszcNVuZx9iFkCELtxrh31QJ68 coolify@coolify-instance" >> ~/.ssh/authorized_keys
-
-EXPOSE 22
-CMD ["/usr/sbin/sshd", "-D", "-o", "ListenAddress=0.0.0.0", "-o", "Port=22"]
diff --git a/hooks/pre-commit b/hooks/pre-commit
deleted file mode 100644
index 69a5a9d416..0000000000
--- a/hooks/pre-commit
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/sh
-# Detect whether /dev/tty is available & functional
-if sh -c ": >/dev/tty" >/dev/null 2>/dev/null; then
- exec < /dev/tty
-fi
-
-# Get list of stashed PHP files
-stashed_files=$(git diff --cached --name-only --diff-filter=ACM -- '*.php')
-
-# If there are no stashed PHP files, exit early
-if [ -z "$stashed_files" ]; then
- exit 0
-fi
-
-# Set files variable to only include stashed PHP files
-files="$stashed_files"
-
-$(pwd)/vendor/bin/pint $files -q
-if [ $? -eq 0 ]; then
- git add $files
-fi
diff --git a/lang/ar.json b/lang/ar.json
deleted file mode 100644
index 9befd1e4a1..0000000000
--- a/lang/ar.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "auth.login": "تسجيل الدخول",
- "auth.login.authentik": "تسجيل الدخول باستخدام Authentik",
- "auth.login.azure": "تسجيل الدخول باستخدام Microsoft",
- "auth.login.bitbucket": "تسجيل الدخول باستخدام Bitbucket",
- "auth.login.github": "تسجيل الدخول باستخدام GitHub",
- "auth.login.gitlab": "تسجيل الدخول باستخدام Gitlab",
- "auth.login.google": "تسجيل الدخول باستخدام Google",
- "auth.login.infomaniak": "تسجيل الدخول باستخدام Infomaniak",
- "auth.already_registered": "هل سبق لك التسجيل؟",
- "auth.confirm_password": "تأكيد كلمة المرور",
- "auth.forgot_password": "نسيت كلمة المرور",
- "auth.forgot_password_send_email": "إرسال بريد إلكتروني لإعادة تعيين كلمة المرور",
- "auth.register_now": "تسجيل",
- "auth.logout": "تسجيل الخروج",
- "auth.register": "تسجيل",
- "auth.registration_disabled": "تم تعطيل التسجيل. يرجى التواصل مع المسؤول.",
- "auth.reset_password": "إعادة تعيين كلمة المرور",
- "auth.failed": "هذه البيانات لا تتطابق مع سجلاتنا.",
- "auth.failed.callback": "فشل في معالجة استدعاء من مزود تسجيل الدخول.",
- "auth.failed.password": "كلمة المرور المقدمة غير صحيحة.",
- "auth.failed.email": "لا يمكننا العثور على مستخدم بهذا البريد الإلكتروني.",
- "auth.throttle": "عدد محاولات تسجيل الدخول كثيرة جدًا. يرجى المحاولة مرة أخرى في :seconds ثانية.",
- "input.name": "الاسم",
- "input.email": "البريد الإلكتروني",
- "input.password": "كلمة المرور",
- "input.password.again": "كلمة المرور مرة أخرى",
- "input.code": "الرمز لمرة واحدة",
- "input.recovery_code": "رمز الاسترداد",
- "button.save": "حفظ",
- "repository.url": "أمثلة للمستودعات العامة، استخدم https://... . للمستودعات الخاصة، استخدم git@... . سيتم تحديد الفرع main لـ https://github.com/coollabsio/coolify-examples سيتم تحديد الفرع nodejs-fastify لـ https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify سيتم تحديد الفرع main لـ https://gitea.com/sedlav/expressjs.git سيتم تحديد الفرع main لـ https://gitlab.com/andrasbacsai/nodejs-example.git .",
- "service.stop": "سيتم إيقاف هذه الخدمة.",
- "resource.docker_cleanup": "قم بتشغيل Docker Cleanup (قم بإزالة الصور غير المستخدمة وذاكرة التخزين المؤقت للمنشئ).",
- "resource.non_persistent": "سيتم حذف جميع البيانات غير الدائمة.",
- "resource.delete_volumes": "حذف جميع المجلدات والملفات المرتبطة بهذا المورد بشكل دائم.",
- "resource.delete_connected_networks": "حذف جميع الشبكات غير المحددة مسبقًا والمرتبطة بهذا المورد بشكل دائم.",
- "resource.delete_configurations": "حذف جميع ملفات التعريف من الخادم بشكل دائم.",
- "database.delete_backups_locally": "حذف كافة النسخ الاحتياطية نهائيًا من التخزين المحلي.",
- "warning.sslipdomain": "تم حفظ ملفات التعريف الخاصة بك، ولكن استخدام نطاق sslip مع https غير مستحسن، لأن خوادم Let's Encrypt مع هذا النطاق العام محدودة المعدل (ستفشل عملية التحقق من شهادة SSL). استخدم نطاقك الخاص بدلاً من ذلك."
-}
diff --git a/lang/cs.json b/lang/cs.json
deleted file mode 100644
index 270fd272ba..0000000000
--- a/lang/cs.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "auth.login": "Přihlásit se",
- "auth.login.azure": "Přihlásit se pomocí Microsoftu",
- "auth.login.bitbucket": "Přihlásit se pomocí Bitbucketu",
- "auth.login.github": "Přihlásit se pomocí GitHubu",
- "auth.login.gitlab": "Přihlásit se pomocí Gitlabu",
- "auth.login.google": "Přihlásit se pomocí Google",
- "auth.login.infomaniak": "Přihlásit se pomocí Infomaniak",
- "auth.already_registered": "Již jste registrováni?",
- "auth.confirm_password": "Potvrďte heslo",
- "auth.forgot_password": "Zapomněli jste heslo",
- "auth.forgot_password_send_email": "Poslat e-mail pro resetování hesla",
- "auth.register_now": "Registrovat se",
- "auth.logout": "Odhlásit se",
- "auth.register": "Registrovat se",
- "auth.registration_disabled": "Registrace je zakázána. Kontaktujte prosím administrátora.",
- "auth.reset_password": "Obnovit heslo",
- "auth.failed": "Tyto údaje neodpovídají našim záznamům.",
- "auth.failed.callback": "Nepodařilo se zpracovat zpětné volání od poskytovatele přihlášení.",
- "auth.failed.password": "Zadané heslo je nesprávné.",
- "auth.failed.email": "Nemůžeme najít uživatele s touto e-mailovou adresou.",
- "auth.throttle": "Příliš mnoho pokusů o přihlášení. Zkuste to prosím znovu za :seconds sekund.",
- "input.name": "Jméno",
- "input.email": "E-mail",
- "input.password": "Heslo",
- "input.password.again": "Heslo znovu",
- "input.code": "Jednorázový kód",
- "input.recovery_code": "Obnovovací kód",
- "button.save": "Uložit",
- "repository.url": "Příklady Pro veřejné repozitáře, použijte https://... . Pro soukromé repozitáře, použijte git@... . https://github.com/coollabsio/coolify-examples main branch bude zvolena https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify nodejs-fastify branch bude vybrána. https://gitea.com/sedlav/expressjs.git main branch vybrána. https://gitlab.com/andrasbacsai/nodejs-example.git main branch bude vybrána."
-}
diff --git a/lang/de.json b/lang/de.json
deleted file mode 100644
index c5644e3a7a..0000000000
--- a/lang/de.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "auth.login": "Anmelden",
- "auth.login.azure": "Mit Microsoft anmelden",
- "auth.login.bitbucket": "Mit Bitbucket anmelden",
- "auth.login.github": "Mit GitHub anmelden",
- "auth.login.gitlab": "Mit GitLab anmelden",
- "auth.login.google": "Mit Google anmelden",
- "auth.login.infomaniak": "Mit Infomaniak anmelden",
- "auth.already_registered": "Bereits registriert?",
- "auth.confirm_password": "Passwort bestätigen",
- "auth.forgot_password": "Passwort vergessen",
- "auth.forgot_password_send_email": "Passwort zurücksetzen E-Mail senden",
- "auth.register_now": "Registrieren",
- "auth.logout": "Abmelden",
- "auth.register": "Registrieren",
- "auth.registration_disabled": "Registrierung ist deaktiviert. Bitte kontaktiere einen Administrator.",
- "auth.reset_password": "Passwort zurücksetzen",
- "auth.failed": "Diese Anmeldedaten wurden nicht gefunden.",
- "auth.failed.callback": "Fehlerhafte Verarbeitung der Antwort des Anmeldeanbieters.",
- "auth.failed.password": "Das angegebene Passwort ist inkorrekt.",
- "auth.failed.email": "Wir können keinen Benutzer mit dieser E-Mail Adresse finden.",
- "auth.throttle": "Zu viele Anmeldeversuche. Bitte versuche es in :seconds Sekunden erneut.",
- "input.name": "Name",
- "input.email": "E-Mail",
- "input.password": "Passwort",
- "input.password.again": "Passwort wiederholen",
- "input.code": "Einmalcode",
- "input.recovery_code": "Wiederherstellungscode",
- "button.save": "Speichern",
- "repository.url": "Beispiele Für öffentliche Repositories benutze https://... . Für private Repositories benutze git@... . https://github.com/coollabsio/coolify-examples main Branch wird ausgewählt https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify nodejs-fastify Branch wird ausgewählt. https://gitea.com/sedlav/expressjs.git main Branch wird ausgewählt. https://gitlab.com/andrasbacsai/nodejs-example.git main Branch wird ausgewählt."
-}
diff --git a/lang/en.json b/lang/en.json
deleted file mode 100644
index cdca686013..0000000000
--- a/lang/en.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "auth.login": "Login",
- "auth.login.authentik": "Login with Authentik",
- "auth.login.azure": "Login with Microsoft",
- "auth.login.bitbucket": "Login with Bitbucket",
- "auth.login.github": "Login with GitHub",
- "auth.login.gitlab": "Login with Gitlab",
- "auth.login.google": "Login with Google",
- "auth.login.infomaniak": "Login with Infomaniak",
- "auth.already_registered": "Already registered?",
- "auth.confirm_password": "Confirm password",
- "auth.forgot_password": "Forgot password",
- "auth.forgot_password_send_email": "Send password reset email",
- "auth.register_now": "Register",
- "auth.logout": "Logout",
- "auth.register": "Register",
- "auth.registration_disabled": "Registration is disabled. Please contact the administrator.",
- "auth.reset_password": "Reset password",
- "auth.failed": "These credentials do not match our records.",
- "auth.failed.callback": "Failed to process callback from login provider.",
- "auth.failed.password": "The provided password is incorrect.",
- "auth.failed.email": "We can't find a user with that e-mail address.",
- "auth.throttle": "Too many login attempts. Please try again in :seconds seconds.",
- "input.name": "Name",
- "input.email": "Email",
- "input.password": "Password",
- "input.password.again": "Password again",
- "input.code": "One-time code",
- "input.recovery_code": "Recovery code",
- "button.save": "Save",
- "repository.url": "Examples For Public repositories, use https://... . For Private repositories, use git@... . https://github.com/coollabsio/coolify-examples main branch will be selected https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify nodejs-fastify branch will be selected. https://gitea.com/sedlav/expressjs.git main branch will be selected. https://gitlab.com/andrasbacsai/nodejs-example.git main branch will be selected.",
- "service.stop": "This service will be stopped.",
- "resource.docker_cleanup": "Run Docker Cleanup (remove unused images and builder cache).",
- "resource.non_persistent": "All non-persistent data will be deleted.",
- "resource.delete_volumes": "Permanently delete all volumes associated with this resource.",
- "resource.delete_connected_networks": "Permanently delete all non-predefined networks associated with this resource.",
- "resource.delete_configurations": "Permanently delete all configuration files from the server.",
- "database.delete_backups_locally": "All backups will be permanently deleted from local storage.",
- "warning.sslipdomain": "Your configuration is saved, but sslip domain with https is NOT recommended, because Let's Encrypt servers with this public domain are rate limited (SSL certificate validation will fail). Use your own domain instead."
-}
diff --git a/lang/es.json b/lang/es.json
deleted file mode 100644
index aceacd4625..0000000000
--- a/lang/es.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "auth.login": "Iniciar Sesión",
- "auth.login.azure": "Acceder con Microsoft",
- "auth.login.bitbucket": "Acceder con Bitbucket",
- "auth.login.github": "Acceder con GitHub",
- "auth.login.gitlab": "Acceder con Gitlab",
- "auth.login.google": "Acceder con Google",
- "auth.login.infomaniak": "Acceder con Infomaniak",
- "auth.already_registered": "¿Ya estás registrado?",
- "auth.confirm_password": "Confirmar contraseña",
- "auth.forgot_password": "¿Olvidaste tu contraseña?",
- "auth.forgot_password_send_email": "Enviar correo de recuperación de contraseña",
- "auth.register_now": "Registrar",
- "auth.logout": "Cerrar sesión",
- "auth.register": "Registrar",
- "auth.registration_disabled": "El registro está desactivado. Por favor contacta con el administrador.",
- "auth.reset_password": "Cambiar contraseña",
- "auth.failed": "Las credenciales no coinciden con nuestro registro..",
- "auth.failed.callback": "Falló el proceso de inicio de sesión con el proveedor.",
- "auth.failed.password": "La contraseña es incorrecta.",
- "auth.failed.email": "No encontramos un usuario con ese correo.",
- "auth.throttle": "Demasiados intentos. Por favor inténtalo en :seconds segundos.",
- "input.name": "Nombre",
- "input.email": "Correo",
- "input.password": "Contraseña",
- "input.password.again": "Escribe la contraseña otra vez",
- "input.code": "Código de único uso",
- "input.recovery_code": "Código de recuperación",
- "button.save": "Guardar",
- "repository.url": "Examples Para repositorios públicos, usar https://... . Para repositorios privados, usar git@... . https://github.com/coollabsio/coolify-examples main la rama 'main' será seleccionada. https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify nodejs-fastify la rama 'nodejs-fastify' será seleccionada. https://gitea.com/sedlav/expressjs.git main la rama 'main' será seleccionada. https://gitlab.com/andrasbacsai/nodejs-example.git main la rama 'main' será seleccionada."
-}
diff --git a/lang/fa.json b/lang/fa.json
deleted file mode 100644
index 7a714e6266..0000000000
--- a/lang/fa.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "auth.login": "ورود",
- "auth.login.azure": "ورود با مایکروسافت",
- "auth.login.bitbucket": "ورود با Bitbucket",
- "auth.login.github": "ورود با گیت هاب",
- "auth.login.gitlab": "ورود با گیت لب",
- "auth.login.google": "ورود با گوگل",
- "auth.login.infomaniak": "ورود با Infomaniak",
- "auth.already_registered": "قبلاً ثبت نام کردهاید؟",
- "auth.confirm_password": "تایید رمز عبور",
- "auth.forgot_password": "فراموشی رمز عبور",
- "auth.forgot_password_send_email": "ارسال ایمیل بازیابی رمز عبور",
- "auth.register_now": "ثبت نام",
- "auth.logout": "خروج",
- "auth.register": "ثبت نام",
- "auth.registration_disabled": "ثبت نام غیر فعال است. لطفا با ادمین تماس بگیرید.",
- "auth.reset_password": "بازیابی رمز عبور",
- "auth.failed": "این اطلاعات با سوابق ما مطابقت ندارد.",
- "auth.failed.callback": "پردازش بازگشت از ارائهدهنده ورود با شکست مواجه شد.",
- "auth.failed.password": "رمز عبور ارائه شده نادرست است.",
- "auth.failed.email": "ما نمی توانیم کاربر با آدرس ایمیل مورد نظر را پیدا کنیم.",
- "auth.throttle": "تعداد تلاشهای ورود بیش از حد است. لطفاً در :seconds ثانیه دوباره تلاش کنید.",
- "input.name": "نام",
- "input.email": "ایمیل",
- "input.password": "رمز عبور",
- "input.password.again": "تکرار رمز عبور",
- "input.code": "کد یک بار مصرف",
- "input.recovery_code": "کد بازیابی",
- "button.save": "ذخیره",
- "repository.url": "مثالها برای مخازن عمومی، از https://... استفاده کنید. برای مخازن خصوصی، از git@... استفاده کنید. شاخه main انتخاب خواهد شد. https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify شاخه nodejs-fastify انتخاب خواهد شد. https://gitea.com/sedlav/expressjs.git شاخه main انتخاب خواهد شد. https://gitlab.com/andrasbacsai/nodejs-example.git شاخه main انتخاب خواهد شد."
-}
diff --git a/lang/fr.json b/lang/fr.json
deleted file mode 100644
index 68763d5e00..0000000000
--- a/lang/fr.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "auth.login": "Connexion",
- "auth.login.authentik": "Connexion avec Authentik",
- "auth.login.azure": "Connexion avec Microsoft",
- "auth.login.bitbucket": "Connexion avec Bitbucket",
- "auth.login.github": "Connexion avec GitHub",
- "auth.login.gitlab": "Connexion avec Gitlab",
- "auth.login.google": "Connexion avec Google",
- "auth.login.infomaniak": "Connexion avec Infomaniak",
- "auth.already_registered": "Déjà enregistré ?",
- "auth.confirm_password": "Confirmer le mot de passe",
- "auth.forgot_password": "Mot de passe oublié",
- "auth.forgot_password_send_email": "Envoyer l'email de réinitialisation de mot de passe",
- "auth.register_now": "S'enregistrer",
- "auth.logout": "Déconnexion",
- "auth.register": "S'enregistrer",
- "auth.registration_disabled": "L'enregistrement est désactivé. Merci de contacter l'administrateur.",
- "auth.reset_password": "Réinitialiser le mot de passe",
- "auth.failed": "Aucune correspondance n'a été trouvée pour les informations d'identification renseignées.",
- "auth.failed.callback": "Erreur lors du processus de retour de la plateforme de connexion.",
- "auth.failed.password": "Le mot de passe renseigné est incorrect.",
- "auth.failed.email": "Aucun utilisateur avec cette adresse email n'a été trouvé.",
- "auth.throttle": "Trop de tentatives de connexion. Merci de réessayer dans :seconds secondes.",
- "input.name": "Nom",
- "input.email": "Email",
- "input.password": "Mot de passe",
- "input.password.again": "Mot de passe identique",
- "input.code": "Code à usage unique",
- "input.recovery_code": "Code de récupération",
- "button.save": "Sauvegarder",
- "repository.url": "Exemples Pour les dépôts publiques, utilisez https://... . Pour les dépôts privés, utilisez git@... . https://github.com/coollabsio/coolify-examples main sera la branche selectionnée https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify nodejs-fastify sera la branche selectionnée. https://gitea.com/sedlav/expressjs.git main sera la branche selectionnée. https://gitlab.com/andrasbacsai/nodejs-example.git main sera la branche selectionnée.",
- "service.stop": "Ce service sera arrêté.",
- "resource.docker_cleanup": "Exécuter le nettoyage Docker (supprimer les images inutilisées et le cache du builder).",
- "resource.non_persistent": "Toutes les données non persistantes seront supprimées.",
- "resource.delete_volumes": "Supprimer définitivement tous les volumes associés à cette ressource.",
- "resource.delete_connected_networks": "Supprimer définitivement tous les réseaux non-prédéfinis associés à cette ressource.",
- "resource.delete_configurations": "Supprimer définitivement tous les fichiers de configuration du serveur.",
- "database.delete_backups_locally": "Toutes les sauvegardes seront définitivement supprimées du stockage local.",
- "warning.sslipdomain": "Votre configuration est enregistrée, mais l'utilisation du domaine sslip avec https N'EST PAS recommandée, car les serveurs Let's Encrypt avec ce domaine public sont limités en taux (la validation du certificat SSL échouera). Utilisez plutôt votre propre domaine."
-}
diff --git a/lang/it.json b/lang/it.json
deleted file mode 100644
index 1923251a5e..0000000000
--- a/lang/it.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "auth.login": "Accedi",
- "auth.login.authentik": "Accedi con Authentik",
- "auth.login.azure": "Accedi con Microsoft",
- "auth.login.bitbucket": "Accedi con Bitbucket",
- "auth.login.github": "Accedi con GitHub",
- "auth.login.gitlab": "Accedi con Gitlab",
- "auth.login.google": "Accedi con Google",
- "auth.login.infomaniak": "Accedi con Infomaniak",
- "auth.already_registered": "Già registrato?",
- "auth.confirm_password": "Conferma password",
- "auth.forgot_password": "Password dimenticata",
- "auth.forgot_password_send_email": "Invia email per reimpostare la password",
- "auth.register_now": "Registrati",
- "auth.logout": "Esci",
- "auth.register": "Registrati",
- "auth.registration_disabled": "La registrazione è disabilitata. Si prega di contattare l'amministratore.",
- "auth.reset_password": "Reimposta password",
- "auth.failed": "Queste credenziali non corrispondono ai nostri record.",
- "auth.failed.callback": "Errore durante l'elaborazione del callback dal provider di accesso.",
- "auth.failed.password": "La password fornita non è corretta.",
- "auth.failed.email": "Non possiamo trovare un utente con questo indirizzo email.",
- "auth.throttle": "Troppi tentativi di accesso. Per favore riprova tra :seconds secondi.",
- "input.name": "Nome",
- "input.email": "Email",
- "input.password": "Password",
- "input.password.again": "Ripeti password",
- "input.code": "Codice monouso",
- "input.recovery_code": "Codice di recupero",
- "button.save": "Salva",
- "repository.url": "Esempi Per i repository pubblici, utilizza https://... . Per i repository privati, utilizza git@... . https://github.com/coollabsio/coolify-examples verrà selezionato il branch main https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify verrà selezionato il branch nodejs-fastify . https://gitea.com/sedlav/expressjs.git verrà selezionato il branch main . https://gitlab.com/andrasbacsai/nodejs-example.git verrà selezionato il branch main .",
- "service.stop": "Questo servizio verrà arrestato.",
- "resource.docker_cleanup": "Esegui pulizia Docker (rimuove immagini non utilizzate e cache del builder).",
- "resource.non_persistent": "Tutti i dati non persistenti verranno eliminati.",
- "resource.delete_volumes": "Elimina definitivamente tutti i volumi associati a questa risorsa.",
- "resource.delete_connected_networks": "Elimina definitivamente tutte le reti non predefinite associate a questa risorsa.",
- "resource.delete_configurations": "Elimina definitivamente tutti i file di configurazione dal server.",
- "database.delete_backups_locally": "Tutti i backup verranno eliminati definitivamente dall'archiviazione locale.",
- "warning.sslipdomain": "La tua configurazione è stata salvata, ma il dominio sslip con https NON è raccomandato, poiché i server di Let's Encrypt con questo dominio pubblico hanno limitazioni di frequenza (la convalida del certificato SSL fallirà). Utilizza invece il tuo dominio personale."
-}
diff --git a/lang/ja.json b/lang/ja.json
deleted file mode 100644
index 4d45899001..0000000000
--- a/lang/ja.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "auth.login": "ログイン",
- "auth.login.azure": "Microsoftでログイン",
- "auth.login.bitbucket": "Bitbucketでログイン",
- "auth.login.github": "GitHubでログイン",
- "auth.login.gitlab": "Gitlabでログイン",
- "auth.login.google": "Googleでログイン",
- "auth.login.infomaniak": "Infomaniakでログイン",
- "auth.already_registered": "すでに登録済みですか?",
- "auth.confirm_password": "パスワードを確認",
- "auth.forgot_password": "パスワードを忘れた",
- "auth.forgot_password_send_email": "パスワードリセットメールを送信",
- "auth.register_now": "今すぐ登録",
- "auth.logout": "ログアウト",
- "auth.register": "登録",
- "auth.registration_disabled": "登録は無効です。管理者に連絡してください。",
- "auth.reset_password": "パスワードをリセット",
- "auth.failed": "これらの資格情報は記録と一致しません。",
- "auth.failed.callback": "ログインプロバイダーからのコールバックの処理に失敗しました。",
- "auth.failed.password": "提供されたパスワードが正しくありません。",
- "auth.failed.email": "そのメールアドレスのユーザーが見つかりません。",
- "auth.throttle": "ログイン試行回数が多すぎます。:seconds秒後にもう一度お試しください。",
- "input.name": "名前",
- "input.email": "メール",
- "input.password": "パスワード",
- "input.password.again": "パスワード再入力",
- "input.code": "ワンタイムコード",
- "input.recovery_code": "リカバリーコード",
- "button.save": "保存",
- "repository.url": "例 公開リポジトリの場合はhttps://... を使用してください。 プライベートリポジトリの場合はgit@... を使用してください。 https://github.com/coollabsio/coolify-examples main ブランチが選択されます https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify nodejs-fastify ブランチが選択されます。 https://gitea.com/sedlav/expressjs.git main ブランチが選択されます。 https://gitlab.com/andrasbacsai/nodejs-example.git main ブランチが選択されます。"
-}
diff --git a/lang/pt.json b/lang/pt.json
deleted file mode 100644
index c5f393e65c..0000000000
--- a/lang/pt.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "auth.login": "Entrar",
- "auth.login.azure": "Entrar com Microsoft",
- "auth.login.bitbucket": "Entrar com Bitbucket",
- "auth.login.github": "Entrar com GitHub",
- "auth.login.gitlab": "Entrar com Gitlab",
- "auth.login.google": "Entrar com Google",
- "auth.login.infomaniak": "Entrar com Infomaniak",
- "auth.already_registered": "Já tem uma conta?",
- "auth.confirm_password": "Confirmar senha",
- "auth.forgot_password": "Esqueceu a senha?",
- "auth.forgot_password_send_email": "Enviar e-mail de redefinição de senha",
- "auth.register_now": "Cadastrar-se",
- "auth.logout": "Sair",
- "auth.register": "Cadastrar",
- "auth.registration_disabled": "Cadastro desativado. Por favor, entre em contato com o administrador.",
- "auth.reset_password": "Redefinir senha",
- "auth.failed": "Essas credenciais não correspondem aos nossos registros.",
- "auth.failed.callback": "Falha ao processar o callback do provedor de login.",
- "auth.failed.password": "A senha fornecida está incorreta.",
- "auth.failed.email": "Não encontramos um usuário com esse endereço de e-mail.",
- "auth.throttle": "Muitas tentativas de login. Por favor, tente novamente em :seconds segundos.",
- "input.name": "Nome",
- "input.email": "E-mail",
- "input.password": "Senha",
- "input.password.again": "Repetir senha",
- "input.code": "Código único",
- "input.recovery_code": "Código de recuperação",
- "button.save": "Salvar",
- "repository.url": "Exemplos Para repositórios públicos, use https://... . Para repositórios privados, use git@... . https://github.com/coollabsio/coolify-examples a branch main será selecionada https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify a branch nodejs-fastify será selecionada. https://gitea.com/sedlav/expressjs.git a branch main será selecionada. https://gitlab.com/andrasbacsai/nodejs-example.git a branch main será selecionada."
-}
diff --git a/lang/ro.json b/lang/ro.json
deleted file mode 100644
index 4c7968cfa2..0000000000
--- a/lang/ro.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "auth.login": "Autentificare",
- "auth.login.azure": "Autentificare prin Microsoft",
- "auth.login.bitbucket": "Autentificare prin Bitbucket",
- "auth.login.github": "Autentificare prin GitHub",
- "auth.login.gitlab": "Autentificare prin Gitlab",
- "auth.login.google": "Autentificare prin Google",
- "auth.login.infomaniak": "Autentificare prin Infomaniak",
- "auth.already_registered": "Sunteți deja înregistrat?",
- "auth.confirm_password": "Confirmați parola",
- "auth.forgot_password": "Ați uitat parola",
- "auth.forgot_password_send_email": "Trimiteți e-mail-ul pentru resetarea parolei",
- "auth.register_now": "Înregistrare",
- "auth.logout": "Deconectare",
- "auth.register": "Înregistrare",
- "auth.registration_disabled": "Înregistrarea este dezactivată. Vă rugăm să contactați administratorul site-ului.",
- "auth.reset_password": "Resetare parolă",
- "auth.failed": "Autentificare nereușită. Vă rugăm să verificați datele introduse.",
- "auth.failed.callback": "A apărut o eroare în timpul autentificării cu furnizorul extern.",
- "auth.failed.password": "Parola furnizată este incorectă.",
- "auth.failed.email": "Nu putem găsi un utilizator cu această adresă de e-mail.",
- "auth.throttle": "Prea multe încercări de autentificare. Vă rugăm să încercați din nou în :seconds secunde.",
- "input.name": "Nume",
- "input.email": "E-mail",
- "input.password": "Parolă",
- "input.password.again": "Repetați parola",
- "input.code": "Cod de unică folosință",
- "input.recovery_code": "Cod de recuperare",
- "button.save": "Salvare",
- "repository.url": "Exemple Pentru depozite publice, utilizați https://... . Pentru depozite private, utilizați git@... . https://github.com/coollabsio/coolify-examples va fi selectată ramura main https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify va fi selectată ramura nodejs-fastify . https://gitea.com/sedlav/expressjs.git va fi selectată ramura main . https://gitlab.com/andrasbacsai/nodejs-example.git va fi selectată ramura main .",
- "service.stop": "Acest serviciu va fi oprit.",
- "resource.docker_cleanup": "Executați curățarea Docker (eliminați imaginile neutilizate și memoria cache a constructorului).",
- "resource.non_persistent": "Toate datele nepersistente vor fi șterse.",
- "resource.delete_volumes": "Ștergeți definitiv toate volumele asociate cu această resursă.",
- "resource.delete_connected_networks": "Ștergeți definitiv toate rețelele non-predefinite asociate cu această resursă.",
- "resource.delete_configurations": "Ștergeți definitiv toate fișierele de configurare de pe server.",
- "database.delete_backups_locally": "Toate copiile de rezervă vor fi șterse definitiv din stocarea locală."
-}
diff --git a/lang/tr.json b/lang/tr.json
deleted file mode 100644
index 3cbcee4098..0000000000
--- a/lang/tr.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "auth.login": "Giriş",
- "auth.login.azure": "Microsoft ile Giriş Yap",
- "auth.login.bitbucket": "Bitbucket ile Giriş Yap",
- "auth.login.github": "GitHub ile Giriş Yap",
- "auth.login.gitlab": "GitLab ile Giriş Yap",
- "auth.login.google": "Google ile Giriş Yap",
- "auth.login.infomaniak": "Infomaniak ile Giriş Yap",
- "auth.already_registered": "Zaten kayıtlı mısınız?",
- "auth.confirm_password": "Şifreyi Onayla",
- "auth.forgot_password": "Şifremi Unuttum",
- "auth.forgot_password_send_email": "Şifre sıfırlama e-postası gönder",
- "auth.register_now": "Kayıt Ol",
- "auth.logout": "Çıkış Yap",
- "auth.register": "Kayıt Ol",
- "auth.registration_disabled": "Kayıt devre dışı bırakıldı. Lütfen yöneticiyle iletişime geçin.",
- "auth.reset_password": "Şifreyi Sıfırla",
- "auth.failed": "Bu kimlik bilgileri kayıtlarımızla eşleşmiyor.",
- "auth.failed.callback": "Giriş sağlayıcıdan gelen istek işlenemedi.",
- "auth.failed.password": "Sağlanan şifre yanlış.",
- "auth.failed.email": "Bu e-posta adresiyle bir kullanıcı bulamıyoruz.",
- "auth.throttle": "Çok fazla giriş denemesi. Lütfen :seconds saniye sonra tekrar deneyin.",
- "input.name": "İsim",
- "input.email": "E-posta",
- "input.password": "Şifre",
- "input.password.again": "Şifreyi Tekrar Girin",
- "input.code": "Tek Kullanımlık Kod",
- "input.recovery_code": "Kurtarma Kodu",
- "button.save": "Kaydet",
- "repository.url": "Örnekler Halka açık depolar için https://... kullanın. Özel depolar için git@... kullanın. https://github.com/coollabsio/coolify-examples main dalı seçilecek https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify nodejs-fastify dalı seçilecek. https://gitea.com/sedlav/expressjs.git main dalı seçilecek. https://gitlab.com/andrasbacsai/nodejs-example.git main dalı seçilecek."
-}
diff --git a/lang/vi.json b/lang/vi.json
deleted file mode 100644
index bb43fd34d4..0000000000
--- a/lang/vi.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "auth.login": "Đăng Nhập",
- "auth.login.azure": "Đăng Nhập Bằng Microsoft",
- "auth.login.bitbucket": "Đăng Nhập Bằng Bitbucket",
- "auth.login.github": "Đăng Nhập Bằng GitHub",
- "auth.login.gitlab": "Đăng Nhập Bằng Gitlab",
- "auth.login.google": "Đăng Nhập Bằng Google",
- "auth.login.infomaniak": "Đăng Nhập Bằng Infomaniak",
- "auth.already_registered": "Đã đăng ký?",
- "auth.confirm_password": "Nhập lại mật khẩu",
- "auth.forgot_password": "Quên mật khẩu",
- "auth.forgot_password_send_email": "Gửi email đặt lại mật khẩu",
- "auth.register_now": "Đăng ký ngay",
- "auth.logout": "Đăng xuất",
- "auth.register": "Đăng ký",
- "auth.registration_disabled": "Đăng ký không khả dụng. Vui lòng liên hệ quản trị viên.",
- "auth.reset_password": "Đặt lại mật khẩu",
- "auth.failed": "Thông tin đăng nhập không khớp với bất kỳ tài khoản nào.",
- "auth.failed.callback": "Xử lý thông tin từ nhà cung cấp đăng nhập thất bại.",
- "auth.failed.password": "Mật khẩu bạn cung cấp không chính xác.",
- "auth.failed.email": "Không có người dùng nào đã đăng ký với email đó.",
- "auth.throttle": "Quá nhiều lần đăng nhập thất bại. Vui lòng thử lại sau :seconds giây.",
- "input.name": "Tên",
- "input.email": "Email",
- "input.password": "Mật khẩu",
- "input.password.again": "Mật khẩu lần nữa",
- "input.code": "One-time code",
- "input.recovery_code": "Mã khôi phục",
- "button.save": "Lưu",
- "repository.url": "Ví dụ Với repo công khai, sử dụng https://... . Với repo riêng tư, sử dụng git@... . https://github.com/coollabsio/coolify-examples nhánh chính sẽ được chọn https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify nhánh nodejs-fastify sẽ được chọn. https://gitea.com/sedlav/expressjs.git nhánh chính sẽ được chọn. https://gitlab.com/andrasbacsai/nodejs-example.git nhánh chính sẽ được chọn."
-}
diff --git a/lang/zh-cn.json b/lang/zh-cn.json
deleted file mode 100644
index 944887a5fc..0000000000
--- a/lang/zh-cn.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "auth.login": "登录",
- "auth.login.azure": "使用 Microsoft 登录",
- "auth.login.bitbucket": "使用 Bitbucket 登录",
- "auth.login.github": "使用 GitHub 登录",
- "auth.login.gitlab": "使用 Gitlab 登录",
- "auth.login.google": "使用 Google 登录",
- "auth.login.infomaniak": "使用 Infomaniak 登录",
- "auth.already_registered": "已经注册?",
- "auth.confirm_password": "确认密码",
- "auth.forgot_password": "忘记密码",
- "auth.forgot_password_send_email": "发送密码重置邮件",
- "auth.register_now": "注册",
- "auth.logout": "退出登录",
- "auth.register": "注册",
- "auth.registration_disabled": "注册已禁用,请联系管理员",
- "auth.reset_password": "重置密码",
- "auth.failed": "这些凭据与我们的记录不符",
- "auth.failed.callback": "处理第三方登录的回调时出错",
- "auth.failed.password": "密码错误",
- "auth.failed.email": "该账户未注册",
- "auth.throttle": "登录次数过多,请在 :seconds 秒后重试",
- "input.name": "用户名",
- "input.email": "邮箱",
- "input.password": "密码",
- "input.password.again": "确认密码",
- "input.code": "验证码",
- "input.recovery_code": "恢复码",
- "button.save": "保存",
- "repository.url": "示例 对于公共代码仓库,请使用 https://... 。 对于私有代码仓库,请使用 git@... 。 https://github.com/coollabsio/coolify-examples main 分支将被选择 https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify nodejs-fastify 分支将被选择。 https://gitea.com/sedlav/expressjs.git main 分支将被选择。 https://gitlab.com/andrasbacsai/nodejs-example.git main 分支将被选择"
-}
diff --git a/lang/zh-tw.json b/lang/zh-tw.json
deleted file mode 100644
index c42ebb33e3..0000000000
--- a/lang/zh-tw.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "auth.login": "登入",
- "auth.login.azure": "使用 Microsoft 登入",
- "auth.login.bitbucket": "使用 Bitbucket 登入",
- "auth.login.github": "使用 GitHub 登入",
- "auth.login.gitlab": "使用 Gitlab 登入",
- "auth.login.google": "使用 Google 登入",
- "auth.login.infomaniak": "使用 Infomaniak 登入",
- "auth.already_registered": "已經註冊?",
- "auth.confirm_password": "確認密碼",
- "auth.forgot_password": "忘記密碼",
- "auth.forgot_password_send_email": "發送重設密碼電郵",
- "auth.register_now": "註冊",
- "auth.logout": "登出",
- "auth.register": "註冊",
- "auth.registration_disabled": "註冊已停用,請聯絡管理員。",
- "auth.reset_password": "重設密碼",
- "auth.failed": "這些憑證與我們的記錄不符。",
- "auth.failed.callback": "無法處理來自登入提供者的回呼。",
- "auth.failed.password": "密碼錯誤。",
- "auth.failed.email": "找不到該電子郵件地址的使用者。",
- "auth.throttle": "登入嘗試次數太多。請在 :seconds 秒後重試。",
- "input.name": "名稱",
- "input.email": "電子郵件",
- "input.password": "密碼",
- "input.password.again": "再次輸入密碼",
- "input.code": "一次性代碼",
- "input.recovery_code": "恢復碼",
- "button.save": "儲存",
- "repository.url": "例子 對於公共代碼倉庫,請使用 https://... 。 對於私有代碼倉庫,請使用 git@... 。 https://github.com/coollabsio/coolify-examples main 分支將被選擇 https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify nodejs-fastify 分支將被選擇。 https://gitea.com/sedlav/expressjs.git main 分支將被選擇。 https://gitlab.com/andrasbacsai/nodejs-example.git main 分支將被選擇。"
-}
diff --git a/openapi.json b/openapi.json
deleted file mode 100644
index 819f229cce..0000000000
--- a/openapi.json
+++ /dev/null
@@ -1,7988 +0,0 @@
-{
- "openapi": "3.1.0",
- "info": {
- "title": "Coolify",
- "version": "0.1"
- },
- "servers": [
- {
- "url": "https:\/\/app.coolify.io\/api\/v1",
- "description": "Coolify Cloud API. Change the host to your own instance if you are self-hosting."
- }
- ],
- "paths": {
- "\/applications": {
- "get": {
- "tags": [
- "Applications"
- ],
- "summary": "List",
- "description": "List all applications.",
- "operationId": "list-applications",
- "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\/public": {
- "post": {
- "tags": [
- "Applications"
- ],
- "summary": "Create (Public)",
- "description": "Create new application based on a public git repository.",
- "operationId": "create-public-application",
- "requestBody": {
- "description": "Application object that needs to be created.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "project_uuid",
- "server_uuid",
- "environment_name",
- "environment_uuid",
- "git_repository",
- "git_branch",
- "build_pack",
- "ports_exposes"
- ],
- "properties": {
- "project_uuid": {
- "type": "string",
- "description": "The project UUID."
- },
- "server_uuid": {
- "type": "string",
- "description": "The server UUID."
- },
- "environment_name": {
- "type": "string",
- "description": "The environment name. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "The environment UUID. You need to provide at least one of environment_name or environment_uuid."
- },
- "git_repository": {
- "type": "string",
- "description": "The git repository URL."
- },
- "git_branch": {
- "type": "string",
- "description": "The git branch."
- },
- "build_pack": {
- "type": "string",
- "enum": [
- "nixpacks",
- "static",
- "dockerfile",
- "dockercompose"
- ],
- "description": "The build pack type."
- },
- "ports_exposes": {
- "type": "string",
- "description": "The ports to expose."
- },
- "destination_uuid": {
- "type": "string",
- "description": "The destination UUID."
- },
- "name": {
- "type": "string",
- "description": "The application name."
- },
- "description": {
- "type": "string",
- "description": "The application description."
- },
- "domains": {
- "type": "string",
- "description": "The application domains."
- },
- "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_tag": {
- "type": "string",
- "description": "The docker registry image tag."
- },
- "is_static": {
- "type": "boolean",
- "description": "The flag to indicate if the application is static."
- },
- "static_image": {
- "type": "string",
- "enum": [
- "nginx:alpine"
- ],
- "description": "The static image."
- },
- "install_command": {
- "type": "string",
- "description": "The install command."
- },
- "build_command": {
- "type": "string",
- "description": "The build command."
- },
- "start_command": {
- "type": "string",
- "description": "The start command."
- },
- "ports_mappings": {
- "type": "string",
- "description": "The ports mappings."
- },
- "base_directory": {
- "type": "string",
- "description": "The base directory for all commands."
- },
- "publish_directory": {
- "type": "string",
- "description": "The publish directory."
- },
- "health_check_enabled": {
- "type": "boolean",
- "description": "Health check enabled."
- },
- "health_check_path": {
- "type": "string",
- "description": "Health check path."
- },
- "health_check_port": {
- "type": "string",
- "nullable": true,
- "description": "Health check port."
- },
- "health_check_host": {
- "type": "string",
- "nullable": true,
- "description": "Health check host."
- },
- "health_check_method": {
- "type": "string",
- "description": "Health check method."
- },
- "health_check_return_code": {
- "type": "integer",
- "description": "Health check return code."
- },
- "health_check_scheme": {
- "type": "string",
- "description": "Health check scheme."
- },
- "health_check_response_text": {
- "type": "string",
- "nullable": true,
- "description": "Health check response text."
- },
- "health_check_interval": {
- "type": "integer",
- "description": "Health check interval in seconds."
- },
- "health_check_timeout": {
- "type": "integer",
- "description": "Health check timeout in seconds."
- },
- "health_check_retries": {
- "type": "integer",
- "description": "Health check retries count."
- },
- "health_check_start_period": {
- "type": "integer",
- "description": "Health check start period in seconds."
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit."
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit."
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness."
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation."
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit."
- },
- "limits_cpuset": {
- "type": "string",
- "nullable": true,
- "description": "CPU set."
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares."
- },
- "custom_labels": {
- "type": "string",
- "description": "Custom labels."
- },
- "custom_docker_run_options": {
- "type": "string",
- "description": "Custom docker run options."
- },
- "post_deployment_command": {
- "type": "string",
- "description": "Post deployment command."
- },
- "post_deployment_command_container": {
- "type": "string",
- "description": "Post deployment command container."
- },
- "pre_deployment_command": {
- "type": "string",
- "description": "Pre deployment command."
- },
- "pre_deployment_command_container": {
- "type": "string",
- "description": "Pre deployment command container."
- },
- "manual_webhook_secret_github": {
- "type": "string",
- "description": "Manual webhook secret for Github."
- },
- "manual_webhook_secret_gitlab": {
- "type": "string",
- "description": "Manual webhook secret for Gitlab."
- },
- "manual_webhook_secret_bitbucket": {
- "type": "string",
- "description": "Manual webhook secret for Bitbucket."
- },
- "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"
- ]
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "The flag to indicate if the application should be deployed instantly."
- },
- "dockerfile": {
- "type": "string",
- "description": "The Dockerfile content."
- },
- "docker_compose_location": {
- "type": "string",
- "description": "The Docker Compose location."
- },
- "docker_compose_raw": {
- "type": "string",
- "description": "The Docker Compose raw content."
- },
- "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_domains": {
- "type": "array",
- "description": "The Docker Compose domains."
- },
- "watch_paths": {
- "type": "string",
- "description": "The watch paths."
- },
- "use_build_server": {
- "type": "boolean",
- "nullable": true,
- "description": "Use build server."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Application created successfully.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/private-github-app": {
- "post": {
- "tags": [
- "Applications"
- ],
- "summary": "Create (Private - GH App)",
- "description": "Create new application based on a private repository through a Github App.",
- "operationId": "create-private-github-app-application",
- "requestBody": {
- "description": "Application object that needs to be created.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "project_uuid",
- "server_uuid",
- "environment_name",
- "environment_uuid",
- "github_app_uuid",
- "git_repository",
- "git_branch",
- "build_pack",
- "ports_exposes"
- ],
- "properties": {
- "project_uuid": {
- "type": "string",
- "description": "The project UUID."
- },
- "server_uuid": {
- "type": "string",
- "description": "The server UUID."
- },
- "environment_name": {
- "type": "string",
- "description": "The environment name. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "The environment UUID. You need to provide at least one of environment_name or environment_uuid."
- },
- "github_app_uuid": {
- "type": "string",
- "description": "The Github App UUID."
- },
- "git_repository": {
- "type": "string",
- "description": "The git repository URL."
- },
- "git_branch": {
- "type": "string",
- "description": "The git branch."
- },
- "ports_exposes": {
- "type": "string",
- "description": "The ports to expose."
- },
- "destination_uuid": {
- "type": "string",
- "description": "The destination UUID."
- },
- "build_pack": {
- "type": "string",
- "enum": [
- "nixpacks",
- "static",
- "dockerfile",
- "dockercompose"
- ],
- "description": "The build pack type."
- },
- "name": {
- "type": "string",
- "description": "The application name."
- },
- "description": {
- "type": "string",
- "description": "The application description."
- },
- "domains": {
- "type": "string",
- "description": "The application domains."
- },
- "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_tag": {
- "type": "string",
- "description": "The docker registry image tag."
- },
- "is_static": {
- "type": "boolean",
- "description": "The flag to indicate if the application is static."
- },
- "static_image": {
- "type": "string",
- "enum": [
- "nginx:alpine"
- ],
- "description": "The static image."
- },
- "install_command": {
- "type": "string",
- "description": "The install command."
- },
- "build_command": {
- "type": "string",
- "description": "The build command."
- },
- "start_command": {
- "type": "string",
- "description": "The start command."
- },
- "ports_mappings": {
- "type": "string",
- "description": "The ports mappings."
- },
- "base_directory": {
- "type": "string",
- "description": "The base directory for all commands."
- },
- "publish_directory": {
- "type": "string",
- "description": "The publish directory."
- },
- "health_check_enabled": {
- "type": "boolean",
- "description": "Health check enabled."
- },
- "health_check_path": {
- "type": "string",
- "description": "Health check path."
- },
- "health_check_port": {
- "type": "string",
- "nullable": true,
- "description": "Health check port."
- },
- "health_check_host": {
- "type": "string",
- "nullable": true,
- "description": "Health check host."
- },
- "health_check_method": {
- "type": "string",
- "description": "Health check method."
- },
- "health_check_return_code": {
- "type": "integer",
- "description": "Health check return code."
- },
- "health_check_scheme": {
- "type": "string",
- "description": "Health check scheme."
- },
- "health_check_response_text": {
- "type": "string",
- "nullable": true,
- "description": "Health check response text."
- },
- "health_check_interval": {
- "type": "integer",
- "description": "Health check interval in seconds."
- },
- "health_check_timeout": {
- "type": "integer",
- "description": "Health check timeout in seconds."
- },
- "health_check_retries": {
- "type": "integer",
- "description": "Health check retries count."
- },
- "health_check_start_period": {
- "type": "integer",
- "description": "Health check start period in seconds."
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit."
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit."
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness."
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation."
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit."
- },
- "limits_cpuset": {
- "type": "string",
- "nullable": true,
- "description": "CPU set."
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares."
- },
- "custom_labels": {
- "type": "string",
- "description": "Custom labels."
- },
- "custom_docker_run_options": {
- "type": "string",
- "description": "Custom docker run options."
- },
- "post_deployment_command": {
- "type": "string",
- "description": "Post deployment command."
- },
- "post_deployment_command_container": {
- "type": "string",
- "description": "Post deployment command container."
- },
- "pre_deployment_command": {
- "type": "string",
- "description": "Pre deployment command."
- },
- "pre_deployment_command_container": {
- "type": "string",
- "description": "Pre deployment command container."
- },
- "manual_webhook_secret_github": {
- "type": "string",
- "description": "Manual webhook secret for Github."
- },
- "manual_webhook_secret_gitlab": {
- "type": "string",
- "description": "Manual webhook secret for Gitlab."
- },
- "manual_webhook_secret_bitbucket": {
- "type": "string",
- "description": "Manual webhook secret for Bitbucket."
- },
- "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"
- ]
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "The flag to indicate if the application should be deployed instantly."
- },
- "dockerfile": {
- "type": "string",
- "description": "The Dockerfile content."
- },
- "docker_compose_location": {
- "type": "string",
- "description": "The Docker Compose location."
- },
- "docker_compose_raw": {
- "type": "string",
- "description": "The Docker Compose raw content."
- },
- "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_domains": {
- "type": "array",
- "description": "The Docker Compose domains."
- },
- "watch_paths": {
- "type": "string",
- "description": "The watch paths."
- },
- "use_build_server": {
- "type": "boolean",
- "nullable": true,
- "description": "Use build server."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Application created successfully.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/private-deploy-key": {
- "post": {
- "tags": [
- "Applications"
- ],
- "summary": "Create (Private - Deploy Key)",
- "description": "Create new application based on a private repository through a Deploy Key.",
- "operationId": "create-private-deploy-key-application",
- "requestBody": {
- "description": "Application object that needs to be created.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "project_uuid",
- "server_uuid",
- "environment_name",
- "environment_uuid",
- "private_key_uuid",
- "git_repository",
- "git_branch",
- "build_pack",
- "ports_exposes"
- ],
- "properties": {
- "project_uuid": {
- "type": "string",
- "description": "The project UUID."
- },
- "server_uuid": {
- "type": "string",
- "description": "The server UUID."
- },
- "environment_name": {
- "type": "string",
- "description": "The environment name. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "The environment UUID. You need to provide at least one of environment_name or environment_uuid."
- },
- "private_key_uuid": {
- "type": "string",
- "description": "The private key UUID."
- },
- "git_repository": {
- "type": "string",
- "description": "The git repository URL."
- },
- "git_branch": {
- "type": "string",
- "description": "The git branch."
- },
- "ports_exposes": {
- "type": "string",
- "description": "The ports to expose."
- },
- "destination_uuid": {
- "type": "string",
- "description": "The destination UUID."
- },
- "build_pack": {
- "type": "string",
- "enum": [
- "nixpacks",
- "static",
- "dockerfile",
- "dockercompose"
- ],
- "description": "The build pack type."
- },
- "name": {
- "type": "string",
- "description": "The application name."
- },
- "description": {
- "type": "string",
- "description": "The application description."
- },
- "domains": {
- "type": "string",
- "description": "The application domains."
- },
- "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_tag": {
- "type": "string",
- "description": "The docker registry image tag."
- },
- "is_static": {
- "type": "boolean",
- "description": "The flag to indicate if the application is static."
- },
- "static_image": {
- "type": "string",
- "enum": [
- "nginx:alpine"
- ],
- "description": "The static image."
- },
- "install_command": {
- "type": "string",
- "description": "The install command."
- },
- "build_command": {
- "type": "string",
- "description": "The build command."
- },
- "start_command": {
- "type": "string",
- "description": "The start command."
- },
- "ports_mappings": {
- "type": "string",
- "description": "The ports mappings."
- },
- "base_directory": {
- "type": "string",
- "description": "The base directory for all commands."
- },
- "publish_directory": {
- "type": "string",
- "description": "The publish directory."
- },
- "health_check_enabled": {
- "type": "boolean",
- "description": "Health check enabled."
- },
- "health_check_path": {
- "type": "string",
- "description": "Health check path."
- },
- "health_check_port": {
- "type": "string",
- "nullable": true,
- "description": "Health check port."
- },
- "health_check_host": {
- "type": "string",
- "nullable": true,
- "description": "Health check host."
- },
- "health_check_method": {
- "type": "string",
- "description": "Health check method."
- },
- "health_check_return_code": {
- "type": "integer",
- "description": "Health check return code."
- },
- "health_check_scheme": {
- "type": "string",
- "description": "Health check scheme."
- },
- "health_check_response_text": {
- "type": "string",
- "nullable": true,
- "description": "Health check response text."
- },
- "health_check_interval": {
- "type": "integer",
- "description": "Health check interval in seconds."
- },
- "health_check_timeout": {
- "type": "integer",
- "description": "Health check timeout in seconds."
- },
- "health_check_retries": {
- "type": "integer",
- "description": "Health check retries count."
- },
- "health_check_start_period": {
- "type": "integer",
- "description": "Health check start period in seconds."
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit."
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit."
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness."
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation."
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit."
- },
- "limits_cpuset": {
- "type": "string",
- "nullable": true,
- "description": "CPU set."
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares."
- },
- "custom_labels": {
- "type": "string",
- "description": "Custom labels."
- },
- "custom_docker_run_options": {
- "type": "string",
- "description": "Custom docker run options."
- },
- "post_deployment_command": {
- "type": "string",
- "description": "Post deployment command."
- },
- "post_deployment_command_container": {
- "type": "string",
- "description": "Post deployment command container."
- },
- "pre_deployment_command": {
- "type": "string",
- "description": "Pre deployment command."
- },
- "pre_deployment_command_container": {
- "type": "string",
- "description": "Pre deployment command container."
- },
- "manual_webhook_secret_github": {
- "type": "string",
- "description": "Manual webhook secret for Github."
- },
- "manual_webhook_secret_gitlab": {
- "type": "string",
- "description": "Manual webhook secret for Gitlab."
- },
- "manual_webhook_secret_bitbucket": {
- "type": "string",
- "description": "Manual webhook secret for Bitbucket."
- },
- "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"
- ]
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "The flag to indicate if the application should be deployed instantly."
- },
- "dockerfile": {
- "type": "string",
- "description": "The Dockerfile content."
- },
- "docker_compose_location": {
- "type": "string",
- "description": "The Docker Compose location."
- },
- "docker_compose_raw": {
- "type": "string",
- "description": "The Docker Compose raw content."
- },
- "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_domains": {
- "type": "array",
- "description": "The Docker Compose domains."
- },
- "watch_paths": {
- "type": "string",
- "description": "The watch paths."
- },
- "use_build_server": {
- "type": "boolean",
- "nullable": true,
- "description": "Use build server."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Application created successfully.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/dockerfile": {
- "post": {
- "tags": [
- "Applications"
- ],
- "summary": "Create (Dockerfile)",
- "description": "Create new application based on a simple Dockerfile.",
- "operationId": "create-dockerfile-application",
- "requestBody": {
- "description": "Application object that needs to be created.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "project_uuid",
- "server_uuid",
- "environment_name",
- "environment_uuid",
- "dockerfile"
- ],
- "properties": {
- "project_uuid": {
- "type": "string",
- "description": "The project UUID."
- },
- "server_uuid": {
- "type": "string",
- "description": "The server UUID."
- },
- "environment_name": {
- "type": "string",
- "description": "The environment name. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "The environment UUID. You need to provide at least one of environment_name or environment_uuid."
- },
- "dockerfile": {
- "type": "string",
- "description": "The Dockerfile content."
- },
- "build_pack": {
- "type": "string",
- "enum": [
- "nixpacks",
- "static",
- "dockerfile",
- "dockercompose"
- ],
- "description": "The build pack type."
- },
- "ports_exposes": {
- "type": "string",
- "description": "The ports to expose."
- },
- "destination_uuid": {
- "type": "string",
- "description": "The destination UUID."
- },
- "name": {
- "type": "string",
- "description": "The application name."
- },
- "description": {
- "type": "string",
- "description": "The application description."
- },
- "domains": {
- "type": "string",
- "description": "The application domains."
- },
- "docker_registry_image_name": {
- "type": "string",
- "description": "The docker registry image name."
- },
- "docker_registry_image_tag": {
- "type": "string",
- "description": "The docker registry image tag."
- },
- "ports_mappings": {
- "type": "string",
- "description": "The ports mappings."
- },
- "base_directory": {
- "type": "string",
- "description": "The base directory for all commands."
- },
- "health_check_enabled": {
- "type": "boolean",
- "description": "Health check enabled."
- },
- "health_check_path": {
- "type": "string",
- "description": "Health check path."
- },
- "health_check_port": {
- "type": "string",
- "nullable": true,
- "description": "Health check port."
- },
- "health_check_host": {
- "type": "string",
- "nullable": true,
- "description": "Health check host."
- },
- "health_check_method": {
- "type": "string",
- "description": "Health check method."
- },
- "health_check_return_code": {
- "type": "integer",
- "description": "Health check return code."
- },
- "health_check_scheme": {
- "type": "string",
- "description": "Health check scheme."
- },
- "health_check_response_text": {
- "type": "string",
- "nullable": true,
- "description": "Health check response text."
- },
- "health_check_interval": {
- "type": "integer",
- "description": "Health check interval in seconds."
- },
- "health_check_timeout": {
- "type": "integer",
- "description": "Health check timeout in seconds."
- },
- "health_check_retries": {
- "type": "integer",
- "description": "Health check retries count."
- },
- "health_check_start_period": {
- "type": "integer",
- "description": "Health check start period in seconds."
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit."
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit."
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness."
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation."
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit."
- },
- "limits_cpuset": {
- "type": "string",
- "nullable": true,
- "description": "CPU set."
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares."
- },
- "custom_labels": {
- "type": "string",
- "description": "Custom labels."
- },
- "custom_docker_run_options": {
- "type": "string",
- "description": "Custom docker run options."
- },
- "post_deployment_command": {
- "type": "string",
- "description": "Post deployment command."
- },
- "post_deployment_command_container": {
- "type": "string",
- "description": "Post deployment command container."
- },
- "pre_deployment_command": {
- "type": "string",
- "description": "Pre deployment command."
- },
- "pre_deployment_command_container": {
- "type": "string",
- "description": "Pre deployment command container."
- },
- "manual_webhook_secret_github": {
- "type": "string",
- "description": "Manual webhook secret for Github."
- },
- "manual_webhook_secret_gitlab": {
- "type": "string",
- "description": "Manual webhook secret for Gitlab."
- },
- "manual_webhook_secret_bitbucket": {
- "type": "string",
- "description": "Manual webhook secret for Bitbucket."
- },
- "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"
- ]
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "The flag to indicate if the application should be deployed instantly."
- },
- "use_build_server": {
- "type": "boolean",
- "nullable": true,
- "description": "Use build server."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Application created successfully.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/dockerimage": {
- "post": {
- "tags": [
- "Applications"
- ],
- "summary": "Create (Docker Image)",
- "description": "Create new application based on a prebuilt docker image",
- "operationId": "create-dockerimage-application",
- "requestBody": {
- "description": "Application object that needs to be created.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "project_uuid",
- "server_uuid",
- "environment_name",
- "environment_uuid",
- "docker_registry_image_name",
- "ports_exposes"
- ],
- "properties": {
- "project_uuid": {
- "type": "string",
- "description": "The project UUID."
- },
- "server_uuid": {
- "type": "string",
- "description": "The server UUID."
- },
- "environment_name": {
- "type": "string",
- "description": "The environment name. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "The environment UUID. You need to provide at least one of environment_name or environment_uuid."
- },
- "docker_registry_image_name": {
- "type": "string",
- "description": "The docker registry image name."
- },
- "docker_registry_image_tag": {
- "type": "string",
- "description": "The docker registry image tag."
- },
- "ports_exposes": {
- "type": "string",
- "description": "The ports to expose."
- },
- "destination_uuid": {
- "type": "string",
- "description": "The destination UUID."
- },
- "name": {
- "type": "string",
- "description": "The application name."
- },
- "description": {
- "type": "string",
- "description": "The application description."
- },
- "domains": {
- "type": "string",
- "description": "The application domains."
- },
- "ports_mappings": {
- "type": "string",
- "description": "The ports mappings."
- },
- "health_check_enabled": {
- "type": "boolean",
- "description": "Health check enabled."
- },
- "health_check_path": {
- "type": "string",
- "description": "Health check path."
- },
- "health_check_port": {
- "type": "string",
- "nullable": true,
- "description": "Health check port."
- },
- "health_check_host": {
- "type": "string",
- "nullable": true,
- "description": "Health check host."
- },
- "health_check_method": {
- "type": "string",
- "description": "Health check method."
- },
- "health_check_return_code": {
- "type": "integer",
- "description": "Health check return code."
- },
- "health_check_scheme": {
- "type": "string",
- "description": "Health check scheme."
- },
- "health_check_response_text": {
- "type": "string",
- "nullable": true,
- "description": "Health check response text."
- },
- "health_check_interval": {
- "type": "integer",
- "description": "Health check interval in seconds."
- },
- "health_check_timeout": {
- "type": "integer",
- "description": "Health check timeout in seconds."
- },
- "health_check_retries": {
- "type": "integer",
- "description": "Health check retries count."
- },
- "health_check_start_period": {
- "type": "integer",
- "description": "Health check start period in seconds."
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit."
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit."
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness."
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation."
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit."
- },
- "limits_cpuset": {
- "type": "string",
- "nullable": true,
- "description": "CPU set."
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares."
- },
- "custom_labels": {
- "type": "string",
- "description": "Custom labels."
- },
- "custom_docker_run_options": {
- "type": "string",
- "description": "Custom docker run options."
- },
- "post_deployment_command": {
- "type": "string",
- "description": "Post deployment command."
- },
- "post_deployment_command_container": {
- "type": "string",
- "description": "Post deployment command container."
- },
- "pre_deployment_command": {
- "type": "string",
- "description": "Pre deployment command."
- },
- "pre_deployment_command_container": {
- "type": "string",
- "description": "Pre deployment command container."
- },
- "manual_webhook_secret_github": {
- "type": "string",
- "description": "Manual webhook secret for Github."
- },
- "manual_webhook_secret_gitlab": {
- "type": "string",
- "description": "Manual webhook secret for Gitlab."
- },
- "manual_webhook_secret_bitbucket": {
- "type": "string",
- "description": "Manual webhook secret for Bitbucket."
- },
- "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"
- ]
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "The flag to indicate if the application should be deployed instantly."
- },
- "use_build_server": {
- "type": "boolean",
- "nullable": true,
- "description": "Use build server."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Application created successfully.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/dockercompose": {
- "post": {
- "tags": [
- "Applications"
- ],
- "summary": "Create (Docker Compose)",
- "description": "Create new application based on a docker-compose file.",
- "operationId": "create-dockercompose-application",
- "requestBody": {
- "description": "Application object that needs to be created.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "project_uuid",
- "server_uuid",
- "environment_name",
- "environment_uuid",
- "docker_compose_raw"
- ],
- "properties": {
- "project_uuid": {
- "type": "string",
- "description": "The project UUID."
- },
- "server_uuid": {
- "type": "string",
- "description": "The server UUID."
- },
- "environment_name": {
- "type": "string",
- "description": "The environment name. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "The environment UUID. You need to provide at least one of environment_name or environment_uuid."
- },
- "docker_compose_raw": {
- "type": "string",
- "description": "The Docker Compose raw content."
- },
- "destination_uuid": {
- "type": "string",
- "description": "The destination UUID if the server has more than one destinations."
- },
- "name": {
- "type": "string",
- "description": "The application name."
- },
- "description": {
- "type": "string",
- "description": "The application description."
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "The flag to indicate if the application should be deployed instantly."
- },
- "use_build_server": {
- "type": "boolean",
- "nullable": true,
- "description": "Use build server."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Application created successfully.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "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": "get-application-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Get application by UUID.",
- "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": []
- }
- ]
- },
- "delete": {
- "tags": [
- "Applications"
- ],
- "summary": "Delete",
- "description": "Delete application by UUID.",
- "operationId": "delete-application-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- },
- {
- "name": "delete_configurations",
- "in": "query",
- "description": "Delete configurations.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- },
- {
- "name": "delete_volumes",
- "in": "query",
- "description": "Delete volumes.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- },
- {
- "name": "docker_cleanup",
- "in": "query",
- "description": "Run docker cleanup.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- },
- {
- "name": "delete_connected_networks",
- "in": "query",
- "description": "Delete connected networks.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Application deleted.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Application deleted."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- },
- "patch": {
- "tags": [
- "Applications"
- ],
- "summary": "Update",
- "description": "Update application by UUID.",
- "operationId": "update-application-by-uuid",
- "requestBody": {
- "description": "Application updated.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "project_uuid": {
- "type": "string",
- "description": "The project UUID."
- },
- "server_uuid": {
- "type": "string",
- "description": "The server UUID."
- },
- "environment_name": {
- "type": "string",
- "description": "The environment name."
- },
- "github_app_uuid": {
- "type": "string",
- "description": "The Github App UUID."
- },
- "git_repository": {
- "type": "string",
- "description": "The git repository URL."
- },
- "git_branch": {
- "type": "string",
- "description": "The git branch."
- },
- "ports_exposes": {
- "type": "string",
- "description": "The ports to expose."
- },
- "destination_uuid": {
- "type": "string",
- "description": "The destination UUID."
- },
- "build_pack": {
- "type": "string",
- "enum": [
- "nixpacks",
- "static",
- "dockerfile",
- "dockercompose"
- ],
- "description": "The build pack type."
- },
- "name": {
- "type": "string",
- "description": "The application name."
- },
- "description": {
- "type": "string",
- "description": "The application description."
- },
- "domains": {
- "type": "string",
- "description": "The application domains."
- },
- "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_tag": {
- "type": "string",
- "description": "The docker registry image tag."
- },
- "is_static": {
- "type": "boolean",
- "description": "The flag to indicate if the application is static."
- },
- "install_command": {
- "type": "string",
- "description": "The install command."
- },
- "build_command": {
- "type": "string",
- "description": "The build command."
- },
- "start_command": {
- "type": "string",
- "description": "The start command."
- },
- "ports_mappings": {
- "type": "string",
- "description": "The ports mappings."
- },
- "base_directory": {
- "type": "string",
- "description": "The base directory for all commands."
- },
- "publish_directory": {
- "type": "string",
- "description": "The publish directory."
- },
- "health_check_enabled": {
- "type": "boolean",
- "description": "Health check enabled."
- },
- "health_check_path": {
- "type": "string",
- "description": "Health check path."
- },
- "health_check_port": {
- "type": "string",
- "nullable": true,
- "description": "Health check port."
- },
- "health_check_host": {
- "type": "string",
- "nullable": true,
- "description": "Health check host."
- },
- "health_check_method": {
- "type": "string",
- "description": "Health check method."
- },
- "health_check_return_code": {
- "type": "integer",
- "description": "Health check return code."
- },
- "health_check_scheme": {
- "type": "string",
- "description": "Health check scheme."
- },
- "health_check_response_text": {
- "type": "string",
- "nullable": true,
- "description": "Health check response text."
- },
- "health_check_interval": {
- "type": "integer",
- "description": "Health check interval in seconds."
- },
- "health_check_timeout": {
- "type": "integer",
- "description": "Health check timeout in seconds."
- },
- "health_check_retries": {
- "type": "integer",
- "description": "Health check retries count."
- },
- "health_check_start_period": {
- "type": "integer",
- "description": "Health check start period in seconds."
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit."
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit."
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness."
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation."
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit."
- },
- "limits_cpuset": {
- "type": "string",
- "nullable": true,
- "description": "CPU set."
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares."
- },
- "custom_labels": {
- "type": "string",
- "description": "Custom labels."
- },
- "custom_docker_run_options": {
- "type": "string",
- "description": "Custom docker run options."
- },
- "post_deployment_command": {
- "type": "string",
- "description": "Post deployment command."
- },
- "post_deployment_command_container": {
- "type": "string",
- "description": "Post deployment command container."
- },
- "pre_deployment_command": {
- "type": "string",
- "description": "Pre deployment command."
- },
- "pre_deployment_command_container": {
- "type": "string",
- "description": "Pre deployment command container."
- },
- "manual_webhook_secret_github": {
- "type": "string",
- "description": "Manual webhook secret for Github."
- },
- "manual_webhook_secret_gitlab": {
- "type": "string",
- "description": "Manual webhook secret for Gitlab."
- },
- "manual_webhook_secret_bitbucket": {
- "type": "string",
- "description": "Manual webhook secret for Bitbucket."
- },
- "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"
- ]
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "The flag to indicate if the application should be deployed instantly."
- },
- "dockerfile": {
- "type": "string",
- "description": "The Dockerfile content."
- },
- "docker_compose_location": {
- "type": "string",
- "description": "The Docker Compose location."
- },
- "docker_compose_raw": {
- "type": "string",
- "description": "The Docker Compose raw content."
- },
- "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_domains": {
- "type": "array",
- "description": "The Docker Compose domains."
- },
- "watch_paths": {
- "type": "string",
- "description": "The watch paths."
- },
- "use_build_server": {
- "type": "boolean",
- "nullable": true,
- "description": "Use build server."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Application updated.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/{uuid}\/envs": {
- "get": {
- "tags": [
- "Applications"
- ],
- "summary": "List Envs",
- "description": "List all envs by application UUID.",
- "operationId": "list-envs-by-application-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "All environment variables by application UUID.",
- "content": {
- "application\/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#\/components\/schemas\/EnvironmentVariable"
- }
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- },
- "post": {
- "tags": [
- "Applications"
- ],
- "summary": "Create Env",
- "description": "Create env by application UUID.",
- "operationId": "create-env-by-application-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "requestBody": {
- "description": "Env created.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "key": {
- "type": "string",
- "description": "The key of the environment variable."
- },
- "value": {
- "type": "string",
- "description": "The value of the environment variable."
- },
- "is_preview": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in preview deployments."
- },
- "is_build_time": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in build time."
- },
- "is_literal": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is a literal, nothing espaced."
- },
- "is_multiline": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is multiline."
- },
- "is_shown_once": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable's value is shown on the UI."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Environment variable created.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string",
- "example": "nc0k04gk8g0cgsk440g0koko"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- },
- "patch": {
- "tags": [
- "Applications"
- ],
- "summary": "Update Env",
- "description": "Update env by application UUID.",
- "operationId": "update-env-by-application-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "requestBody": {
- "description": "Env updated.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "key",
- "value"
- ],
- "properties": {
- "key": {
- "type": "string",
- "description": "The key of the environment variable."
- },
- "value": {
- "type": "string",
- "description": "The value of the environment variable."
- },
- "is_preview": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in preview deployments."
- },
- "is_build_time": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in build time."
- },
- "is_literal": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is a literal, nothing espaced."
- },
- "is_multiline": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is multiline."
- },
- "is_shown_once": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable's value is shown on the UI."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Environment variable updated.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Environment variable updated."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/{uuid}\/envs\/bulk": {
- "patch": {
- "tags": [
- "Applications"
- ],
- "summary": "Update Envs (Bulk)",
- "description": "Update multiple envs by application UUID.",
- "operationId": "update-envs-by-application-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "requestBody": {
- "description": "Bulk envs updated.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "data"
- ],
- "properties": {
- "data": {
- "type": "array",
- "items": {
- "properties": {
- "key": {
- "type": "string",
- "description": "The key of the environment variable."
- },
- "value": {
- "type": "string",
- "description": "The value of the environment variable."
- },
- "is_preview": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in preview deployments."
- },
- "is_build_time": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in build time."
- },
- "is_literal": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is a literal, nothing espaced."
- },
- "is_multiline": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is multiline."
- },
- "is_shown_once": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable's value is shown on the UI."
- }
- },
- "type": "object"
- }
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Environment variables updated.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Environment variables updated."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/{uuid}\/envs\/{env_uuid}": {
- "delete": {
- "tags": [
- "Applications"
- ],
- "summary": "Delete Env",
- "description": "Delete env by UUID.",
- "operationId": "delete-env-by-application-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- },
- {
- "name": "env_uuid",
- "in": "path",
- "description": "UUID of the environment variable.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Environment variable deleted.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Environment variable deleted."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/{uuid}\/start": {
- "get": {
- "tags": [
- "Applications"
- ],
- "summary": "Start",
- "description": "Start application. `Post` request is also accepted.",
- "operationId": "start-application-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- },
- {
- "name": "force",
- "in": "query",
- "description": "Force rebuild.",
- "schema": {
- "type": "boolean",
- "default": false
- }
- },
- {
- "name": "instant_deploy",
- "in": "query",
- "description": "Instant deploy (skip queuing).",
- "schema": {
- "type": "boolean",
- "default": false
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Start application.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Deployment request queued.",
- "description": "Message."
- },
- "deployment_uuid": {
- "type": "string",
- "example": "doogksw",
- "description": "UUID of the deployment."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/{uuid}\/stop": {
- "get": {
- "tags": [
- "Applications"
- ],
- "summary": "Stop",
- "description": "Stop application. `Post` request is also accepted.",
- "operationId": "stop-application-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Stop application.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Application stopping request queued."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/{uuid}\/restart": {
- "get": {
- "tags": [
- "Applications"
- ],
- "summary": "Restart",
- "description": "Restart application. `Post` request is also accepted.",
- "operationId": "restart-application-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Restart application.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Restart request queued."
- },
- "deployment_uuid": {
- "type": "string",
- "example": "doogksw",
- "description": "UUID of the deployment."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/applications\/{uuid}\/execute": {
- "post": {
- "tags": [
- "Applications"
- ],
- "summary": "Execute Command",
- "description": "Execute a command on the application's current container.",
- "operationId": "execute-command-application",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "requestBody": {
- "description": "Command to execute.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "command": {
- "type": "string",
- "description": "Command to execute."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Execute a command on the application's current container.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Command executed."
- },
- "response": {
- "type": "string"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases": {
- "get": {
- "tags": [
- "Databases"
- ],
- "summary": "List",
- "description": "List all databases.",
- "operationId": "list-databases",
- "responses": {
- "200": {
- "description": "Get all databases",
- "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": []
- }
- ]
- }
- },
- "\/databases\/{uuid}": {
- "get": {
- "tags": [
- "Databases"
- ],
- "summary": "Get",
- "description": "Get database by UUID.",
- "operationId": "get-database-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the database.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Get all databases",
- "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"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- },
- "delete": {
- "tags": [
- "Databases"
- ],
- "summary": "Delete",
- "description": "Delete database by UUID.",
- "operationId": "delete-database-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the database.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- },
- {
- "name": "delete_configurations",
- "in": "query",
- "description": "Delete configurations.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- },
- {
- "name": "delete_volumes",
- "in": "query",
- "description": "Delete volumes.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- },
- {
- "name": "docker_cleanup",
- "in": "query",
- "description": "Run docker cleanup.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- },
- {
- "name": "delete_connected_networks",
- "in": "query",
- "description": "Delete connected networks.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Database deleted.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Database deleted."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- },
- "patch": {
- "tags": [
- "Databases"
- ],
- "summary": "Update",
- "description": "Update database by UUID.",
- "operationId": "update-database-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the database.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "requestBody": {
- "description": "Database data",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "name": {
- "type": "string",
- "description": "Name of the database"
- },
- "description": {
- "type": "string",
- "description": "Description of the database"
- },
- "image": {
- "type": "string",
- "description": "Docker Image of the database"
- },
- "is_public": {
- "type": "boolean",
- "description": "Is the database public?"
- },
- "public_port": {
- "type": "integer",
- "description": "Public port of the database"
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit of the database"
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit of the database"
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness of the database"
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation of the database"
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit of the database"
- },
- "limits_cpuset": {
- "type": "string",
- "description": "CPU set of the database"
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares of the database"
- },
- "postgres_user": {
- "type": "string",
- "description": "PostgreSQL user"
- },
- "postgres_password": {
- "type": "string",
- "description": "PostgreSQL password"
- },
- "postgres_db": {
- "type": "string",
- "description": "PostgreSQL database"
- },
- "postgres_initdb_args": {
- "type": "string",
- "description": "PostgreSQL initdb args"
- },
- "postgres_host_auth_method": {
- "type": "string",
- "description": "PostgreSQL host auth method"
- },
- "postgres_conf": {
- "type": "string",
- "description": "PostgreSQL conf"
- },
- "clickhouse_admin_user": {
- "type": "string",
- "description": "Clickhouse admin user"
- },
- "clickhouse_admin_password": {
- "type": "string",
- "description": "Clickhouse admin password"
- },
- "dragonfly_password": {
- "type": "string",
- "description": "DragonFly password"
- },
- "redis_password": {
- "type": "string",
- "description": "Redis password"
- },
- "redis_conf": {
- "type": "string",
- "description": "Redis conf"
- },
- "keydb_password": {
- "type": "string",
- "description": "KeyDB password"
- },
- "keydb_conf": {
- "type": "string",
- "description": "KeyDB conf"
- },
- "mariadb_conf": {
- "type": "string",
- "description": "MariaDB conf"
- },
- "mariadb_root_password": {
- "type": "string",
- "description": "MariaDB root password"
- },
- "mariadb_user": {
- "type": "string",
- "description": "MariaDB user"
- },
- "mariadb_password": {
- "type": "string",
- "description": "MariaDB password"
- },
- "mariadb_database": {
- "type": "string",
- "description": "MariaDB database"
- },
- "mongo_conf": {
- "type": "string",
- "description": "Mongo conf"
- },
- "mongo_initdb_root_username": {
- "type": "string",
- "description": "Mongo initdb root username"
- },
- "mongo_initdb_root_password": {
- "type": "string",
- "description": "Mongo initdb root password"
- },
- "mongo_initdb_database": {
- "type": "string",
- "description": "Mongo initdb init database"
- },
- "mysql_root_password": {
- "type": "string",
- "description": "MySQL root password"
- },
- "mysql_password": {
- "type": "string",
- "description": "MySQL password"
- },
- "mysql_user": {
- "type": "string",
- "description": "MySQL user"
- },
- "mysql_database": {
- "type": "string",
- "description": "MySQL database"
- },
- "mysql_conf": {
- "type": "string",
- "description": "MySQL conf"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Database updated"
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases\/postgresql": {
- "post": {
- "tags": [
- "Databases"
- ],
- "summary": "Create (PostgreSQL)",
- "description": "Create a new PostgreSQL database.",
- "operationId": "create-database-postgresql",
- "requestBody": {
- "description": "Database data",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "server_uuid",
- "project_uuid",
- "environment_name",
- "environment_uuid"
- ],
- "properties": {
- "server_uuid": {
- "type": "string",
- "description": "UUID of the server"
- },
- "project_uuid": {
- "type": "string",
- "description": "UUID of the project"
- },
- "environment_name": {
- "type": "string",
- "description": "Name of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "UUID of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "postgres_user": {
- "type": "string",
- "description": "PostgreSQL user"
- },
- "postgres_password": {
- "type": "string",
- "description": "PostgreSQL password"
- },
- "postgres_db": {
- "type": "string",
- "description": "PostgreSQL database"
- },
- "postgres_initdb_args": {
- "type": "string",
- "description": "PostgreSQL initdb args"
- },
- "postgres_host_auth_method": {
- "type": "string",
- "description": "PostgreSQL host auth method"
- },
- "postgres_conf": {
- "type": "string",
- "description": "PostgreSQL conf"
- },
- "destination_uuid": {
- "type": "string",
- "description": "UUID of the destination if the server has multiple destinations"
- },
- "name": {
- "type": "string",
- "description": "Name of the database"
- },
- "description": {
- "type": "string",
- "description": "Description of the database"
- },
- "image": {
- "type": "string",
- "description": "Docker Image of the database"
- },
- "is_public": {
- "type": "boolean",
- "description": "Is the database public?"
- },
- "public_port": {
- "type": "integer",
- "description": "Public port of the database"
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit of the database"
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit of the database"
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness of the database"
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation of the database"
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit of the database"
- },
- "limits_cpuset": {
- "type": "string",
- "description": "CPU set of the database"
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares of the database"
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "Instant deploy the database"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Database updated"
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases\/clickhouse": {
- "post": {
- "tags": [
- "Databases"
- ],
- "summary": "Create (Clickhouse)",
- "description": "Create a new Clickhouse database.",
- "operationId": "create-database-clickhouse",
- "requestBody": {
- "description": "Database data",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "server_uuid",
- "project_uuid",
- "environment_name",
- "environment_uuid"
- ],
- "properties": {
- "server_uuid": {
- "type": "string",
- "description": "UUID of the server"
- },
- "project_uuid": {
- "type": "string",
- "description": "UUID of the project"
- },
- "environment_name": {
- "type": "string",
- "description": "Name of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "UUID of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "destination_uuid": {
- "type": "string",
- "description": "UUID of the destination if the server has multiple destinations"
- },
- "clickhouse_admin_user": {
- "type": "string",
- "description": "Clickhouse admin user"
- },
- "clickhouse_admin_password": {
- "type": "string",
- "description": "Clickhouse admin password"
- },
- "name": {
- "type": "string",
- "description": "Name of the database"
- },
- "description": {
- "type": "string",
- "description": "Description of the database"
- },
- "image": {
- "type": "string",
- "description": "Docker Image of the database"
- },
- "is_public": {
- "type": "boolean",
- "description": "Is the database public?"
- },
- "public_port": {
- "type": "integer",
- "description": "Public port of the database"
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit of the database"
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit of the database"
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness of the database"
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation of the database"
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit of the database"
- },
- "limits_cpuset": {
- "type": "string",
- "description": "CPU set of the database"
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares of the database"
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "Instant deploy the database"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Database updated"
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases\/dragonfly": {
- "post": {
- "tags": [
- "Databases"
- ],
- "summary": "Create (DragonFly)",
- "description": "Create a new DragonFly database.",
- "operationId": "create-database-dragonfly",
- "requestBody": {
- "description": "Database data",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "server_uuid",
- "project_uuid",
- "environment_name",
- "environment_uuid"
- ],
- "properties": {
- "server_uuid": {
- "type": "string",
- "description": "UUID of the server"
- },
- "project_uuid": {
- "type": "string",
- "description": "UUID of the project"
- },
- "environment_name": {
- "type": "string",
- "description": "Name of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "UUID of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "destination_uuid": {
- "type": "string",
- "description": "UUID of the destination if the server has multiple destinations"
- },
- "dragonfly_password": {
- "type": "string",
- "description": "DragonFly password"
- },
- "name": {
- "type": "string",
- "description": "Name of the database"
- },
- "description": {
- "type": "string",
- "description": "Description of the database"
- },
- "image": {
- "type": "string",
- "description": "Docker Image of the database"
- },
- "is_public": {
- "type": "boolean",
- "description": "Is the database public?"
- },
- "public_port": {
- "type": "integer",
- "description": "Public port of the database"
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit of the database"
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit of the database"
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness of the database"
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation of the database"
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit of the database"
- },
- "limits_cpuset": {
- "type": "string",
- "description": "CPU set of the database"
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares of the database"
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "Instant deploy the database"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Database updated"
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases\/redis": {
- "post": {
- "tags": [
- "Databases"
- ],
- "summary": "Create (Redis)",
- "description": "Create a new Redis database.",
- "operationId": "create-database-redis",
- "requestBody": {
- "description": "Database data",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "server_uuid",
- "project_uuid",
- "environment_name",
- "environment_uuid"
- ],
- "properties": {
- "server_uuid": {
- "type": "string",
- "description": "UUID of the server"
- },
- "project_uuid": {
- "type": "string",
- "description": "UUID of the project"
- },
- "environment_name": {
- "type": "string",
- "description": "Name of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "UUID of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "destination_uuid": {
- "type": "string",
- "description": "UUID of the destination if the server has multiple destinations"
- },
- "redis_password": {
- "type": "string",
- "description": "Redis password"
- },
- "redis_conf": {
- "type": "string",
- "description": "Redis conf"
- },
- "name": {
- "type": "string",
- "description": "Name of the database"
- },
- "description": {
- "type": "string",
- "description": "Description of the database"
- },
- "image": {
- "type": "string",
- "description": "Docker Image of the database"
- },
- "is_public": {
- "type": "boolean",
- "description": "Is the database public?"
- },
- "public_port": {
- "type": "integer",
- "description": "Public port of the database"
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit of the database"
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit of the database"
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness of the database"
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation of the database"
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit of the database"
- },
- "limits_cpuset": {
- "type": "string",
- "description": "CPU set of the database"
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares of the database"
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "Instant deploy the database"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Database updated"
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases\/keydb": {
- "post": {
- "tags": [
- "Databases"
- ],
- "summary": "Create (KeyDB)",
- "description": "Create a new KeyDB database.",
- "operationId": "create-database-keydb",
- "requestBody": {
- "description": "Database data",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "server_uuid",
- "project_uuid",
- "environment_name",
- "environment_uuid"
- ],
- "properties": {
- "server_uuid": {
- "type": "string",
- "description": "UUID of the server"
- },
- "project_uuid": {
- "type": "string",
- "description": "UUID of the project"
- },
- "environment_name": {
- "type": "string",
- "description": "Name of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "UUID of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "destination_uuid": {
- "type": "string",
- "description": "UUID of the destination if the server has multiple destinations"
- },
- "keydb_password": {
- "type": "string",
- "description": "KeyDB password"
- },
- "keydb_conf": {
- "type": "string",
- "description": "KeyDB conf"
- },
- "name": {
- "type": "string",
- "description": "Name of the database"
- },
- "description": {
- "type": "string",
- "description": "Description of the database"
- },
- "image": {
- "type": "string",
- "description": "Docker Image of the database"
- },
- "is_public": {
- "type": "boolean",
- "description": "Is the database public?"
- },
- "public_port": {
- "type": "integer",
- "description": "Public port of the database"
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit of the database"
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit of the database"
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness of the database"
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation of the database"
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit of the database"
- },
- "limits_cpuset": {
- "type": "string",
- "description": "CPU set of the database"
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares of the database"
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "Instant deploy the database"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Database updated"
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases\/mariadb": {
- "post": {
- "tags": [
- "Databases"
- ],
- "summary": "Create (MariaDB)",
- "description": "Create a new MariaDB database.",
- "operationId": "create-database-mariadb",
- "requestBody": {
- "description": "Database data",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "server_uuid",
- "project_uuid",
- "environment_name",
- "environment_uuid"
- ],
- "properties": {
- "server_uuid": {
- "type": "string",
- "description": "UUID of the server"
- },
- "project_uuid": {
- "type": "string",
- "description": "UUID of the project"
- },
- "environment_name": {
- "type": "string",
- "description": "Name of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "UUID of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "destination_uuid": {
- "type": "string",
- "description": "UUID of the destination if the server has multiple destinations"
- },
- "mariadb_conf": {
- "type": "string",
- "description": "MariaDB conf"
- },
- "mariadb_root_password": {
- "type": "string",
- "description": "MariaDB root password"
- },
- "mariadb_user": {
- "type": "string",
- "description": "MariaDB user"
- },
- "mariadb_password": {
- "type": "string",
- "description": "MariaDB password"
- },
- "mariadb_database": {
- "type": "string",
- "description": "MariaDB database"
- },
- "name": {
- "type": "string",
- "description": "Name of the database"
- },
- "description": {
- "type": "string",
- "description": "Description of the database"
- },
- "image": {
- "type": "string",
- "description": "Docker Image of the database"
- },
- "is_public": {
- "type": "boolean",
- "description": "Is the database public?"
- },
- "public_port": {
- "type": "integer",
- "description": "Public port of the database"
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit of the database"
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit of the database"
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness of the database"
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation of the database"
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit of the database"
- },
- "limits_cpuset": {
- "type": "string",
- "description": "CPU set of the database"
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares of the database"
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "Instant deploy the database"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Database updated"
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases\/mysql": {
- "post": {
- "tags": [
- "Databases"
- ],
- "summary": "Create (MySQL)",
- "description": "Create a new MySQL database.",
- "operationId": "create-database-mysql",
- "requestBody": {
- "description": "Database data",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "server_uuid",
- "project_uuid",
- "environment_name",
- "environment_uuid"
- ],
- "properties": {
- "server_uuid": {
- "type": "string",
- "description": "UUID of the server"
- },
- "project_uuid": {
- "type": "string",
- "description": "UUID of the project"
- },
- "environment_name": {
- "type": "string",
- "description": "Name of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "UUID of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "destination_uuid": {
- "type": "string",
- "description": "UUID of the destination if the server has multiple destinations"
- },
- "mysql_root_password": {
- "type": "string",
- "description": "MySQL root password"
- },
- "mysql_password": {
- "type": "string",
- "description": "MySQL password"
- },
- "mysql_user": {
- "type": "string",
- "description": "MySQL user"
- },
- "mysql_database": {
- "type": "string",
- "description": "MySQL database"
- },
- "mysql_conf": {
- "type": "string",
- "description": "MySQL conf"
- },
- "name": {
- "type": "string",
- "description": "Name of the database"
- },
- "description": {
- "type": "string",
- "description": "Description of the database"
- },
- "image": {
- "type": "string",
- "description": "Docker Image of the database"
- },
- "is_public": {
- "type": "boolean",
- "description": "Is the database public?"
- },
- "public_port": {
- "type": "integer",
- "description": "Public port of the database"
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit of the database"
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit of the database"
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness of the database"
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation of the database"
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit of the database"
- },
- "limits_cpuset": {
- "type": "string",
- "description": "CPU set of the database"
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares of the database"
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "Instant deploy the database"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Database updated"
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases\/mongodb": {
- "post": {
- "tags": [
- "Databases"
- ],
- "summary": "Create (MongoDB)",
- "description": "Create a new MongoDB database.",
- "operationId": "create-database-mongodb",
- "requestBody": {
- "description": "Database data",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "server_uuid",
- "project_uuid",
- "environment_name",
- "environment_uuid"
- ],
- "properties": {
- "server_uuid": {
- "type": "string",
- "description": "UUID of the server"
- },
- "project_uuid": {
- "type": "string",
- "description": "UUID of the project"
- },
- "environment_name": {
- "type": "string",
- "description": "Name of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "UUID of the environment. You need to provide at least one of environment_name or environment_uuid."
- },
- "destination_uuid": {
- "type": "string",
- "description": "UUID of the destination if the server has multiple destinations"
- },
- "mongo_conf": {
- "type": "string",
- "description": "MongoDB conf"
- },
- "mongo_initdb_root_username": {
- "type": "string",
- "description": "MongoDB initdb root username"
- },
- "name": {
- "type": "string",
- "description": "Name of the database"
- },
- "description": {
- "type": "string",
- "description": "Description of the database"
- },
- "image": {
- "type": "string",
- "description": "Docker Image of the database"
- },
- "is_public": {
- "type": "boolean",
- "description": "Is the database public?"
- },
- "public_port": {
- "type": "integer",
- "description": "Public port of the database"
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit of the database"
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit of the database"
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness of the database"
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation of the database"
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit of the database"
- },
- "limits_cpuset": {
- "type": "string",
- "description": "CPU set of the database"
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares of the database"
- },
- "instant_deploy": {
- "type": "boolean",
- "description": "Instant deploy the database"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Database updated"
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases\/{uuid}\/start": {
- "get": {
- "tags": [
- "Databases"
- ],
- "summary": "Start",
- "description": "Start database. `Post` request is also accepted.",
- "operationId": "start-database-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the database.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Start database.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Database starting request queued."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases\/{uuid}\/stop": {
- "get": {
- "tags": [
- "Databases"
- ],
- "summary": "Stop",
- "description": "Stop database. `Post` request is also accepted.",
- "operationId": "stop-database-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the database.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Stop database.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Database stopping request queued."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/databases\/{uuid}\/restart": {
- "get": {
- "tags": [
- "Databases"
- ],
- "summary": "Restart",
- "description": "Restart database. `Post` request is also accepted.",
- "operationId": "restart-database-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the database.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Restart database.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Database restaring request queued."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "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": "list-deployments",
- "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": "get-deployment-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Deployment UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "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": "deploy-by-tag-or-uuid",
- "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",
- "description": "Get Coolify version.",
- "operationId": "version",
- "responses": {
- "200": {
- "description": "Returns the version of the application",
- "content": {
- "application\/json": {
- "schema": {
- "type": "string"
- },
- "example": "v4.0.0"
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/enable": {
- "get": {
- "summary": "Enable API",
- "description": "Enable API (only with root permissions).",
- "operationId": "enable-api",
- "responses": {
- "200": {
- "description": "Enable API.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "API enabled."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "403": {
- "description": "You are not allowed to enable the API.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "You are not allowed to enable the API."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/disable": {
- "get": {
- "summary": "Disable API",
- "description": "Disable API (only with root permissions).",
- "operationId": "disable-api",
- "responses": {
- "200": {
- "description": "Disable API.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "API disabled."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "403": {
- "description": "You are not allowed to disable the API.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "You are not allowed to disable the API."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/health": {
- "get": {
- "summary": "Healthcheck",
- "description": "Healthcheck endpoint.",
- "operationId": "healthcheck",
- "responses": {
- "200": {
- "description": "Healthcheck endpoint.",
- "content": {
- "application\/json": {
- "schema": {
- "type": "string"
- },
- "example": "OK"
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- }
- }
- },
- "\/projects": {
- "get": {
- "tags": [
- "Projects"
- ],
- "summary": "List",
- "description": "List projects.",
- "operationId": "list-projects",
- "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": []
- }
- ]
- },
- "post": {
- "tags": [
- "Projects"
- ],
- "summary": "Create",
- "description": "Create Project.",
- "operationId": "create-project",
- "requestBody": {
- "description": "Project created.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "name": {
- "type": "string",
- "description": "The name of the project."
- },
- "description": {
- "type": "string",
- "description": "The description of the project."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Project created.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string",
- "example": "og888os",
- "description": "The UUID of the project."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/projects\/{uuid}": {
- "get": {
- "tags": [
- "Projects"
- ],
- "summary": "Get",
- "description": "Get project by UUID.",
- "operationId": "get-project-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Project UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "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": []
- }
- ]
- },
- "delete": {
- "tags": [
- "Projects"
- ],
- "summary": "Delete",
- "description": "Delete project by UUID.",
- "operationId": "delete-project-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the application.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Project deleted.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Project deleted."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- },
- "patch": {
- "tags": [
- "Projects"
- ],
- "summary": "Update",
- "description": "Update Project.",
- "operationId": "update-project-by-uuid",
- "requestBody": {
- "description": "Project updated.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "name": {
- "type": "string",
- "description": "The name of the project."
- },
- "description": {
- "type": "string",
- "description": "The description of the project."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Project updated.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string",
- "example": "og888os"
- },
- "name": {
- "type": "string",
- "example": "Project Name"
- },
- "description": {
- "type": "string",
- "example": "Project Description"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/projects\/{uuid}\/{environment_name_or_uuid}": {
- "get": {
- "tags": [
- "Projects"
- ],
- "summary": "Environment",
- "description": "Get environment by name or UUID.",
- "operationId": "get-environment-by-name-or-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Project UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "environment_name_or_uuid",
- "in": "path",
- "description": "Environment name or UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Environment 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": "list-resources",
- "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": "list-private-keys",
- "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": "create-private-key",
- "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": "update-private-key",
- "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": "get-private-key-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Private Key UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Get all private keys.",
- "content": {
- "application\/json": {
- "schema": {
- "$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": "delete-private-key-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Private Key UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "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": "list-servers",
- "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": []
- }
- ]
- },
- "post": {
- "tags": [
- "Servers"
- ],
- "summary": "Create",
- "description": "Create Server.",
- "operationId": "create-server",
- "requestBody": {
- "description": "Server created.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "name": {
- "type": "string",
- "example": "My Server",
- "description": "The name of the server."
- },
- "description": {
- "type": "string",
- "example": "My Server Description",
- "description": "The description of the server."
- },
- "ip": {
- "type": "string",
- "example": "127.0.0.1",
- "description": "The IP of the server."
- },
- "port": {
- "type": "integer",
- "example": 22,
- "description": "The port of the server."
- },
- "user": {
- "type": "string",
- "example": "root",
- "description": "The user of the server."
- },
- "private_key_uuid": {
- "type": "string",
- "example": "og888os",
- "description": "The UUID of the private key."
- },
- "is_build_server": {
- "type": "boolean",
- "example": false,
- "description": "Is build server."
- },
- "instant_validate": {
- "type": "boolean",
- "example": false,
- "description": "Instant validate."
- },
- "proxy_type": {
- "type": "string",
- "enum": [
- "traefik",
- "caddy",
- "none"
- ],
- "example": "traefik",
- "description": "The proxy type."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Server created.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string",
- "example": "og888os",
- "description": "The UUID of the server."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/servers\/{uuid}": {
- "get": {
- "tags": [
- "Servers"
- ],
- "summary": "Get",
- "description": "Get server by UUID.",
- "operationId": "get-server-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Server's UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "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": []
- }
- ]
- },
- "delete": {
- "tags": [
- "Servers"
- ],
- "summary": "Delete",
- "description": "Delete server by UUID.",
- "operationId": "delete-server-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the server.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Server deleted.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Server deleted."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- },
- "patch": {
- "tags": [
- "Servers"
- ],
- "summary": "Update",
- "description": "Update Server.",
- "operationId": "update-server-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Server UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "description": "Server updated.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "name": {
- "type": "string",
- "description": "The name of the server."
- },
- "description": {
- "type": "string",
- "description": "The description of the server."
- },
- "ip": {
- "type": "string",
- "description": "The IP of the server."
- },
- "port": {
- "type": "integer",
- "description": "The port of the server."
- },
- "user": {
- "type": "string",
- "description": "The user of the server."
- },
- "private_key_uuid": {
- "type": "string",
- "description": "The UUID of the private key."
- },
- "is_build_server": {
- "type": "boolean",
- "description": "Is build server."
- },
- "instant_validate": {
- "type": "boolean",
- "description": "Instant validate."
- },
- "proxy_type": {
- "type": "string",
- "enum": [
- "traefik",
- "caddy",
- "none"
- ],
- "description": "The proxy type."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Server updated.",
- "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": "get-resources-by-server-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Server's UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "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": "get-domains-by-server-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Server's UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "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": []
- }
- ]
- }
- },
- "\/servers\/{uuid}\/validate": {
- "get": {
- "tags": [
- "Servers"
- ],
- "summary": "Validate",
- "description": "Validate server by UUID.",
- "operationId": "validate-server-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Server UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "201": {
- "description": "Server validation started.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Validation started."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/services": {
- "get": {
- "tags": [
- "Services"
- ],
- "summary": "List",
- "description": "List all services.",
- "operationId": "list-services",
- "responses": {
- "200": {
- "description": "Get all services",
- "content": {
- "application\/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#\/components\/schemas\/Service"
- }
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- },
- "post": {
- "tags": [
- "Services"
- ],
- "summary": "Create",
- "description": "Create a one-click service",
- "operationId": "create-service",
- "requestBody": {
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "server_uuid",
- "project_uuid",
- "environment_name",
- "environment_uuid",
- "type"
- ],
- "properties": {
- "type": {
- "description": "The one-click service type",
- "type": "string",
- "enum": [
- "activepieces",
- "appsmith",
- "appwrite",
- "authentik",
- "babybuddy",
- "budge",
- "changedetection",
- "chatwoot",
- "classicpress-with-mariadb",
- "classicpress-with-mysql",
- "classicpress-without-database",
- "cloudflared",
- "code-server",
- "dashboard",
- "directus",
- "directus-with-postgresql",
- "docker-registry",
- "docuseal",
- "docuseal-with-postgres",
- "dokuwiki",
- "duplicati",
- "emby",
- "embystat",
- "fider",
- "filebrowser",
- "firefly",
- "formbricks",
- "ghost",
- "gitea",
- "gitea-with-mariadb",
- "gitea-with-mysql",
- "gitea-with-postgresql",
- "glance",
- "glances",
- "glitchtip",
- "grafana",
- "grafana-with-postgresql",
- "grocy",
- "heimdall",
- "homepage",
- "jellyfin",
- "kuzzle",
- "listmonk",
- "logto",
- "mediawiki",
- "meilisearch",
- "metabase",
- "metube",
- "minio",
- "moodle",
- "n8n",
- "n8n-with-postgresql",
- "next-image-transformation",
- "nextcloud",
- "nocodb",
- "odoo",
- "openblocks",
- "pairdrop",
- "penpot",
- "phpmyadmin",
- "pocketbase",
- "posthog",
- "reactive-resume",
- "rocketchat",
- "shlink",
- "slash",
- "snapdrop",
- "statusnook",
- "stirling-pdf",
- "supabase",
- "syncthing",
- "tolgee",
- "trigger",
- "trigger-with-external-database",
- "twenty",
- "umami",
- "unleash-with-postgresql",
- "unleash-without-database",
- "uptime-kuma",
- "vaultwarden",
- "vikunja",
- "weblate",
- "whoogle",
- "wordpress-with-mariadb",
- "wordpress-with-mysql",
- "wordpress-without-database"
- ]
- },
- "name": {
- "type": "string",
- "maxLength": 255,
- "description": "Name of the service."
- },
- "description": {
- "type": "string",
- "nullable": true,
- "description": "Description of the service."
- },
- "project_uuid": {
- "type": "string",
- "description": "Project UUID."
- },
- "environment_name": {
- "type": "string",
- "description": "Environment name. You need to provide at least one of environment_name or environment_uuid."
- },
- "environment_uuid": {
- "type": "string",
- "description": "Environment UUID. You need to provide at least one of environment_name or environment_uuid."
- },
- "server_uuid": {
- "type": "string",
- "description": "Server UUID."
- },
- "destination_uuid": {
- "type": "string",
- "description": "Destination UUID. Required if server has multiple destinations."
- },
- "instant_deploy": {
- "type": "boolean",
- "default": false,
- "description": "Start the service immediately after creation."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Create a service.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string",
- "description": "Service UUID."
- },
- "domains": {
- "type": "array",
- "items": {
- "type": "string"
- },
- "description": "Service domains."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/services\/{uuid}": {
- "get": {
- "tags": [
- "Services"
- ],
- "summary": "Get",
- "description": "Get service by UUID.",
- "operationId": "get-service-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Service UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Get a service by UUID.",
- "content": {
- "application\/json": {
- "schema": {
- "$ref": "#\/components\/schemas\/Service"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- },
- "delete": {
- "tags": [
- "Services"
- ],
- "summary": "Delete",
- "description": "Delete service by UUID.",
- "operationId": "delete-service-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "Service UUID",
- "required": true,
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "delete_configurations",
- "in": "query",
- "description": "Delete configurations.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- },
- {
- "name": "delete_volumes",
- "in": "query",
- "description": "Delete volumes.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- },
- {
- "name": "docker_cleanup",
- "in": "query",
- "description": "Run docker cleanup.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- },
- {
- "name": "delete_connected_networks",
- "in": "query",
- "description": "Delete connected networks.",
- "required": false,
- "schema": {
- "type": "boolean",
- "default": true
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Delete a service by UUID",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Service deletion request queued."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/services\/{uuid}\/envs": {
- "get": {
- "tags": [
- "Services"
- ],
- "summary": "List Envs",
- "description": "List all envs by service UUID.",
- "operationId": "list-envs-by-service-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the service.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "All environment variables by service UUID.",
- "content": {
- "application\/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#\/components\/schemas\/EnvironmentVariable"
- }
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- },
- "post": {
- "tags": [
- "Services"
- ],
- "summary": "Create Env",
- "description": "Create env by service UUID.",
- "operationId": "create-env-by-service-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the service.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "requestBody": {
- "description": "Env created.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "key": {
- "type": "string",
- "description": "The key of the environment variable."
- },
- "value": {
- "type": "string",
- "description": "The value of the environment variable."
- },
- "is_preview": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in preview deployments."
- },
- "is_build_time": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in build time."
- },
- "is_literal": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is a literal, nothing espaced."
- },
- "is_multiline": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is multiline."
- },
- "is_shown_once": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable's value is shown on the UI."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Environment variable created.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "uuid": {
- "type": "string",
- "example": "nc0k04gk8g0cgsk440g0koko"
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- },
- "patch": {
- "tags": [
- "Services"
- ],
- "summary": "Update Env",
- "description": "Update env by service UUID.",
- "operationId": "update-env-by-service-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the service.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "requestBody": {
- "description": "Env updated.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "key",
- "value"
- ],
- "properties": {
- "key": {
- "type": "string",
- "description": "The key of the environment variable."
- },
- "value": {
- "type": "string",
- "description": "The value of the environment variable."
- },
- "is_preview": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in preview deployments."
- },
- "is_build_time": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in build time."
- },
- "is_literal": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is a literal, nothing espaced."
- },
- "is_multiline": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is multiline."
- },
- "is_shown_once": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable's value is shown on the UI."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Environment variable updated.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Environment variable updated."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/services\/{uuid}\/envs\/bulk": {
- "patch": {
- "tags": [
- "Services"
- ],
- "summary": "Update Envs (Bulk)",
- "description": "Update multiple envs by service UUID.",
- "operationId": "update-envs-by-service-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the service.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "requestBody": {
- "description": "Bulk envs updated.",
- "required": true,
- "content": {
- "application\/json": {
- "schema": {
- "required": [
- "data"
- ],
- "properties": {
- "data": {
- "type": "array",
- "items": {
- "properties": {
- "key": {
- "type": "string",
- "description": "The key of the environment variable."
- },
- "value": {
- "type": "string",
- "description": "The value of the environment variable."
- },
- "is_preview": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in preview deployments."
- },
- "is_build_time": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is used in build time."
- },
- "is_literal": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is a literal, nothing espaced."
- },
- "is_multiline": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable is multiline."
- },
- "is_shown_once": {
- "type": "boolean",
- "description": "The flag to indicate if the environment variable's value is shown on the UI."
- }
- },
- "type": "object"
- }
- }
- },
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "Environment variables updated.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Environment variables updated."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/services\/{uuid}\/envs\/{env_uuid}": {
- "delete": {
- "tags": [
- "Services"
- ],
- "summary": "Delete Env",
- "description": "Delete env by UUID.",
- "operationId": "delete-env-by-service-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the service.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- },
- {
- "name": "env_uuid",
- "in": "path",
- "description": "UUID of the environment variable.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Environment variable deleted.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Environment variable deleted."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/services\/{uuid}\/start": {
- "get": {
- "tags": [
- "Services"
- ],
- "summary": "Start",
- "description": "Start service. `Post` request is also accepted.",
- "operationId": "start-service-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the service.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Start service.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Service starting request queued."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/services\/{uuid}\/stop": {
- "get": {
- "tags": [
- "Services"
- ],
- "summary": "Stop",
- "description": "Stop service. `Post` request is also accepted.",
- "operationId": "stop-service-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the service.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Stop service.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Service stopping request queued."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/services\/{uuid}\/restart": {
- "get": {
- "tags": [
- "Services"
- ],
- "summary": "Restart",
- "description": "Restart service. `Post` request is also accepted.",
- "operationId": "restart-service-by-uuid",
- "parameters": [
- {
- "name": "uuid",
- "in": "path",
- "description": "UUID of the service.",
- "required": true,
- "schema": {
- "type": "string",
- "format": "uuid"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Restart service.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Service restaring request queued."
- }
- },
- "type": "object"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/teams": {
- "get": {
- "tags": [
- "Teams"
- ],
- "summary": "List",
- "description": "Get all teams.",
- "operationId": "list-teams",
- "responses": {
- "200": {
- "description": "List of teams.",
- "content": {
- "application\/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#\/components\/schemas\/Team"
- }
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/teams\/{id}": {
- "get": {
- "tags": [
- "Teams"
- ],
- "summary": "Get",
- "description": "Get team by TeamId.",
- "operationId": "get-team-by-id",
- "parameters": [
- {
- "name": "id",
- "in": "path",
- "description": "Team ID",
- "required": true,
- "schema": {
- "type": "integer"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "List of teams.",
- "content": {
- "application\/json": {
- "schema": {
- "$ref": "#\/components\/schemas\/Team"
- }
- }
- }
- },
- "401": {
- "$ref": "#\/components\/responses\/401"
- },
- "400": {
- "$ref": "#\/components\/responses\/400"
- },
- "404": {
- "$ref": "#\/components\/responses\/404"
- }
- },
- "security": [
- {
- "bearerAuth": []
- }
- ]
- }
- },
- "\/teams\/{id}\/members": {
- "get": {
- "tags": [
- "Teams"
- ],
- "summary": "Members",
- "description": "Get members by TeamId.",
- "operationId": "get-members-by-team-id",
- "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": "get-current-team",
- "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": "get-current-team-members",
- "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",
- "description": "The application identifier in the database."
- },
- "description": {
- "type": "string",
- "nullable": true,
- "description": "The application description."
- },
- "repository_project_id": {
- "type": "integer",
- "nullable": true,
- "description": "The repository project identifier."
- },
- "uuid": {
- "type": "string",
- "description": "The application UUID."
- },
- "name": {
- "type": "string",
- "description": "The application name."
- },
- "fqdn": {
- "type": "string",
- "nullable": true,
- "description": "The application domains."
- },
- "config_hash": {
- "type": "string",
- "description": "Configuration hash."
- },
- "git_repository": {
- "type": "string",
- "description": "Git repository URL."
- },
- "git_branch": {
- "type": "string",
- "description": "Git branch."
- },
- "git_commit_sha": {
- "type": "string",
- "description": "Git commit SHA."
- },
- "git_full_url": {
- "type": "string",
- "nullable": true,
- "description": "Git full URL."
- },
- "docker_registry_image_name": {
- "type": "string",
- "nullable": true,
- "description": "Docker registry image name."
- },
- "docker_registry_image_tag": {
- "type": "string",
- "nullable": true,
- "description": "Docker registry image tag."
- },
- "build_pack": {
- "type": "string",
- "description": "Build pack.",
- "enum": [
- "nixpacks",
- "static",
- "dockerfile",
- "dockercompose"
- ]
- },
- "static_image": {
- "type": "string",
- "description": "Static image used when static site is deployed."
- },
- "install_command": {
- "type": "string",
- "description": "Install command."
- },
- "build_command": {
- "type": "string",
- "description": "Build command."
- },
- "start_command": {
- "type": "string",
- "description": "Start command."
- },
- "ports_exposes": {
- "type": "string",
- "description": "Ports exposes."
- },
- "ports_mappings": {
- "type": "string",
- "nullable": true,
- "description": "Ports mappings."
- },
- "base_directory": {
- "type": "string",
- "description": "Base directory for all commands."
- },
- "publish_directory": {
- "type": "string",
- "description": "Publish directory."
- },
- "health_check_enabled": {
- "type": "boolean",
- "description": "Health check enabled."
- },
- "health_check_path": {
- "type": "string",
- "description": "Health check path."
- },
- "health_check_port": {
- "type": "string",
- "nullable": true,
- "description": "Health check port."
- },
- "health_check_host": {
- "type": "string",
- "nullable": true,
- "description": "Health check host."
- },
- "health_check_method": {
- "type": "string",
- "description": "Health check method."
- },
- "health_check_return_code": {
- "type": "integer",
- "description": "Health check return code."
- },
- "health_check_scheme": {
- "type": "string",
- "description": "Health check scheme."
- },
- "health_check_response_text": {
- "type": "string",
- "nullable": true,
- "description": "Health check response text."
- },
- "health_check_interval": {
- "type": "integer",
- "description": "Health check interval in seconds."
- },
- "health_check_timeout": {
- "type": "integer",
- "description": "Health check timeout in seconds."
- },
- "health_check_retries": {
- "type": "integer",
- "description": "Health check retries count."
- },
- "health_check_start_period": {
- "type": "integer",
- "description": "Health check start period in seconds."
- },
- "limits_memory": {
- "type": "string",
- "description": "Memory limit."
- },
- "limits_memory_swap": {
- "type": "string",
- "description": "Memory swap limit."
- },
- "limits_memory_swappiness": {
- "type": "integer",
- "description": "Memory swappiness."
- },
- "limits_memory_reservation": {
- "type": "string",
- "description": "Memory reservation."
- },
- "limits_cpus": {
- "type": "string",
- "description": "CPU limit."
- },
- "limits_cpuset": {
- "type": "string",
- "nullable": true,
- "description": "CPU set."
- },
- "limits_cpu_shares": {
- "type": "integer",
- "description": "CPU shares."
- },
- "status": {
- "type": "string",
- "description": "Application status."
- },
- "preview_url_template": {
- "type": "string",
- "description": "Preview URL template."
- },
- "destination_type": {
- "type": "string",
- "description": "Destination type."
- },
- "destination_id": {
- "type": "integer",
- "description": "Destination identifier."
- },
- "source_id": {
- "type": "integer",
- "nullable": true,
- "description": "Source identifier."
- },
- "private_key_id": {
- "type": "integer",
- "nullable": true,
- "description": "Private key identifier."
- },
- "environment_id": {
- "type": "integer",
- "description": "Environment identifier."
- },
- "dockerfile": {
- "type": "string",
- "nullable": true,
- "description": "Dockerfile content. Used for dockerfile build pack."
- },
- "dockerfile_location": {
- "type": "string",
- "description": "Dockerfile location."
- },
- "custom_labels": {
- "type": "string",
- "nullable": true,
- "description": "Custom labels."
- },
- "dockerfile_target_build": {
- "type": "string",
- "nullable": true,
- "description": "Dockerfile target build."
- },
- "manual_webhook_secret_github": {
- "type": "string",
- "nullable": true,
- "description": "Manual webhook secret for GitHub."
- },
- "manual_webhook_secret_gitlab": {
- "type": "string",
- "nullable": true,
- "description": "Manual webhook secret for GitLab."
- },
- "manual_webhook_secret_bitbucket": {
- "type": "string",
- "nullable": true,
- "description": "Manual webhook secret for Bitbucket."
- },
- "manual_webhook_secret_gitea": {
- "type": "string",
- "nullable": true,
- "description": "Manual webhook secret for Gitea."
- },
- "docker_compose_location": {
- "type": "string",
- "description": "Docker compose location."
- },
- "docker_compose": {
- "type": "string",
- "nullable": true,
- "description": "Docker compose content. Used for docker compose build pack."
- },
- "docker_compose_raw": {
- "type": "string",
- "nullable": true,
- "description": "Docker compose raw content."
- },
- "docker_compose_domains": {
- "type": "string",
- "nullable": true,
- "description": "Docker compose domains."
- },
- "docker_compose_custom_start_command": {
- "type": "string",
- "nullable": true,
- "description": "Docker compose custom start command."
- },
- "docker_compose_custom_build_command": {
- "type": "string",
- "nullable": true,
- "description": "Docker compose custom build command."
- },
- "swarm_replicas": {
- "type": "integer",
- "nullable": true,
- "description": "Swarm replicas. Only used for swarm deployments."
- },
- "swarm_placement_constraints": {
- "type": "string",
- "nullable": true,
- "description": "Swarm placement constraints. Only used for swarm deployments."
- },
- "custom_docker_run_options": {
- "type": "string",
- "nullable": true,
- "description": "Custom docker run options."
- },
- "post_deployment_command": {
- "type": "string",
- "nullable": true,
- "description": "Post deployment command."
- },
- "post_deployment_command_container": {
- "type": "string",
- "nullable": true,
- "description": "Post deployment command container."
- },
- "pre_deployment_command": {
- "type": "string",
- "nullable": true,
- "description": "Pre deployment command."
- },
- "pre_deployment_command_container": {
- "type": "string",
- "nullable": true,
- "description": "Pre deployment command container."
- },
- "watch_paths": {
- "type": "string",
- "nullable": true,
- "description": "Watch paths."
- },
- "custom_healthcheck_found": {
- "type": "boolean",
- "description": "Custom healthcheck found."
- },
- "redirect": {
- "type": "string",
- "nullable": true,
- "description": "How to set redirect with Traefik \/ Caddy. www<->non-www.",
- "enum": [
- "www",
- "non-www",
- "both"
- ]
- },
- "created_at": {
- "type": "string",
- "format": "date-time",
- "description": "The date and time when the application was created."
- },
- "updated_at": {
- "type": "string",
- "format": "date-time",
- "description": "The date and time when the application was last updated."
- },
- "deleted_at": {
- "type": "string",
- "format": "date-time",
- "nullable": true,
- "description": "The date and time when the application was deleted."
- },
- "compose_parsing_version": {
- "type": "string",
- "description": "How Coolify parse the compose file."
- },
- "custom_nginx_configuration": {
- "type": "string",
- "nullable": true,
- "description": "Custom Nginx configuration base64 encoded."
- }
- },
- "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"
- },
- "EnvironmentVariable": {
- "description": "Environment Variable model",
- "properties": {
- "id": {
- "type": "integer"
- },
- "uuid": {
- "type": "string"
- },
- "resourceable_type": {
- "type": "string"
- },
- "resourceable_id": {
- "type": "integer"
- },
- "is_build_time": {
- "type": "boolean"
- },
- "is_literal": {
- "type": "boolean"
- },
- "is_multiline": {
- "type": "boolean"
- },
- "is_preview": {
- "type": "boolean"
- },
- "is_shared": {
- "type": "boolean"
- },
- "is_shown_once": {
- "type": "boolean"
- },
- "key": {
- "type": "string"
- },
- "value": {
- "type": "string"
- },
- "real_value": {
- "type": "string"
- },
- "version": {
- "type": "string"
- },
- "created_at": {
- "type": "string"
- },
- "updated_at": {
- "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"
- },
- "description": {
- "type": "string"
- },
- "environments": {
- "description": "The environments of the project.",
- "type": "array",
- "items": {
- "$ref": "#\/components\/schemas\/Environment"
- }
- }
- },
- "type": "object"
- },
- "Server": {
- "description": "Server model",
- "properties": {
- "id": {
- "type": "integer",
- "description": "The server ID."
- },
- "uuid": {
- "type": "string",
- "description": "The server UUID."
- },
- "name": {
- "type": "string",
- "description": "The server name."
- },
- "description": {
- "type": "string",
- "description": "The server description."
- },
- "ip": {
- "type": "string",
- "description": "The IP address."
- },
- "user": {
- "type": "string",
- "description": "The user."
- },
- "port": {
- "type": "integer",
- "description": "The port number."
- },
- "proxy": {
- "type": "object",
- "description": "The proxy configuration."
- },
- "proxy_type": {
- "type": "string",
- "enum": [
- "traefik",
- "caddy",
- "none"
- ],
- "description": "The proxy type."
- },
- "high_disk_usage_notification_sent": {
- "type": "boolean",
- "description": "The flag to indicate if the high disk usage notification has been sent."
- },
- "unreachable_notification_sent": {
- "type": "boolean",
- "description": "The flag to indicate if the unreachable notification has been sent."
- },
- "unreachable_count": {
- "type": "integer",
- "description": "The unreachable count for your server."
- },
- "validation_logs": {
- "type": "string",
- "description": "The validation logs."
- },
- "log_drain_notification_sent": {
- "type": "boolean",
- "description": "The flag to indicate if the log drain notification has been sent."
- },
- "swarm_cluster": {
- "type": "string",
- "description": "The swarm cluster configuration."
- },
- "settings": {
- "$ref": "#\/components\/schemas\/ServerSetting"
- }
- },
- "type": "object"
- },
- "ServerSetting": {
- "description": "Server Settings model",
- "properties": {
- "id": {
- "type": "integer"
- },
- "concurrent_builds": {
- "type": "integer"
- },
- "dynamic_timeout": {
- "type": "integer"
- },
- "force_disabled": {
- "type": "boolean"
- },
- "force_server_cleanup": {
- "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_sentinel_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"
- },
- "sentinel_metrics_history_days": {
- "type": "integer"
- },
- "sentinel_metrics_refresh_rate_seconds": {
- "type": "integer"
- },
- "sentinel_token": {
- "type": "string"
- },
- "docker_cleanup_frequency": {
- "type": "string"
- },
- "docker_cleanup_threshold": {
- "type": "integer"
- },
- "server_id": {
- "type": "integer"
- },
- "wildcard_domain": {
- "type": "string"
- },
- "created_at": {
- "type": "string"
- },
- "updated_at": {
- "type": "string"
- },
- "delete_unused_volumes": {
- "type": "boolean",
- "description": "The flag to indicate if the unused volumes should be deleted."
- },
- "delete_unused_networks": {
- "type": "boolean",
- "description": "The flag to indicate if the unused networks should be deleted."
- }
- },
- "type": "object"
- },
- "Service": {
- "description": "Service model",
- "properties": {
- "id": {
- "type": "integer",
- "description": "The unique identifier of the service. Only used for database identification."
- },
- "uuid": {
- "type": "string",
- "description": "The unique identifier of the service."
- },
- "name": {
- "type": "string",
- "description": "The name of the service."
- },
- "environment_id": {
- "type": "integer",
- "description": "The unique identifier of the environment where the service is attached to."
- },
- "server_id": {
- "type": "integer",
- "description": "The unique identifier of the server where the service is running."
- },
- "description": {
- "type": "string",
- "description": "The description of the service."
- },
- "docker_compose_raw": {
- "type": "string",
- "description": "The raw docker-compose.yml file of the service."
- },
- "docker_compose": {
- "type": "string",
- "description": "The docker-compose.yml file that is parsed and modified by Coolify."
- },
- "destination_type": {
- "type": "string",
- "description": "Destination type."
- },
- "destination_id": {
- "type": "integer",
- "description": "The unique identifier of the destination where the service is running."
- },
- "connect_to_docker_network": {
- "type": "boolean",
- "description": "The flag to connect the service to the predefined Docker network."
- },
- "is_container_label_escape_enabled": {
- "type": "boolean",
- "description": "The flag to enable the container label escape."
- },
- "is_container_label_readonly_enabled": {
- "type": "boolean",
- "description": "The flag to enable the container label readonly."
- },
- "config_hash": {
- "type": "string",
- "description": "The hash of the service configuration."
- },
- "service_type": {
- "type": "string",
- "description": "The type of the service."
- },
- "created_at": {
- "type": "string",
- "description": "The date and time when the service was created."
- },
- "updated_at": {
- "type": "string",
- "description": "The date and time when the service was last updated."
- },
- "deleted_at": {
- "type": "string",
- "description": "The date and time when the service was deleted."
- }
- },
- "type": "object"
- },
- "Team": {
- "description": "Team model",
- "properties": {
- "id": {
- "type": "integer",
- "description": "The unique identifier of the team."
- },
- "name": {
- "type": "string",
- "description": "The name of the team."
- },
- "description": {
- "type": "string",
- "description": "The description of the team."
- },
- "personal_team": {
- "type": "boolean",
- "description": "Whether the team is personal or not."
- },
- "created_at": {
- "type": "string",
- "description": "The date and time the team was created."
- },
- "updated_at": {
- "type": "string",
- "description": "The date and time the team was last updated."
- },
- "show_boarding": {
- "type": "boolean",
- "description": "Whether to show the boarding screen or not."
- },
- "custom_server_limit": {
- "type": "string",
- "description": "The custom server limit."
- },
- "members": {
- "description": "The members of the team.",
- "type": "array",
- "items": {
- "$ref": "#\/components\/schemas\/User"
- }
- }
- },
- "type": "object"
- },
- "User": {
- "description": "User model",
- "properties": {
- "id": {
- "type": "integer",
- "description": "The user identifier in the database."
- },
- "name": {
- "type": "string",
- "description": "The user name."
- },
- "email": {
- "type": "string",
- "description": "The user email."
- },
- "email_verified_at": {
- "type": "string",
- "description": "The date when the user email was verified."
- },
- "created_at": {
- "type": "string",
- "description": "The date when the user was created."
- },
- "updated_at": {
- "type": "string",
- "description": "The date when the user was updated."
- },
- "two_factor_confirmed_at": {
- "type": "string",
- "description": "The date when the user two factor was confirmed."
- },
- "force_password_reset": {
- "type": "boolean",
- "description": "The flag to force the user to reset the password."
- },
- "marketing_emails": {
- "type": "boolean",
- "description": "The flag to receive marketing emails."
- }
- },
- "type": "object"
- }
- },
- "responses": {
- "400": {
- "description": "Invalid token.",
- "content": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "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": {
- "application\/json": {
- "schema": {
- "properties": {
- "message": {
- "type": "string",
- "example": "Resource not found."
- }
- },
- "type": "object"
- }
- }
- }
- }
- },
- "securitySchemes": {
- "bearerAuth": {
- "type": "http",
- "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": "Databases",
- "description": "Databases"
- },
- {
- "name": "Deployments",
- "description": "Deployments"
- },
- {
- "name": "Projects",
- "description": "Projects"
- },
- {
- "name": "Resources",
- "description": "Resources"
- },
- {
- "name": "Private Keys",
- "description": "Private Keys"
- },
- {
- "name": "Servers",
- "description": "Servers"
- },
- {
- "name": "Services",
- "description": "Services"
- },
- {
- "name": "Teams",
- "description": "Teams"
- }
- ]
-}
\ No newline at end of file
diff --git a/openapi.yaml b/openapi.yaml
deleted file mode 100644
index 2d18031133..0000000000
--- a/openapi.yaml
+++ /dev/null
@@ -1,5342 +0,0 @@
-openapi: 3.1.0
-info:
- title: Coolify
- version: '0.1'
-servers:
- -
- url: 'https://app.coolify.io/api/v1'
- description: 'Coolify Cloud API. Change the host to your own instance if you are self-hosting.'
-paths:
- /applications:
- get:
- tags:
- - Applications
- summary: List
- description: 'List all applications.'
- operationId: list-applications
- 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/public:
- post:
- tags:
- - Applications
- summary: 'Create (Public)'
- description: 'Create new application based on a public git repository.'
- operationId: create-public-application
- requestBody:
- description: 'Application object that needs to be created.'
- required: true
- content:
- application/json:
- schema:
- required:
- - project_uuid
- - server_uuid
- - environment_name
- - environment_uuid
- - git_repository
- - git_branch
- - build_pack
- - ports_exposes
- properties:
- project_uuid:
- type: string
- description: 'The project UUID.'
- server_uuid:
- type: string
- description: 'The server UUID.'
- environment_name:
- type: string
- description: 'The environment name. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'
- git_repository:
- type: string
- description: 'The git repository URL.'
- git_branch:
- type: string
- description: 'The git branch.'
- build_pack:
- type: string
- enum: [nixpacks, static, dockerfile, dockercompose]
- description: 'The build pack type.'
- ports_exposes:
- type: string
- description: 'The ports to expose.'
- destination_uuid:
- type: string
- description: 'The destination UUID.'
- name:
- type: string
- description: 'The application name.'
- description:
- type: string
- description: 'The application description.'
- domains:
- type: string
- description: 'The application domains.'
- 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_tag:
- type: string
- description: 'The docker registry image tag.'
- is_static:
- type: boolean
- description: 'The flag to indicate if the application is static.'
- static_image:
- type: string
- enum: ['nginx:alpine']
- description: 'The static image.'
- install_command:
- type: string
- description: 'The install command.'
- build_command:
- type: string
- description: 'The build command.'
- start_command:
- type: string
- description: 'The start command.'
- ports_mappings:
- type: string
- description: 'The ports mappings.'
- base_directory:
- type: string
- description: 'The base directory for all commands.'
- publish_directory:
- type: string
- description: 'The publish directory.'
- health_check_enabled:
- type: boolean
- description: 'Health check enabled.'
- health_check_path:
- type: string
- description: 'Health check path.'
- health_check_port:
- type: string
- nullable: true
- description: 'Health check port.'
- health_check_host:
- type: string
- nullable: true
- description: 'Health check host.'
- health_check_method:
- type: string
- description: 'Health check method.'
- health_check_return_code:
- type: integer
- description: 'Health check return code.'
- health_check_scheme:
- type: string
- description: 'Health check scheme.'
- health_check_response_text:
- type: string
- nullable: true
- description: 'Health check response text.'
- health_check_interval:
- type: integer
- description: 'Health check interval in seconds.'
- health_check_timeout:
- type: integer
- description: 'Health check timeout in seconds.'
- health_check_retries:
- type: integer
- description: 'Health check retries count.'
- health_check_start_period:
- type: integer
- description: 'Health check start period in seconds.'
- limits_memory:
- type: string
- description: 'Memory limit.'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit.'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness.'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation.'
- limits_cpus:
- type: string
- description: 'CPU limit.'
- limits_cpuset:
- type: string
- nullable: true
- description: 'CPU set.'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares.'
- custom_labels:
- type: string
- description: 'Custom labels.'
- custom_docker_run_options:
- type: string
- description: 'Custom docker run options.'
- post_deployment_command:
- type: string
- description: 'Post deployment command.'
- post_deployment_command_container:
- type: string
- description: 'Post deployment command container.'
- pre_deployment_command:
- type: string
- description: 'Pre deployment command.'
- pre_deployment_command_container:
- type: string
- description: 'Pre deployment command container.'
- manual_webhook_secret_github:
- type: string
- description: 'Manual webhook secret for Github.'
- manual_webhook_secret_gitlab:
- type: string
- description: 'Manual webhook secret for Gitlab.'
- manual_webhook_secret_bitbucket:
- type: string
- description: 'Manual webhook secret for Bitbucket.'
- 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]
- instant_deploy:
- type: boolean
- description: 'The flag to indicate if the application should be deployed instantly.'
- dockerfile:
- type: string
- description: 'The Dockerfile content.'
- docker_compose_location:
- type: string
- description: 'The Docker Compose location.'
- docker_compose_raw:
- type: string
- description: 'The Docker Compose raw content.'
- 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_domains:
- type: array
- description: 'The Docker Compose domains.'
- watch_paths:
- type: string
- description: 'The watch paths.'
- use_build_server:
- type: boolean
- nullable: true
- description: 'Use build server.'
- type: object
- responses:
- '201':
- description: 'Application created successfully.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /applications/private-github-app:
- post:
- tags:
- - Applications
- summary: 'Create (Private - GH App)'
- description: 'Create new application based on a private repository through a Github App.'
- operationId: create-private-github-app-application
- requestBody:
- description: 'Application object that needs to be created.'
- required: true
- content:
- application/json:
- schema:
- required:
- - project_uuid
- - server_uuid
- - environment_name
- - environment_uuid
- - github_app_uuid
- - git_repository
- - git_branch
- - build_pack
- - ports_exposes
- properties:
- project_uuid:
- type: string
- description: 'The project UUID.'
- server_uuid:
- type: string
- description: 'The server UUID.'
- environment_name:
- type: string
- description: 'The environment name. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'
- github_app_uuid:
- type: string
- description: 'The Github App UUID.'
- git_repository:
- type: string
- description: 'The git repository URL.'
- git_branch:
- type: string
- description: 'The git branch.'
- ports_exposes:
- type: string
- description: 'The ports to expose.'
- destination_uuid:
- type: string
- description: 'The destination UUID.'
- build_pack:
- type: string
- enum: [nixpacks, static, dockerfile, dockercompose]
- description: 'The build pack type.'
- name:
- type: string
- description: 'The application name.'
- description:
- type: string
- description: 'The application description.'
- domains:
- type: string
- description: 'The application domains.'
- 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_tag:
- type: string
- description: 'The docker registry image tag.'
- is_static:
- type: boolean
- description: 'The flag to indicate if the application is static.'
- static_image:
- type: string
- enum: ['nginx:alpine']
- description: 'The static image.'
- install_command:
- type: string
- description: 'The install command.'
- build_command:
- type: string
- description: 'The build command.'
- start_command:
- type: string
- description: 'The start command.'
- ports_mappings:
- type: string
- description: 'The ports mappings.'
- base_directory:
- type: string
- description: 'The base directory for all commands.'
- publish_directory:
- type: string
- description: 'The publish directory.'
- health_check_enabled:
- type: boolean
- description: 'Health check enabled.'
- health_check_path:
- type: string
- description: 'Health check path.'
- health_check_port:
- type: string
- nullable: true
- description: 'Health check port.'
- health_check_host:
- type: string
- nullable: true
- description: 'Health check host.'
- health_check_method:
- type: string
- description: 'Health check method.'
- health_check_return_code:
- type: integer
- description: 'Health check return code.'
- health_check_scheme:
- type: string
- description: 'Health check scheme.'
- health_check_response_text:
- type: string
- nullable: true
- description: 'Health check response text.'
- health_check_interval:
- type: integer
- description: 'Health check interval in seconds.'
- health_check_timeout:
- type: integer
- description: 'Health check timeout in seconds.'
- health_check_retries:
- type: integer
- description: 'Health check retries count.'
- health_check_start_period:
- type: integer
- description: 'Health check start period in seconds.'
- limits_memory:
- type: string
- description: 'Memory limit.'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit.'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness.'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation.'
- limits_cpus:
- type: string
- description: 'CPU limit.'
- limits_cpuset:
- type: string
- nullable: true
- description: 'CPU set.'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares.'
- custom_labels:
- type: string
- description: 'Custom labels.'
- custom_docker_run_options:
- type: string
- description: 'Custom docker run options.'
- post_deployment_command:
- type: string
- description: 'Post deployment command.'
- post_deployment_command_container:
- type: string
- description: 'Post deployment command container.'
- pre_deployment_command:
- type: string
- description: 'Pre deployment command.'
- pre_deployment_command_container:
- type: string
- description: 'Pre deployment command container.'
- manual_webhook_secret_github:
- type: string
- description: 'Manual webhook secret for Github.'
- manual_webhook_secret_gitlab:
- type: string
- description: 'Manual webhook secret for Gitlab.'
- manual_webhook_secret_bitbucket:
- type: string
- description: 'Manual webhook secret for Bitbucket.'
- 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]
- instant_deploy:
- type: boolean
- description: 'The flag to indicate if the application should be deployed instantly.'
- dockerfile:
- type: string
- description: 'The Dockerfile content.'
- docker_compose_location:
- type: string
- description: 'The Docker Compose location.'
- docker_compose_raw:
- type: string
- description: 'The Docker Compose raw content.'
- 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_domains:
- type: array
- description: 'The Docker Compose domains.'
- watch_paths:
- type: string
- description: 'The watch paths.'
- use_build_server:
- type: boolean
- nullable: true
- description: 'Use build server.'
- type: object
- responses:
- '201':
- description: 'Application created successfully.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /applications/private-deploy-key:
- post:
- tags:
- - Applications
- summary: 'Create (Private - Deploy Key)'
- description: 'Create new application based on a private repository through a Deploy Key.'
- operationId: create-private-deploy-key-application
- requestBody:
- description: 'Application object that needs to be created.'
- required: true
- content:
- application/json:
- schema:
- required:
- - project_uuid
- - server_uuid
- - environment_name
- - environment_uuid
- - private_key_uuid
- - git_repository
- - git_branch
- - build_pack
- - ports_exposes
- properties:
- project_uuid:
- type: string
- description: 'The project UUID.'
- server_uuid:
- type: string
- description: 'The server UUID.'
- environment_name:
- type: string
- description: 'The environment name. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'
- private_key_uuid:
- type: string
- description: 'The private key UUID.'
- git_repository:
- type: string
- description: 'The git repository URL.'
- git_branch:
- type: string
- description: 'The git branch.'
- ports_exposes:
- type: string
- description: 'The ports to expose.'
- destination_uuid:
- type: string
- description: 'The destination UUID.'
- build_pack:
- type: string
- enum: [nixpacks, static, dockerfile, dockercompose]
- description: 'The build pack type.'
- name:
- type: string
- description: 'The application name.'
- description:
- type: string
- description: 'The application description.'
- domains:
- type: string
- description: 'The application domains.'
- 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_tag:
- type: string
- description: 'The docker registry image tag.'
- is_static:
- type: boolean
- description: 'The flag to indicate if the application is static.'
- static_image:
- type: string
- enum: ['nginx:alpine']
- description: 'The static image.'
- install_command:
- type: string
- description: 'The install command.'
- build_command:
- type: string
- description: 'The build command.'
- start_command:
- type: string
- description: 'The start command.'
- ports_mappings:
- type: string
- description: 'The ports mappings.'
- base_directory:
- type: string
- description: 'The base directory for all commands.'
- publish_directory:
- type: string
- description: 'The publish directory.'
- health_check_enabled:
- type: boolean
- description: 'Health check enabled.'
- health_check_path:
- type: string
- description: 'Health check path.'
- health_check_port:
- type: string
- nullable: true
- description: 'Health check port.'
- health_check_host:
- type: string
- nullable: true
- description: 'Health check host.'
- health_check_method:
- type: string
- description: 'Health check method.'
- health_check_return_code:
- type: integer
- description: 'Health check return code.'
- health_check_scheme:
- type: string
- description: 'Health check scheme.'
- health_check_response_text:
- type: string
- nullable: true
- description: 'Health check response text.'
- health_check_interval:
- type: integer
- description: 'Health check interval in seconds.'
- health_check_timeout:
- type: integer
- description: 'Health check timeout in seconds.'
- health_check_retries:
- type: integer
- description: 'Health check retries count.'
- health_check_start_period:
- type: integer
- description: 'Health check start period in seconds.'
- limits_memory:
- type: string
- description: 'Memory limit.'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit.'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness.'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation.'
- limits_cpus:
- type: string
- description: 'CPU limit.'
- limits_cpuset:
- type: string
- nullable: true
- description: 'CPU set.'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares.'
- custom_labels:
- type: string
- description: 'Custom labels.'
- custom_docker_run_options:
- type: string
- description: 'Custom docker run options.'
- post_deployment_command:
- type: string
- description: 'Post deployment command.'
- post_deployment_command_container:
- type: string
- description: 'Post deployment command container.'
- pre_deployment_command:
- type: string
- description: 'Pre deployment command.'
- pre_deployment_command_container:
- type: string
- description: 'Pre deployment command container.'
- manual_webhook_secret_github:
- type: string
- description: 'Manual webhook secret for Github.'
- manual_webhook_secret_gitlab:
- type: string
- description: 'Manual webhook secret for Gitlab.'
- manual_webhook_secret_bitbucket:
- type: string
- description: 'Manual webhook secret for Bitbucket.'
- 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]
- instant_deploy:
- type: boolean
- description: 'The flag to indicate if the application should be deployed instantly.'
- dockerfile:
- type: string
- description: 'The Dockerfile content.'
- docker_compose_location:
- type: string
- description: 'The Docker Compose location.'
- docker_compose_raw:
- type: string
- description: 'The Docker Compose raw content.'
- 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_domains:
- type: array
- description: 'The Docker Compose domains.'
- watch_paths:
- type: string
- description: 'The watch paths.'
- use_build_server:
- type: boolean
- nullable: true
- description: 'Use build server.'
- type: object
- responses:
- '201':
- description: 'Application created successfully.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /applications/dockerfile:
- post:
- tags:
- - Applications
- summary: 'Create (Dockerfile)'
- description: 'Create new application based on a simple Dockerfile.'
- operationId: create-dockerfile-application
- requestBody:
- description: 'Application object that needs to be created.'
- required: true
- content:
- application/json:
- schema:
- required:
- - project_uuid
- - server_uuid
- - environment_name
- - environment_uuid
- - dockerfile
- properties:
- project_uuid:
- type: string
- description: 'The project UUID.'
- server_uuid:
- type: string
- description: 'The server UUID.'
- environment_name:
- type: string
- description: 'The environment name. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'
- dockerfile:
- type: string
- description: 'The Dockerfile content.'
- build_pack:
- type: string
- enum: [nixpacks, static, dockerfile, dockercompose]
- description: 'The build pack type.'
- ports_exposes:
- type: string
- description: 'The ports to expose.'
- destination_uuid:
- type: string
- description: 'The destination UUID.'
- name:
- type: string
- description: 'The application name.'
- description:
- type: string
- description: 'The application description.'
- domains:
- type: string
- description: 'The application domains.'
- docker_registry_image_name:
- type: string
- description: 'The docker registry image name.'
- docker_registry_image_tag:
- type: string
- description: 'The docker registry image tag.'
- ports_mappings:
- type: string
- description: 'The ports mappings.'
- base_directory:
- type: string
- description: 'The base directory for all commands.'
- health_check_enabled:
- type: boolean
- description: 'Health check enabled.'
- health_check_path:
- type: string
- description: 'Health check path.'
- health_check_port:
- type: string
- nullable: true
- description: 'Health check port.'
- health_check_host:
- type: string
- nullable: true
- description: 'Health check host.'
- health_check_method:
- type: string
- description: 'Health check method.'
- health_check_return_code:
- type: integer
- description: 'Health check return code.'
- health_check_scheme:
- type: string
- description: 'Health check scheme.'
- health_check_response_text:
- type: string
- nullable: true
- description: 'Health check response text.'
- health_check_interval:
- type: integer
- description: 'Health check interval in seconds.'
- health_check_timeout:
- type: integer
- description: 'Health check timeout in seconds.'
- health_check_retries:
- type: integer
- description: 'Health check retries count.'
- health_check_start_period:
- type: integer
- description: 'Health check start period in seconds.'
- limits_memory:
- type: string
- description: 'Memory limit.'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit.'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness.'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation.'
- limits_cpus:
- type: string
- description: 'CPU limit.'
- limits_cpuset:
- type: string
- nullable: true
- description: 'CPU set.'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares.'
- custom_labels:
- type: string
- description: 'Custom labels.'
- custom_docker_run_options:
- type: string
- description: 'Custom docker run options.'
- post_deployment_command:
- type: string
- description: 'Post deployment command.'
- post_deployment_command_container:
- type: string
- description: 'Post deployment command container.'
- pre_deployment_command:
- type: string
- description: 'Pre deployment command.'
- pre_deployment_command_container:
- type: string
- description: 'Pre deployment command container.'
- manual_webhook_secret_github:
- type: string
- description: 'Manual webhook secret for Github.'
- manual_webhook_secret_gitlab:
- type: string
- description: 'Manual webhook secret for Gitlab.'
- manual_webhook_secret_bitbucket:
- type: string
- description: 'Manual webhook secret for Bitbucket.'
- 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]
- instant_deploy:
- type: boolean
- description: 'The flag to indicate if the application should be deployed instantly.'
- use_build_server:
- type: boolean
- nullable: true
- description: 'Use build server.'
- type: object
- responses:
- '201':
- description: 'Application created successfully.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /applications/dockerimage:
- post:
- tags:
- - Applications
- summary: 'Create (Docker Image)'
- description: 'Create new application based on a prebuilt docker image'
- operationId: create-dockerimage-application
- requestBody:
- description: 'Application object that needs to be created.'
- required: true
- content:
- application/json:
- schema:
- required:
- - project_uuid
- - server_uuid
- - environment_name
- - environment_uuid
- - docker_registry_image_name
- - ports_exposes
- properties:
- project_uuid:
- type: string
- description: 'The project UUID.'
- server_uuid:
- type: string
- description: 'The server UUID.'
- environment_name:
- type: string
- description: 'The environment name. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'
- docker_registry_image_name:
- type: string
- description: 'The docker registry image name.'
- docker_registry_image_tag:
- type: string
- description: 'The docker registry image tag.'
- ports_exposes:
- type: string
- description: 'The ports to expose.'
- destination_uuid:
- type: string
- description: 'The destination UUID.'
- name:
- type: string
- description: 'The application name.'
- description:
- type: string
- description: 'The application description.'
- domains:
- type: string
- description: 'The application domains.'
- ports_mappings:
- type: string
- description: 'The ports mappings.'
- health_check_enabled:
- type: boolean
- description: 'Health check enabled.'
- health_check_path:
- type: string
- description: 'Health check path.'
- health_check_port:
- type: string
- nullable: true
- description: 'Health check port.'
- health_check_host:
- type: string
- nullable: true
- description: 'Health check host.'
- health_check_method:
- type: string
- description: 'Health check method.'
- health_check_return_code:
- type: integer
- description: 'Health check return code.'
- health_check_scheme:
- type: string
- description: 'Health check scheme.'
- health_check_response_text:
- type: string
- nullable: true
- description: 'Health check response text.'
- health_check_interval:
- type: integer
- description: 'Health check interval in seconds.'
- health_check_timeout:
- type: integer
- description: 'Health check timeout in seconds.'
- health_check_retries:
- type: integer
- description: 'Health check retries count.'
- health_check_start_period:
- type: integer
- description: 'Health check start period in seconds.'
- limits_memory:
- type: string
- description: 'Memory limit.'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit.'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness.'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation.'
- limits_cpus:
- type: string
- description: 'CPU limit.'
- limits_cpuset:
- type: string
- nullable: true
- description: 'CPU set.'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares.'
- custom_labels:
- type: string
- description: 'Custom labels.'
- custom_docker_run_options:
- type: string
- description: 'Custom docker run options.'
- post_deployment_command:
- type: string
- description: 'Post deployment command.'
- post_deployment_command_container:
- type: string
- description: 'Post deployment command container.'
- pre_deployment_command:
- type: string
- description: 'Pre deployment command.'
- pre_deployment_command_container:
- type: string
- description: 'Pre deployment command container.'
- manual_webhook_secret_github:
- type: string
- description: 'Manual webhook secret for Github.'
- manual_webhook_secret_gitlab:
- type: string
- description: 'Manual webhook secret for Gitlab.'
- manual_webhook_secret_bitbucket:
- type: string
- description: 'Manual webhook secret for Bitbucket.'
- 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]
- instant_deploy:
- type: boolean
- description: 'The flag to indicate if the application should be deployed instantly.'
- use_build_server:
- type: boolean
- nullable: true
- description: 'Use build server.'
- type: object
- responses:
- '201':
- description: 'Application created successfully.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /applications/dockercompose:
- post:
- tags:
- - Applications
- summary: 'Create (Docker Compose)'
- description: 'Create new application based on a docker-compose file.'
- operationId: create-dockercompose-application
- requestBody:
- description: 'Application object that needs to be created.'
- required: true
- content:
- application/json:
- schema:
- required:
- - project_uuid
- - server_uuid
- - environment_name
- - environment_uuid
- - docker_compose_raw
- properties:
- project_uuid:
- type: string
- description: 'The project UUID.'
- server_uuid:
- type: string
- description: 'The server UUID.'
- environment_name:
- type: string
- description: 'The environment name. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'The environment UUID. You need to provide at least one of environment_name or environment_uuid.'
- docker_compose_raw:
- type: string
- description: 'The Docker Compose raw content.'
- destination_uuid:
- type: string
- description: 'The destination UUID if the server has more than one destinations.'
- name:
- type: string
- description: 'The application name.'
- description:
- type: string
- description: 'The application description.'
- instant_deploy:
- type: boolean
- description: 'The flag to indicate if the application should be deployed instantly.'
- use_build_server:
- type: boolean
- nullable: true
- description: 'Use build server.'
- type: object
- responses:
- '201':
- description: 'Application created successfully.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string }
- type: object
- '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: get-application-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Get application by UUID.'
- 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: []
- delete:
- tags:
- - Applications
- summary: Delete
- description: 'Delete application by UUID.'
- operationId: delete-application-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- -
- name: delete_configurations
- in: query
- description: 'Delete configurations.'
- required: false
- schema:
- type: boolean
- default: true
- -
- name: delete_volumes
- in: query
- description: 'Delete volumes.'
- required: false
- schema:
- type: boolean
- default: true
- -
- name: docker_cleanup
- in: query
- description: 'Run docker cleanup.'
- required: false
- schema:
- type: boolean
- default: true
- -
- name: delete_connected_networks
- in: query
- description: 'Delete connected networks.'
- required: false
- schema:
- type: boolean
- default: true
- responses:
- '200':
- description: 'Application deleted.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Application deleted.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- patch:
- tags:
- - Applications
- summary: Update
- description: 'Update application by UUID.'
- operationId: update-application-by-uuid
- requestBody:
- description: 'Application updated.'
- required: true
- content:
- application/json:
- schema:
- properties:
- project_uuid:
- type: string
- description: 'The project UUID.'
- server_uuid:
- type: string
- description: 'The server UUID.'
- environment_name:
- type: string
- description: 'The environment name.'
- github_app_uuid:
- type: string
- description: 'The Github App UUID.'
- git_repository:
- type: string
- description: 'The git repository URL.'
- git_branch:
- type: string
- description: 'The git branch.'
- ports_exposes:
- type: string
- description: 'The ports to expose.'
- destination_uuid:
- type: string
- description: 'The destination UUID.'
- build_pack:
- type: string
- enum: [nixpacks, static, dockerfile, dockercompose]
- description: 'The build pack type.'
- name:
- type: string
- description: 'The application name.'
- description:
- type: string
- description: 'The application description.'
- domains:
- type: string
- description: 'The application domains.'
- 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_tag:
- type: string
- description: 'The docker registry image tag.'
- is_static:
- type: boolean
- description: 'The flag to indicate if the application is static.'
- install_command:
- type: string
- description: 'The install command.'
- build_command:
- type: string
- description: 'The build command.'
- start_command:
- type: string
- description: 'The start command.'
- ports_mappings:
- type: string
- description: 'The ports mappings.'
- base_directory:
- type: string
- description: 'The base directory for all commands.'
- publish_directory:
- type: string
- description: 'The publish directory.'
- health_check_enabled:
- type: boolean
- description: 'Health check enabled.'
- health_check_path:
- type: string
- description: 'Health check path.'
- health_check_port:
- type: string
- nullable: true
- description: 'Health check port.'
- health_check_host:
- type: string
- nullable: true
- description: 'Health check host.'
- health_check_method:
- type: string
- description: 'Health check method.'
- health_check_return_code:
- type: integer
- description: 'Health check return code.'
- health_check_scheme:
- type: string
- description: 'Health check scheme.'
- health_check_response_text:
- type: string
- nullable: true
- description: 'Health check response text.'
- health_check_interval:
- type: integer
- description: 'Health check interval in seconds.'
- health_check_timeout:
- type: integer
- description: 'Health check timeout in seconds.'
- health_check_retries:
- type: integer
- description: 'Health check retries count.'
- health_check_start_period:
- type: integer
- description: 'Health check start period in seconds.'
- limits_memory:
- type: string
- description: 'Memory limit.'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit.'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness.'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation.'
- limits_cpus:
- type: string
- description: 'CPU limit.'
- limits_cpuset:
- type: string
- nullable: true
- description: 'CPU set.'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares.'
- custom_labels:
- type: string
- description: 'Custom labels.'
- custom_docker_run_options:
- type: string
- description: 'Custom docker run options.'
- post_deployment_command:
- type: string
- description: 'Post deployment command.'
- post_deployment_command_container:
- type: string
- description: 'Post deployment command container.'
- pre_deployment_command:
- type: string
- description: 'Pre deployment command.'
- pre_deployment_command_container:
- type: string
- description: 'Pre deployment command container.'
- manual_webhook_secret_github:
- type: string
- description: 'Manual webhook secret for Github.'
- manual_webhook_secret_gitlab:
- type: string
- description: 'Manual webhook secret for Gitlab.'
- manual_webhook_secret_bitbucket:
- type: string
- description: 'Manual webhook secret for Bitbucket.'
- 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]
- instant_deploy:
- type: boolean
- description: 'The flag to indicate if the application should be deployed instantly.'
- dockerfile:
- type: string
- description: 'The Dockerfile content.'
- docker_compose_location:
- type: string
- description: 'The Docker Compose location.'
- docker_compose_raw:
- type: string
- description: 'The Docker Compose raw content.'
- 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_domains:
- type: array
- description: 'The Docker Compose domains.'
- watch_paths:
- type: string
- description: 'The watch paths.'
- use_build_server:
- type: boolean
- nullable: true
- description: 'Use build server.'
- type: object
- responses:
- '200':
- description: 'Application updated.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/applications/{uuid}/envs':
- get:
- tags:
- - Applications
- summary: 'List Envs'
- description: 'List all envs by application UUID.'
- operationId: list-envs-by-application-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'All environment variables by application UUID.'
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/EnvironmentVariable'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- post:
- tags:
- - Applications
- summary: 'Create Env'
- description: 'Create env by application UUID.'
- operationId: create-env-by-application-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- requestBody:
- description: 'Env created.'
- required: true
- content:
- application/json:
- schema:
- properties:
- key:
- type: string
- description: 'The key of the environment variable.'
- value:
- type: string
- description: 'The value of the environment variable.'
- is_preview:
- type: boolean
- description: 'The flag to indicate if the environment variable is used in preview deployments.'
- is_build_time:
- type: boolean
- description: 'The flag to indicate if the environment variable is used in build time.'
- is_literal:
- type: boolean
- description: 'The flag to indicate if the environment variable is a literal, nothing espaced.'
- is_multiline:
- type: boolean
- description: 'The flag to indicate if the environment variable is multiline.'
- is_shown_once:
- type: boolean
- description: "The flag to indicate if the environment variable's value is shown on the UI."
- type: object
- responses:
- '201':
- description: 'Environment variable created.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string, example: nc0k04gk8g0cgsk440g0koko }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- patch:
- tags:
- - Applications
- summary: 'Update Env'
- description: 'Update env by application UUID.'
- operationId: update-env-by-application-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- requestBody:
- description: 'Env updated.'
- required: true
- content:
- application/json:
- schema:
- required:
- - key
- - value
- properties:
- key:
- type: string
- description: 'The key of the environment variable.'
- value:
- type: string
- description: 'The value of the environment variable.'
- is_preview:
- type: boolean
- description: 'The flag to indicate if the environment variable is used in preview deployments.'
- is_build_time:
- type: boolean
- description: 'The flag to indicate if the environment variable is used in build time.'
- is_literal:
- type: boolean
- description: 'The flag to indicate if the environment variable is a literal, nothing espaced.'
- is_multiline:
- type: boolean
- description: 'The flag to indicate if the environment variable is multiline.'
- is_shown_once:
- type: boolean
- description: "The flag to indicate if the environment variable's value is shown on the UI."
- type: object
- responses:
- '201':
- description: 'Environment variable updated.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Environment variable updated.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/applications/{uuid}/envs/bulk':
- patch:
- tags:
- - Applications
- summary: 'Update Envs (Bulk)'
- description: 'Update multiple envs by application UUID.'
- operationId: update-envs-by-application-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- requestBody:
- description: 'Bulk envs updated.'
- required: true
- content:
- application/json:
- schema:
- required:
- - data
- properties:
- data:
- type: array
- items: { properties: { key: { type: string, description: 'The key of the environment variable.' }, value: { type: string, description: 'The value of the environment variable.' }, is_preview: { type: boolean, description: 'The flag to indicate if the environment variable is used in preview deployments.' }, is_build_time: { type: boolean, description: 'The flag to indicate if the environment variable is used in build time.' }, is_literal: { type: boolean, description: 'The flag to indicate if the environment variable is a literal, nothing espaced.' }, is_multiline: { type: boolean, description: 'The flag to indicate if the environment variable is multiline.' }, is_shown_once: { type: boolean, description: "The flag to indicate if the environment variable's value is shown on the UI." } }, type: object }
- type: object
- responses:
- '201':
- description: 'Environment variables updated.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Environment variables updated.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/applications/{uuid}/envs/{env_uuid}':
- delete:
- tags:
- - Applications
- summary: 'Delete Env'
- description: 'Delete env by UUID.'
- operationId: delete-env-by-application-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- -
- name: env_uuid
- in: path
- description: 'UUID of the environment variable.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Environment variable deleted.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Environment variable deleted.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/applications/{uuid}/start':
- get:
- tags:
- - Applications
- summary: Start
- description: 'Start application. `Post` request is also accepted.'
- operationId: start-application-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- -
- name: force
- in: query
- description: 'Force rebuild.'
- schema:
- type: boolean
- default: false
- -
- name: instant_deploy
- in: query
- description: 'Instant deploy (skip queuing).'
- schema:
- type: boolean
- default: false
- responses:
- '200':
- description: 'Start application.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Deployment request queued.', description: Message. }
- deployment_uuid: { type: string, example: doogksw, description: 'UUID of the deployment.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/applications/{uuid}/stop':
- get:
- tags:
- - Applications
- summary: Stop
- description: 'Stop application. `Post` request is also accepted.'
- operationId: stop-application-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Stop application.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Application stopping request queued.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/applications/{uuid}/restart':
- get:
- tags:
- - Applications
- summary: Restart
- description: 'Restart application. `Post` request is also accepted.'
- operationId: restart-application-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Restart application.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Restart request queued.' }
- deployment_uuid: { type: string, example: doogksw, description: 'UUID of the deployment.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/applications/{uuid}/execute':
- post:
- tags:
- - Applications
- summary: 'Execute Command'
- description: "Execute a command on the application's current container."
- operationId: execute-command-application
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- requestBody:
- description: 'Command to execute.'
- required: true
- content:
- application/json:
- schema:
- properties:
- command:
- type: string
- description: 'Command to execute.'
- type: object
- responses:
- '200':
- description: "Execute a command on the application's current container."
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Command executed.' }
- response: { type: string }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- /databases:
- get:
- tags:
- - Databases
- summary: List
- description: 'List all databases.'
- operationId: list-databases
- responses:
- '200':
- description: 'Get all databases'
- 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: []
- '/databases/{uuid}':
- get:
- tags:
- - Databases
- summary: Get
- description: 'Get database by UUID.'
- operationId: get-database-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the database.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Get all databases'
- 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'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- delete:
- tags:
- - Databases
- summary: Delete
- description: 'Delete database by UUID.'
- operationId: delete-database-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the database.'
- required: true
- schema:
- type: string
- format: uuid
- -
- name: delete_configurations
- in: query
- description: 'Delete configurations.'
- required: false
- schema:
- type: boolean
- default: true
- -
- name: delete_volumes
- in: query
- description: 'Delete volumes.'
- required: false
- schema:
- type: boolean
- default: true
- -
- name: docker_cleanup
- in: query
- description: 'Run docker cleanup.'
- required: false
- schema:
- type: boolean
- default: true
- -
- name: delete_connected_networks
- in: query
- description: 'Delete connected networks.'
- required: false
- schema:
- type: boolean
- default: true
- responses:
- '200':
- description: 'Database deleted.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Database deleted.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- patch:
- tags:
- - Databases
- summary: Update
- description: 'Update database by UUID.'
- operationId: update-database-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the database.'
- required: true
- schema:
- type: string
- format: uuid
- requestBody:
- description: 'Database data'
- required: true
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- description: 'Name of the database'
- description:
- type: string
- description: 'Description of the database'
- image:
- type: string
- description: 'Docker Image of the database'
- is_public:
- type: boolean
- description: 'Is the database public?'
- public_port:
- type: integer
- description: 'Public port of the database'
- limits_memory:
- type: string
- description: 'Memory limit of the database'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit of the database'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness of the database'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation of the database'
- limits_cpus:
- type: string
- description: 'CPU limit of the database'
- limits_cpuset:
- type: string
- description: 'CPU set of the database'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares of the database'
- postgres_user:
- type: string
- description: 'PostgreSQL user'
- postgres_password:
- type: string
- description: 'PostgreSQL password'
- postgres_db:
- type: string
- description: 'PostgreSQL database'
- postgres_initdb_args:
- type: string
- description: 'PostgreSQL initdb args'
- postgres_host_auth_method:
- type: string
- description: 'PostgreSQL host auth method'
- postgres_conf:
- type: string
- description: 'PostgreSQL conf'
- clickhouse_admin_user:
- type: string
- description: 'Clickhouse admin user'
- clickhouse_admin_password:
- type: string
- description: 'Clickhouse admin password'
- dragonfly_password:
- type: string
- description: 'DragonFly password'
- redis_password:
- type: string
- description: 'Redis password'
- redis_conf:
- type: string
- description: 'Redis conf'
- keydb_password:
- type: string
- description: 'KeyDB password'
- keydb_conf:
- type: string
- description: 'KeyDB conf'
- mariadb_conf:
- type: string
- description: 'MariaDB conf'
- mariadb_root_password:
- type: string
- description: 'MariaDB root password'
- mariadb_user:
- type: string
- description: 'MariaDB user'
- mariadb_password:
- type: string
- description: 'MariaDB password'
- mariadb_database:
- type: string
- description: 'MariaDB database'
- mongo_conf:
- type: string
- description: 'Mongo conf'
- mongo_initdb_root_username:
- type: string
- description: 'Mongo initdb root username'
- mongo_initdb_root_password:
- type: string
- description: 'Mongo initdb root password'
- mongo_initdb_database:
- type: string
- description: 'Mongo initdb init database'
- mysql_root_password:
- type: string
- description: 'MySQL root password'
- mysql_password:
- type: string
- description: 'MySQL password'
- mysql_user:
- type: string
- description: 'MySQL user'
- mysql_database:
- type: string
- description: 'MySQL database'
- mysql_conf:
- type: string
- description: 'MySQL conf'
- type: object
- responses:
- '200':
- description: 'Database updated'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- /databases/postgresql:
- post:
- tags:
- - Databases
- summary: 'Create (PostgreSQL)'
- description: 'Create a new PostgreSQL database.'
- operationId: create-database-postgresql
- requestBody:
- description: 'Database data'
- required: true
- content:
- application/json:
- schema:
- required:
- - server_uuid
- - project_uuid
- - environment_name
- - environment_uuid
- properties:
- server_uuid:
- type: string
- description: 'UUID of the server'
- project_uuid:
- type: string
- description: 'UUID of the project'
- environment_name:
- type: string
- description: 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'
- postgres_user:
- type: string
- description: 'PostgreSQL user'
- postgres_password:
- type: string
- description: 'PostgreSQL password'
- postgres_db:
- type: string
- description: 'PostgreSQL database'
- postgres_initdb_args:
- type: string
- description: 'PostgreSQL initdb args'
- postgres_host_auth_method:
- type: string
- description: 'PostgreSQL host auth method'
- postgres_conf:
- type: string
- description: 'PostgreSQL conf'
- destination_uuid:
- type: string
- description: 'UUID of the destination if the server has multiple destinations'
- name:
- type: string
- description: 'Name of the database'
- description:
- type: string
- description: 'Description of the database'
- image:
- type: string
- description: 'Docker Image of the database'
- is_public:
- type: boolean
- description: 'Is the database public?'
- public_port:
- type: integer
- description: 'Public port of the database'
- limits_memory:
- type: string
- description: 'Memory limit of the database'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit of the database'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness of the database'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation of the database'
- limits_cpus:
- type: string
- description: 'CPU limit of the database'
- limits_cpuset:
- type: string
- description: 'CPU set of the database'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares of the database'
- instant_deploy:
- type: boolean
- description: 'Instant deploy the database'
- type: object
- responses:
- '200':
- description: 'Database updated'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /databases/clickhouse:
- post:
- tags:
- - Databases
- summary: 'Create (Clickhouse)'
- description: 'Create a new Clickhouse database.'
- operationId: create-database-clickhouse
- requestBody:
- description: 'Database data'
- required: true
- content:
- application/json:
- schema:
- required:
- - server_uuid
- - project_uuid
- - environment_name
- - environment_uuid
- properties:
- server_uuid:
- type: string
- description: 'UUID of the server'
- project_uuid:
- type: string
- description: 'UUID of the project'
- environment_name:
- type: string
- description: 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'
- destination_uuid:
- type: string
- description: 'UUID of the destination if the server has multiple destinations'
- clickhouse_admin_user:
- type: string
- description: 'Clickhouse admin user'
- clickhouse_admin_password:
- type: string
- description: 'Clickhouse admin password'
- name:
- type: string
- description: 'Name of the database'
- description:
- type: string
- description: 'Description of the database'
- image:
- type: string
- description: 'Docker Image of the database'
- is_public:
- type: boolean
- description: 'Is the database public?'
- public_port:
- type: integer
- description: 'Public port of the database'
- limits_memory:
- type: string
- description: 'Memory limit of the database'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit of the database'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness of the database'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation of the database'
- limits_cpus:
- type: string
- description: 'CPU limit of the database'
- limits_cpuset:
- type: string
- description: 'CPU set of the database'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares of the database'
- instant_deploy:
- type: boolean
- description: 'Instant deploy the database'
- type: object
- responses:
- '200':
- description: 'Database updated'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /databases/dragonfly:
- post:
- tags:
- - Databases
- summary: 'Create (DragonFly)'
- description: 'Create a new DragonFly database.'
- operationId: create-database-dragonfly
- requestBody:
- description: 'Database data'
- required: true
- content:
- application/json:
- schema:
- required:
- - server_uuid
- - project_uuid
- - environment_name
- - environment_uuid
- properties:
- server_uuid:
- type: string
- description: 'UUID of the server'
- project_uuid:
- type: string
- description: 'UUID of the project'
- environment_name:
- type: string
- description: 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'
- destination_uuid:
- type: string
- description: 'UUID of the destination if the server has multiple destinations'
- dragonfly_password:
- type: string
- description: 'DragonFly password'
- name:
- type: string
- description: 'Name of the database'
- description:
- type: string
- description: 'Description of the database'
- image:
- type: string
- description: 'Docker Image of the database'
- is_public:
- type: boolean
- description: 'Is the database public?'
- public_port:
- type: integer
- description: 'Public port of the database'
- limits_memory:
- type: string
- description: 'Memory limit of the database'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit of the database'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness of the database'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation of the database'
- limits_cpus:
- type: string
- description: 'CPU limit of the database'
- limits_cpuset:
- type: string
- description: 'CPU set of the database'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares of the database'
- instant_deploy:
- type: boolean
- description: 'Instant deploy the database'
- type: object
- responses:
- '200':
- description: 'Database updated'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /databases/redis:
- post:
- tags:
- - Databases
- summary: 'Create (Redis)'
- description: 'Create a new Redis database.'
- operationId: create-database-redis
- requestBody:
- description: 'Database data'
- required: true
- content:
- application/json:
- schema:
- required:
- - server_uuid
- - project_uuid
- - environment_name
- - environment_uuid
- properties:
- server_uuid:
- type: string
- description: 'UUID of the server'
- project_uuid:
- type: string
- description: 'UUID of the project'
- environment_name:
- type: string
- description: 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'
- destination_uuid:
- type: string
- description: 'UUID of the destination if the server has multiple destinations'
- redis_password:
- type: string
- description: 'Redis password'
- redis_conf:
- type: string
- description: 'Redis conf'
- name:
- type: string
- description: 'Name of the database'
- description:
- type: string
- description: 'Description of the database'
- image:
- type: string
- description: 'Docker Image of the database'
- is_public:
- type: boolean
- description: 'Is the database public?'
- public_port:
- type: integer
- description: 'Public port of the database'
- limits_memory:
- type: string
- description: 'Memory limit of the database'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit of the database'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness of the database'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation of the database'
- limits_cpus:
- type: string
- description: 'CPU limit of the database'
- limits_cpuset:
- type: string
- description: 'CPU set of the database'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares of the database'
- instant_deploy:
- type: boolean
- description: 'Instant deploy the database'
- type: object
- responses:
- '200':
- description: 'Database updated'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /databases/keydb:
- post:
- tags:
- - Databases
- summary: 'Create (KeyDB)'
- description: 'Create a new KeyDB database.'
- operationId: create-database-keydb
- requestBody:
- description: 'Database data'
- required: true
- content:
- application/json:
- schema:
- required:
- - server_uuid
- - project_uuid
- - environment_name
- - environment_uuid
- properties:
- server_uuid:
- type: string
- description: 'UUID of the server'
- project_uuid:
- type: string
- description: 'UUID of the project'
- environment_name:
- type: string
- description: 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'
- destination_uuid:
- type: string
- description: 'UUID of the destination if the server has multiple destinations'
- keydb_password:
- type: string
- description: 'KeyDB password'
- keydb_conf:
- type: string
- description: 'KeyDB conf'
- name:
- type: string
- description: 'Name of the database'
- description:
- type: string
- description: 'Description of the database'
- image:
- type: string
- description: 'Docker Image of the database'
- is_public:
- type: boolean
- description: 'Is the database public?'
- public_port:
- type: integer
- description: 'Public port of the database'
- limits_memory:
- type: string
- description: 'Memory limit of the database'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit of the database'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness of the database'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation of the database'
- limits_cpus:
- type: string
- description: 'CPU limit of the database'
- limits_cpuset:
- type: string
- description: 'CPU set of the database'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares of the database'
- instant_deploy:
- type: boolean
- description: 'Instant deploy the database'
- type: object
- responses:
- '200':
- description: 'Database updated'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /databases/mariadb:
- post:
- tags:
- - Databases
- summary: 'Create (MariaDB)'
- description: 'Create a new MariaDB database.'
- operationId: create-database-mariadb
- requestBody:
- description: 'Database data'
- required: true
- content:
- application/json:
- schema:
- required:
- - server_uuid
- - project_uuid
- - environment_name
- - environment_uuid
- properties:
- server_uuid:
- type: string
- description: 'UUID of the server'
- project_uuid:
- type: string
- description: 'UUID of the project'
- environment_name:
- type: string
- description: 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'
- destination_uuid:
- type: string
- description: 'UUID of the destination if the server has multiple destinations'
- mariadb_conf:
- type: string
- description: 'MariaDB conf'
- mariadb_root_password:
- type: string
- description: 'MariaDB root password'
- mariadb_user:
- type: string
- description: 'MariaDB user'
- mariadb_password:
- type: string
- description: 'MariaDB password'
- mariadb_database:
- type: string
- description: 'MariaDB database'
- name:
- type: string
- description: 'Name of the database'
- description:
- type: string
- description: 'Description of the database'
- image:
- type: string
- description: 'Docker Image of the database'
- is_public:
- type: boolean
- description: 'Is the database public?'
- public_port:
- type: integer
- description: 'Public port of the database'
- limits_memory:
- type: string
- description: 'Memory limit of the database'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit of the database'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness of the database'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation of the database'
- limits_cpus:
- type: string
- description: 'CPU limit of the database'
- limits_cpuset:
- type: string
- description: 'CPU set of the database'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares of the database'
- instant_deploy:
- type: boolean
- description: 'Instant deploy the database'
- type: object
- responses:
- '200':
- description: 'Database updated'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /databases/mysql:
- post:
- tags:
- - Databases
- summary: 'Create (MySQL)'
- description: 'Create a new MySQL database.'
- operationId: create-database-mysql
- requestBody:
- description: 'Database data'
- required: true
- content:
- application/json:
- schema:
- required:
- - server_uuid
- - project_uuid
- - environment_name
- - environment_uuid
- properties:
- server_uuid:
- type: string
- description: 'UUID of the server'
- project_uuid:
- type: string
- description: 'UUID of the project'
- environment_name:
- type: string
- description: 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'
- destination_uuid:
- type: string
- description: 'UUID of the destination if the server has multiple destinations'
- mysql_root_password:
- type: string
- description: 'MySQL root password'
- mysql_password:
- type: string
- description: 'MySQL password'
- mysql_user:
- type: string
- description: 'MySQL user'
- mysql_database:
- type: string
- description: 'MySQL database'
- mysql_conf:
- type: string
- description: 'MySQL conf'
- name:
- type: string
- description: 'Name of the database'
- description:
- type: string
- description: 'Description of the database'
- image:
- type: string
- description: 'Docker Image of the database'
- is_public:
- type: boolean
- description: 'Is the database public?'
- public_port:
- type: integer
- description: 'Public port of the database'
- limits_memory:
- type: string
- description: 'Memory limit of the database'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit of the database'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness of the database'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation of the database'
- limits_cpus:
- type: string
- description: 'CPU limit of the database'
- limits_cpuset:
- type: string
- description: 'CPU set of the database'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares of the database'
- instant_deploy:
- type: boolean
- description: 'Instant deploy the database'
- type: object
- responses:
- '200':
- description: 'Database updated'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /databases/mongodb:
- post:
- tags:
- - Databases
- summary: 'Create (MongoDB)'
- description: 'Create a new MongoDB database.'
- operationId: create-database-mongodb
- requestBody:
- description: 'Database data'
- required: true
- content:
- application/json:
- schema:
- required:
- - server_uuid
- - project_uuid
- - environment_name
- - environment_uuid
- properties:
- server_uuid:
- type: string
- description: 'UUID of the server'
- project_uuid:
- type: string
- description: 'UUID of the project'
- environment_name:
- type: string
- description: 'Name of the environment. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'UUID of the environment. You need to provide at least one of environment_name or environment_uuid.'
- destination_uuid:
- type: string
- description: 'UUID of the destination if the server has multiple destinations'
- mongo_conf:
- type: string
- description: 'MongoDB conf'
- mongo_initdb_root_username:
- type: string
- description: 'MongoDB initdb root username'
- name:
- type: string
- description: 'Name of the database'
- description:
- type: string
- description: 'Description of the database'
- image:
- type: string
- description: 'Docker Image of the database'
- is_public:
- type: boolean
- description: 'Is the database public?'
- public_port:
- type: integer
- description: 'Public port of the database'
- limits_memory:
- type: string
- description: 'Memory limit of the database'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit of the database'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness of the database'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation of the database'
- limits_cpus:
- type: string
- description: 'CPU limit of the database'
- limits_cpuset:
- type: string
- description: 'CPU set of the database'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares of the database'
- instant_deploy:
- type: boolean
- description: 'Instant deploy the database'
- type: object
- responses:
- '200':
- description: 'Database updated'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- '/databases/{uuid}/start':
- get:
- tags:
- - Databases
- summary: Start
- description: 'Start database. `Post` request is also accepted.'
- operationId: start-database-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the database.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Start database.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Database starting request queued.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/databases/{uuid}/stop':
- get:
- tags:
- - Databases
- summary: Stop
- description: 'Stop database. `Post` request is also accepted.'
- operationId: stop-database-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the database.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Stop database.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Database stopping request queued.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/databases/{uuid}/restart':
- get:
- tags:
- - Databases
- summary: Restart
- description: 'Restart database. `Post` request is also accepted.'
- operationId: restart-database-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the database.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Restart database.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Database restaring request queued.' }
- type: object
- '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: list-deployments
- 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: get-deployment-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'Deployment UUID'
- required: true
- schema:
- type: string
- 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: deploy-by-tag-or-uuid
- 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
- description: 'Get Coolify version.'
- operationId: version
- responses:
- '200':
- description: 'Returns the version of the application'
- content:
- application/json:
- schema:
- type: string
- example: v4.0.0
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /enable:
- get:
- summary: 'Enable API'
- description: 'Enable API (only with root permissions).'
- operationId: enable-api
- responses:
- '200':
- description: 'Enable API.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'API enabled.' }
- type: object
- '403':
- description: 'You are not allowed to enable the API.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'You are not allowed to enable the API.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /disable:
- get:
- summary: 'Disable API'
- description: 'Disable API (only with root permissions).'
- operationId: disable-api
- responses:
- '200':
- description: 'Disable API.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'API disabled.' }
- type: object
- '403':
- description: 'You are not allowed to disable the API.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'You are not allowed to disable the API.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- /health:
- get:
- summary: Healthcheck
- description: 'Healthcheck endpoint.'
- operationId: healthcheck
- responses:
- '200':
- description: 'Healthcheck endpoint.'
- content:
- application/json:
- schema:
- type: string
- example: OK
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- /projects:
- get:
- tags:
- - Projects
- summary: List
- description: 'List projects.'
- operationId: list-projects
- 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: []
- post:
- tags:
- - Projects
- summary: Create
- description: 'Create Project.'
- operationId: create-project
- requestBody:
- description: 'Project created.'
- required: true
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- description: 'The name of the project.'
- description:
- type: string
- description: 'The description of the project.'
- type: object
- responses:
- '201':
- description: 'Project created.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string, example: og888os, description: 'The UUID of the project.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/projects/{uuid}':
- get:
- tags:
- - Projects
- summary: Get
- description: 'Get project by UUID.'
- operationId: get-project-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'Project UUID'
- required: true
- schema:
- type: string
- 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: []
- delete:
- tags:
- - Projects
- summary: Delete
- description: 'Delete project by UUID.'
- operationId: delete-project-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the application.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Project deleted.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Project deleted.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- patch:
- tags:
- - Projects
- summary: Update
- description: 'Update Project.'
- operationId: update-project-by-uuid
- requestBody:
- description: 'Project updated.'
- required: true
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- description: 'The name of the project.'
- description:
- type: string
- description: 'The description of the project.'
- type: object
- responses:
- '201':
- description: 'Project updated.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string, example: og888os }
- name: { type: string, example: 'Project Name' }
- description: { type: string, example: 'Project Description' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/projects/{uuid}/{environment_name_or_uuid}':
- get:
- tags:
- - Projects
- summary: Environment
- description: 'Get environment by name or UUID.'
- operationId: get-environment-by-name-or-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'Project UUID'
- required: true
- schema:
- type: string
- -
- name: environment_name_or_uuid
- in: path
- description: 'Environment name or UUID'
- required: true
- schema:
- type: string
- responses:
- '200':
- description: 'Environment 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: list-resources
- 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: list-private-keys
- 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: create-private-key
- 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: update-private-key
- 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: get-private-key-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'Private Key UUID'
- required: true
- schema:
- type: string
- responses:
- '200':
- description: 'Get all private keys.'
- content:
- application/json:
- schema:
- $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: delete-private-key-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'Private Key UUID'
- required: true
- schema:
- type: string
- 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: list-servers
- 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: []
- post:
- tags:
- - Servers
- summary: Create
- description: 'Create Server.'
- operationId: create-server
- requestBody:
- description: 'Server created.'
- required: true
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- example: 'My Server'
- description: 'The name of the server.'
- description:
- type: string
- example: 'My Server Description'
- description: 'The description of the server.'
- ip:
- type: string
- example: 127.0.0.1
- description: 'The IP of the server.'
- port:
- type: integer
- example: 22
- description: 'The port of the server.'
- user:
- type: string
- example: root
- description: 'The user of the server.'
- private_key_uuid:
- type: string
- example: og888os
- description: 'The UUID of the private key.'
- is_build_server:
- type: boolean
- example: false
- description: 'Is build server.'
- instant_validate:
- type: boolean
- example: false
- description: 'Instant validate.'
- proxy_type:
- type: string
- enum: [traefik, caddy, none]
- example: traefik
- description: 'The proxy type.'
- type: object
- responses:
- '201':
- description: 'Server created.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string, example: og888os, description: 'The UUID of the server.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/servers/{uuid}':
- get:
- tags:
- - Servers
- summary: Get
- description: 'Get server by UUID.'
- operationId: get-server-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: "Server's UUID"
- required: true
- schema:
- type: string
- 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: []
- delete:
- tags:
- - Servers
- summary: Delete
- description: 'Delete server by UUID.'
- operationId: delete-server-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the server.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Server deleted.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Server deleted.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- patch:
- tags:
- - Servers
- summary: Update
- description: 'Update Server.'
- operationId: update-server-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'Server UUID'
- required: true
- schema:
- type: string
- requestBody:
- description: 'Server updated.'
- required: true
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- description: 'The name of the server.'
- description:
- type: string
- description: 'The description of the server.'
- ip:
- type: string
- description: 'The IP of the server.'
- port:
- type: integer
- description: 'The port of the server.'
- user:
- type: string
- description: 'The user of the server.'
- private_key_uuid:
- type: string
- description: 'The UUID of the private key.'
- is_build_server:
- type: boolean
- description: 'Is build server.'
- instant_validate:
- type: boolean
- description: 'Instant validate.'
- proxy_type:
- type: string
- enum: [traefik, caddy, none]
- description: 'The proxy type.'
- type: object
- responses:
- '201':
- description: 'Server updated.'
- 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: get-resources-by-server-uuid
- parameters:
- -
- name: uuid
- in: path
- description: "Server's UUID"
- required: true
- schema:
- type: string
- 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: get-domains-by-server-uuid
- parameters:
- -
- name: uuid
- in: path
- description: "Server's UUID"
- required: true
- schema:
- type: string
- 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: []
- '/servers/{uuid}/validate':
- get:
- tags:
- - Servers
- summary: Validate
- description: 'Validate server by UUID.'
- operationId: validate-server-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'Server UUID'
- required: true
- schema:
- type: string
- responses:
- '201':
- description: 'Server validation started.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Validation started.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- /services:
- get:
- tags:
- - Services
- summary: List
- description: 'List all services.'
- operationId: list-services
- responses:
- '200':
- description: 'Get all services'
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/Service'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- post:
- tags:
- - Services
- summary: Create
- description: 'Create a one-click service'
- operationId: create-service
- requestBody:
- required: true
- content:
- application/json:
- schema:
- required:
- - server_uuid
- - project_uuid
- - environment_name
- - environment_uuid
- - type
- properties:
- type:
- description: 'The one-click service type'
- type: string
- enum: [activepieces, appsmith, appwrite, authentik, babybuddy, budge, changedetection, chatwoot, classicpress-with-mariadb, classicpress-with-mysql, classicpress-without-database, cloudflared, code-server, dashboard, directus, directus-with-postgresql, docker-registry, docuseal, docuseal-with-postgres, dokuwiki, duplicati, emby, embystat, fider, filebrowser, firefly, formbricks, ghost, gitea, gitea-with-mariadb, gitea-with-mysql, gitea-with-postgresql, glance, glances, glitchtip, grafana, grafana-with-postgresql, grocy, heimdall, homepage, jellyfin, kuzzle, listmonk, logto, mediawiki, meilisearch, metabase, metube, minio, moodle, n8n, n8n-with-postgresql, next-image-transformation, nextcloud, nocodb, odoo, openblocks, pairdrop, penpot, phpmyadmin, pocketbase, posthog, reactive-resume, rocketchat, shlink, slash, snapdrop, statusnook, stirling-pdf, supabase, syncthing, tolgee, trigger, trigger-with-external-database, twenty, umami, unleash-with-postgresql, unleash-without-database, uptime-kuma, vaultwarden, vikunja, weblate, whoogle, wordpress-with-mariadb, wordpress-with-mysql, wordpress-without-database]
- name:
- type: string
- maxLength: 255
- description: 'Name of the service.'
- description:
- type: string
- nullable: true
- description: 'Description of the service.'
- project_uuid:
- type: string
- description: 'Project UUID.'
- environment_name:
- type: string
- description: 'Environment name. You need to provide at least one of environment_name or environment_uuid.'
- environment_uuid:
- type: string
- description: 'Environment UUID. You need to provide at least one of environment_name or environment_uuid.'
- server_uuid:
- type: string
- description: 'Server UUID.'
- destination_uuid:
- type: string
- description: 'Destination UUID. Required if server has multiple destinations.'
- instant_deploy:
- type: boolean
- default: false
- description: 'Start the service immediately after creation.'
- type: object
- responses:
- '201':
- description: 'Create a service.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string, description: 'Service UUID.' }
- domains: { type: array, items: { type: string }, description: 'Service domains.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- '/services/{uuid}':
- get:
- tags:
- - Services
- summary: Get
- description: 'Get service by UUID.'
- operationId: get-service-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'Service UUID'
- required: true
- schema:
- type: string
- responses:
- '200':
- description: 'Get a service by UUID.'
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Service'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- delete:
- tags:
- - Services
- summary: Delete
- description: 'Delete service by UUID.'
- operationId: delete-service-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'Service UUID'
- required: true
- schema:
- type: string
- -
- name: delete_configurations
- in: query
- description: 'Delete configurations.'
- required: false
- schema:
- type: boolean
- default: true
- -
- name: delete_volumes
- in: query
- description: 'Delete volumes.'
- required: false
- schema:
- type: boolean
- default: true
- -
- name: docker_cleanup
- in: query
- description: 'Run docker cleanup.'
- required: false
- schema:
- type: boolean
- default: true
- -
- name: delete_connected_networks
- in: query
- description: 'Delete connected networks.'
- required: false
- schema:
- type: boolean
- default: true
- responses:
- '200':
- description: 'Delete a service by UUID'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Service deletion request queued.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/services/{uuid}/envs':
- get:
- tags:
- - Services
- summary: 'List Envs'
- description: 'List all envs by service UUID.'
- operationId: list-envs-by-service-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the service.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'All environment variables by service UUID.'
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/EnvironmentVariable'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- post:
- tags:
- - Services
- summary: 'Create Env'
- description: 'Create env by service UUID.'
- operationId: create-env-by-service-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the service.'
- required: true
- schema:
- type: string
- format: uuid
- requestBody:
- description: 'Env created.'
- required: true
- content:
- application/json:
- schema:
- properties:
- key:
- type: string
- description: 'The key of the environment variable.'
- value:
- type: string
- description: 'The value of the environment variable.'
- is_preview:
- type: boolean
- description: 'The flag to indicate if the environment variable is used in preview deployments.'
- is_build_time:
- type: boolean
- description: 'The flag to indicate if the environment variable is used in build time.'
- is_literal:
- type: boolean
- description: 'The flag to indicate if the environment variable is a literal, nothing espaced.'
- is_multiline:
- type: boolean
- description: 'The flag to indicate if the environment variable is multiline.'
- is_shown_once:
- type: boolean
- description: "The flag to indicate if the environment variable's value is shown on the UI."
- type: object
- responses:
- '201':
- description: 'Environment variable created.'
- content:
- application/json:
- schema:
- properties:
- uuid: { type: string, example: nc0k04gk8g0cgsk440g0koko }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- patch:
- tags:
- - Services
- summary: 'Update Env'
- description: 'Update env by service UUID.'
- operationId: update-env-by-service-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the service.'
- required: true
- schema:
- type: string
- format: uuid
- requestBody:
- description: 'Env updated.'
- required: true
- content:
- application/json:
- schema:
- required:
- - key
- - value
- properties:
- key:
- type: string
- description: 'The key of the environment variable.'
- value:
- type: string
- description: 'The value of the environment variable.'
- is_preview:
- type: boolean
- description: 'The flag to indicate if the environment variable is used in preview deployments.'
- is_build_time:
- type: boolean
- description: 'The flag to indicate if the environment variable is used in build time.'
- is_literal:
- type: boolean
- description: 'The flag to indicate if the environment variable is a literal, nothing espaced.'
- is_multiline:
- type: boolean
- description: 'The flag to indicate if the environment variable is multiline.'
- is_shown_once:
- type: boolean
- description: "The flag to indicate if the environment variable's value is shown on the UI."
- type: object
- responses:
- '201':
- description: 'Environment variable updated.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Environment variable updated.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/services/{uuid}/envs/bulk':
- patch:
- tags:
- - Services
- summary: 'Update Envs (Bulk)'
- description: 'Update multiple envs by service UUID.'
- operationId: update-envs-by-service-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the service.'
- required: true
- schema:
- type: string
- format: uuid
- requestBody:
- description: 'Bulk envs updated.'
- required: true
- content:
- application/json:
- schema:
- required:
- - data
- properties:
- data:
- type: array
- items: { properties: { key: { type: string, description: 'The key of the environment variable.' }, value: { type: string, description: 'The value of the environment variable.' }, is_preview: { type: boolean, description: 'The flag to indicate if the environment variable is used in preview deployments.' }, is_build_time: { type: boolean, description: 'The flag to indicate if the environment variable is used in build time.' }, is_literal: { type: boolean, description: 'The flag to indicate if the environment variable is a literal, nothing espaced.' }, is_multiline: { type: boolean, description: 'The flag to indicate if the environment variable is multiline.' }, is_shown_once: { type: boolean, description: "The flag to indicate if the environment variable's value is shown on the UI." } }, type: object }
- type: object
- responses:
- '201':
- description: 'Environment variables updated.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Environment variables updated.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/services/{uuid}/envs/{env_uuid}':
- delete:
- tags:
- - Services
- summary: 'Delete Env'
- description: 'Delete env by UUID.'
- operationId: delete-env-by-service-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the service.'
- required: true
- schema:
- type: string
- format: uuid
- -
- name: env_uuid
- in: path
- description: 'UUID of the environment variable.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Environment variable deleted.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Environment variable deleted.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/services/{uuid}/start':
- get:
- tags:
- - Services
- summary: Start
- description: 'Start service. `Post` request is also accepted.'
- operationId: start-service-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the service.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Start service.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Service starting request queued.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/services/{uuid}/stop':
- get:
- tags:
- - Services
- summary: Stop
- description: 'Stop service. `Post` request is also accepted.'
- operationId: stop-service-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the service.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Stop service.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Service stopping request queued.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/services/{uuid}/restart':
- get:
- tags:
- - Services
- summary: Restart
- description: 'Restart service. `Post` request is also accepted.'
- operationId: restart-service-by-uuid
- parameters:
- -
- name: uuid
- in: path
- description: 'UUID of the service.'
- required: true
- schema:
- type: string
- format: uuid
- responses:
- '200':
- description: 'Restart service.'
- content:
- application/json:
- schema:
- properties:
- message: { type: string, example: 'Service restaring request queued.' }
- type: object
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- /teams:
- get:
- tags:
- - Teams
- summary: List
- description: 'Get all teams.'
- operationId: list-teams
- responses:
- '200':
- description: 'List of teams.'
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: '#/components/schemas/Team'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- security:
- -
- bearerAuth: []
- '/teams/{id}':
- get:
- tags:
- - Teams
- summary: Get
- description: 'Get team by TeamId.'
- operationId: get-team-by-id
- parameters:
- -
- name: id
- in: path
- description: 'Team ID'
- required: true
- schema:
- type: integer
- responses:
- '200':
- description: 'List of teams.'
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Team'
- '401':
- $ref: '#/components/responses/401'
- '400':
- $ref: '#/components/responses/400'
- '404':
- $ref: '#/components/responses/404'
- security:
- -
- bearerAuth: []
- '/teams/{id}/members':
- get:
- tags:
- - Teams
- summary: Members
- description: 'Get members by TeamId.'
- operationId: get-members-by-team-id
- 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: get-current-team
- 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: get-current-team-members
- 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
- description: 'The application identifier in the database.'
- description:
- type: string
- nullable: true
- description: 'The application description.'
- repository_project_id:
- type: integer
- nullable: true
- description: 'The repository project identifier.'
- uuid:
- type: string
- description: 'The application UUID.'
- name:
- type: string
- description: 'The application name.'
- fqdn:
- type: string
- nullable: true
- description: 'The application domains.'
- config_hash:
- type: string
- description: 'Configuration hash.'
- git_repository:
- type: string
- description: 'Git repository URL.'
- git_branch:
- type: string
- description: 'Git branch.'
- git_commit_sha:
- type: string
- description: 'Git commit SHA.'
- git_full_url:
- type: string
- nullable: true
- description: 'Git full URL.'
- docker_registry_image_name:
- type: string
- nullable: true
- description: 'Docker registry image name.'
- docker_registry_image_tag:
- type: string
- nullable: true
- description: 'Docker registry image tag.'
- build_pack:
- type: string
- description: 'Build pack.'
- enum:
- - nixpacks
- - static
- - dockerfile
- - dockercompose
- static_image:
- type: string
- description: 'Static image used when static site is deployed.'
- install_command:
- type: string
- description: 'Install command.'
- build_command:
- type: string
- description: 'Build command.'
- start_command:
- type: string
- description: 'Start command.'
- ports_exposes:
- type: string
- description: 'Ports exposes.'
- ports_mappings:
- type: string
- nullable: true
- description: 'Ports mappings.'
- base_directory:
- type: string
- description: 'Base directory for all commands.'
- publish_directory:
- type: string
- description: 'Publish directory.'
- health_check_enabled:
- type: boolean
- description: 'Health check enabled.'
- health_check_path:
- type: string
- description: 'Health check path.'
- health_check_port:
- type: string
- nullable: true
- description: 'Health check port.'
- health_check_host:
- type: string
- nullable: true
- description: 'Health check host.'
- health_check_method:
- type: string
- description: 'Health check method.'
- health_check_return_code:
- type: integer
- description: 'Health check return code.'
- health_check_scheme:
- type: string
- description: 'Health check scheme.'
- health_check_response_text:
- type: string
- nullable: true
- description: 'Health check response text.'
- health_check_interval:
- type: integer
- description: 'Health check interval in seconds.'
- health_check_timeout:
- type: integer
- description: 'Health check timeout in seconds.'
- health_check_retries:
- type: integer
- description: 'Health check retries count.'
- health_check_start_period:
- type: integer
- description: 'Health check start period in seconds.'
- limits_memory:
- type: string
- description: 'Memory limit.'
- limits_memory_swap:
- type: string
- description: 'Memory swap limit.'
- limits_memory_swappiness:
- type: integer
- description: 'Memory swappiness.'
- limits_memory_reservation:
- type: string
- description: 'Memory reservation.'
- limits_cpus:
- type: string
- description: 'CPU limit.'
- limits_cpuset:
- type: string
- nullable: true
- description: 'CPU set.'
- limits_cpu_shares:
- type: integer
- description: 'CPU shares.'
- status:
- type: string
- description: 'Application status.'
- preview_url_template:
- type: string
- description: 'Preview URL template.'
- destination_type:
- type: string
- description: 'Destination type.'
- destination_id:
- type: integer
- description: 'Destination identifier.'
- source_id:
- type: integer
- nullable: true
- description: 'Source identifier.'
- private_key_id:
- type: integer
- nullable: true
- description: 'Private key identifier.'
- environment_id:
- type: integer
- description: 'Environment identifier.'
- dockerfile:
- type: string
- nullable: true
- description: 'Dockerfile content. Used for dockerfile build pack.'
- dockerfile_location:
- type: string
- description: 'Dockerfile location.'
- custom_labels:
- type: string
- nullable: true
- description: 'Custom labels.'
- dockerfile_target_build:
- type: string
- nullable: true
- description: 'Dockerfile target build.'
- manual_webhook_secret_github:
- type: string
- nullable: true
- description: 'Manual webhook secret for GitHub.'
- manual_webhook_secret_gitlab:
- type: string
- nullable: true
- description: 'Manual webhook secret for GitLab.'
- manual_webhook_secret_bitbucket:
- type: string
- nullable: true
- description: 'Manual webhook secret for Bitbucket.'
- manual_webhook_secret_gitea:
- type: string
- nullable: true
- description: 'Manual webhook secret for Gitea.'
- docker_compose_location:
- type: string
- description: 'Docker compose location.'
- docker_compose:
- type: string
- nullable: true
- description: 'Docker compose content. Used for docker compose build pack.'
- docker_compose_raw:
- type: string
- nullable: true
- description: 'Docker compose raw content.'
- docker_compose_domains:
- type: string
- nullable: true
- description: 'Docker compose domains.'
- docker_compose_custom_start_command:
- type: string
- nullable: true
- description: 'Docker compose custom start command.'
- docker_compose_custom_build_command:
- type: string
- nullable: true
- description: 'Docker compose custom build command.'
- swarm_replicas:
- type: integer
- nullable: true
- description: 'Swarm replicas. Only used for swarm deployments.'
- swarm_placement_constraints:
- type: string
- nullable: true
- description: 'Swarm placement constraints. Only used for swarm deployments.'
- custom_docker_run_options:
- type: string
- nullable: true
- description: 'Custom docker run options.'
- post_deployment_command:
- type: string
- nullable: true
- description: 'Post deployment command.'
- post_deployment_command_container:
- type: string
- nullable: true
- description: 'Post deployment command container.'
- pre_deployment_command:
- type: string
- nullable: true
- description: 'Pre deployment command.'
- pre_deployment_command_container:
- type: string
- nullable: true
- description: 'Pre deployment command container.'
- watch_paths:
- type: string
- nullable: true
- description: 'Watch paths.'
- custom_healthcheck_found:
- type: boolean
- description: 'Custom healthcheck found.'
- redirect:
- type: string
- nullable: true
- description: 'How to set redirect with Traefik / Caddy. www<->non-www.'
- enum:
- - www
- - non-www
- - both
- created_at:
- type: string
- format: date-time
- description: 'The date and time when the application was created.'
- updated_at:
- type: string
- format: date-time
- description: 'The date and time when the application was last updated.'
- deleted_at:
- type: string
- format: date-time
- nullable: true
- description: 'The date and time when the application was deleted.'
- compose_parsing_version:
- type: string
- description: 'How Coolify parse the compose file.'
- custom_nginx_configuration:
- type: string
- nullable: true
- description: 'Custom Nginx configuration base64 encoded.'
- 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
- EnvironmentVariable:
- description: 'Environment Variable model'
- properties:
- id:
- type: integer
- uuid:
- type: string
- resourceable_type:
- type: string
- resourceable_id:
- type: integer
- is_build_time:
- type: boolean
- is_literal:
- type: boolean
- is_multiline:
- type: boolean
- is_preview:
- type: boolean
- is_shared:
- type: boolean
- is_shown_once:
- type: boolean
- key:
- type: string
- value:
- type: string
- real_value:
- type: string
- version:
- type: string
- created_at:
- type: string
- updated_at:
- 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
- description:
- type: string
- environments:
- description: 'The environments of the project.'
- type: array
- items:
- $ref: '#/components/schemas/Environment'
- type: object
- Server:
- description: 'Server model'
- properties:
- id:
- type: integer
- description: 'The server ID.'
- uuid:
- type: string
- description: 'The server UUID.'
- name:
- type: string
- description: 'The server name.'
- description:
- type: string
- description: 'The server description.'
- ip:
- type: string
- description: 'The IP address.'
- user:
- type: string
- description: 'The user.'
- port:
- type: integer
- description: 'The port number.'
- proxy:
- type: object
- description: 'The proxy configuration.'
- proxy_type:
- type: string
- enum:
- - traefik
- - caddy
- - none
- description: 'The proxy type.'
- high_disk_usage_notification_sent:
- type: boolean
- description: 'The flag to indicate if the high disk usage notification has been sent.'
- unreachable_notification_sent:
- type: boolean
- description: 'The flag to indicate if the unreachable notification has been sent.'
- unreachable_count:
- type: integer
- description: 'The unreachable count for your server.'
- validation_logs:
- type: string
- description: 'The validation logs.'
- log_drain_notification_sent:
- type: boolean
- description: 'The flag to indicate if the log drain notification has been sent.'
- swarm_cluster:
- type: string
- description: 'The swarm cluster configuration.'
- settings:
- $ref: '#/components/schemas/ServerSetting'
- type: object
- ServerSetting:
- description: 'Server Settings model'
- properties:
- id:
- type: integer
- concurrent_builds:
- type: integer
- dynamic_timeout:
- type: integer
- force_disabled:
- type: boolean
- force_server_cleanup:
- 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_sentinel_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
- sentinel_metrics_history_days:
- type: integer
- sentinel_metrics_refresh_rate_seconds:
- type: integer
- sentinel_token:
- type: string
- docker_cleanup_frequency:
- type: string
- docker_cleanup_threshold:
- type: integer
- server_id:
- type: integer
- wildcard_domain:
- type: string
- created_at:
- type: string
- updated_at:
- type: string
- delete_unused_volumes:
- type: boolean
- description: 'The flag to indicate if the unused volumes should be deleted.'
- delete_unused_networks:
- type: boolean
- description: 'The flag to indicate if the unused networks should be deleted.'
- type: object
- Service:
- description: 'Service model'
- properties:
- id:
- type: integer
- description: 'The unique identifier of the service. Only used for database identification.'
- uuid:
- type: string
- description: 'The unique identifier of the service.'
- name:
- type: string
- description: 'The name of the service.'
- environment_id:
- type: integer
- description: 'The unique identifier of the environment where the service is attached to.'
- server_id:
- type: integer
- description: 'The unique identifier of the server where the service is running.'
- description:
- type: string
- description: 'The description of the service.'
- docker_compose_raw:
- type: string
- description: 'The raw docker-compose.yml file of the service.'
- docker_compose:
- type: string
- description: 'The docker-compose.yml file that is parsed and modified by Coolify.'
- destination_type:
- type: string
- description: 'Destination type.'
- destination_id:
- type: integer
- description: 'The unique identifier of the destination where the service is running.'
- connect_to_docker_network:
- type: boolean
- description: 'The flag to connect the service to the predefined Docker network.'
- is_container_label_escape_enabled:
- type: boolean
- description: 'The flag to enable the container label escape.'
- is_container_label_readonly_enabled:
- type: boolean
- description: 'The flag to enable the container label readonly.'
- config_hash:
- type: string
- description: 'The hash of the service configuration.'
- service_type:
- type: string
- description: 'The type of the service.'
- created_at:
- type: string
- description: 'The date and time when the service was created.'
- updated_at:
- type: string
- description: 'The date and time when the service was last updated.'
- deleted_at:
- type: string
- description: 'The date and time when the service was deleted.'
- type: object
- Team:
- description: 'Team model'
- properties:
- id:
- type: integer
- description: 'The unique identifier of the team.'
- name:
- type: string
- description: 'The name of the team.'
- description:
- type: string
- description: 'The description of the team.'
- personal_team:
- type: boolean
- description: 'Whether the team is personal or not.'
- created_at:
- type: string
- description: 'The date and time the team was created.'
- updated_at:
- type: string
- description: 'The date and time the team was last updated.'
- show_boarding:
- type: boolean
- description: 'Whether to show the boarding screen or not.'
- custom_server_limit:
- type: string
- description: 'The custom server limit.'
- members:
- description: 'The members of the team.'
- type: array
- items:
- $ref: '#/components/schemas/User'
- type: object
- User:
- description: 'User model'
- properties:
- id:
- type: integer
- description: 'The user identifier in the database.'
- name:
- type: string
- description: 'The user name.'
- email:
- type: string
- description: 'The user email.'
- email_verified_at:
- type: string
- description: 'The date when the user email was verified.'
- created_at:
- type: string
- description: 'The date when the user was created.'
- updated_at:
- type: string
- description: 'The date when the user was updated.'
- two_factor_confirmed_at:
- type: string
- description: 'The date when the user two factor was confirmed.'
- force_password_reset:
- type: boolean
- description: 'The flag to force the user to reset the password.'
- marketing_emails:
- type: boolean
- description: 'The flag to receive marketing emails.'
- type: object
- responses:
- '400':
- description: 'Invalid token.'
- content:
- application/json:
- schema:
- properties:
- message:
- 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:
- application/json:
- schema:
- properties:
- message:
- type: string
- example: 'Resource not found.'
- type: object
- securitySchemes:
- bearerAuth:
- type: http
- 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: Databases
- description: Databases
- -
- name: Deployments
- description: Deployments
- -
- name: Projects
- description: Projects
- -
- name: Resources
- description: Resources
- -
- name: 'Private Keys'
- description: 'Private Keys'
- -
- name: Servers
- description: Servers
- -
- name: Services
- description: Services
- -
- name: Teams
- description: Teams
diff --git a/other/logos/advin.png b/other/logos/advin.png
deleted file mode 100644
index 155408b9cb1914a35c86e99d8b3a85b06def62d6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 33880
zcmdSAby!?Yvj>P<&|nGf5F7^A;0*5Wgu#7q2_$IH3_55C6I_G)Ac2q!lEH!#2oM|s
z1cL75ec$`t`+awJ|JdDs_B_vUW~!^JtE;MiU8nkxsHdYwL_kA;hK5E2R97}YL&Iu7
zLqq4q!$DD|dNlMRk+A6i8L4EA$%_?Kn8
z{Q2$wq6GXgCqK&50`|}T*hcW*Z1Z<7DTQbL|3mRVGck1X{SOMtI)55`?EUmaVKGrj
zArT>QNl^*Ge~tfFQ;P1kuDf5T#zi9t4umAT^hyss)3&DRW
z7i{nIzk(0NEcI8Qc>5W7dwa+!*?R@rGjSO>c|CLTbMkv4Bk-Rb|9ATS7b^V+4+@|D
zM<5IQ3*Y39U(TDLp+(*Tl@*MF3-*`$0~S?Dan|N#RtJe+7?F0q5TsP5H>3YbuTEcq
z^$wGrGPe%yhi$^0VA%hiiHqz>6dJaS8(GAv%Cv*f*VB7Ykmer%efr^(rof*sXvAc8
z=%|~XC_2@jpT^|>|NnV?_>LOwUJcqYj;M!*{6@N?CK&Z@DjFN`8NtCKr#4hYfAuc&
zeMBQRssTQ*1Ap<`dieP_W96aw=@-zBPlzOhm2NFI${L!bm=8eN(B~h#q5>>6LZnMp
zq*&xyMf+5S(%xlyPnqDOcs`e)c&6jDt9!mV2Wht~k}(ccyWAJaw=tj^d0(SF*lJ<4
zQBhU~c@>!-m6eux#-Qlk+!(yMb7jumlC64SFYQgu0>FGIvY9YCRe`EM;(OrU+I7)L
zn;|tOimJ&1e=+5fTJZd_>>}C59a9jB7A%ToCRndM5e#U3x)^bO2&bSo`$ulY#BaF&
zU*4>Lh4w(|*_H~(#u>CK*6Vm1KD4B?Z2COM;E<#4&-|!1$53J5mH~D4eU4*1bjugz
zt$TB@1srfR^^7AvlSf{Mul@do<&L69RpB+Py+&A#Oc7ToSzi6R
z^?CCPw6<8Ca2fEX_p~0x5gdSJ*5JM@G~3)i`)Dl2yO>Cu>zxPZG%l*M%0s*Ux-#c*
zL94v}NpZPCJ0esEJ$iJiiv=;@a{E>%`k|zRAT2oePBZ=IhK_E^O
z+FkCgowwp8ssGGfl+><2*s!ZXs_nAH@;)y*sEz(el+0Ij3zd7IH9W)M{d#^I?QA$$
z(u?K+SYP%W`D&~-)^+mvPcS*5`qnwe8<7+1KNoixKUirSXIZatTv-Opp*o|@pe7is
zgg*1dk`Ul8`u4E+U1nEL<8AFrlGc&BKda4+6aM0)tSEY>MYgdz$!#_AVkZ8F9AHmV
zZSq_hBu3u(0mZcT9m~u|%DUvsHQA9TV`MYECAI8nq_hzmU=I3Qh^1F`XgiRW1;uEj
z8-=|=FSRD?aLLh6f57*`QL2O?$Sxw`PN!j&Bz%vBMQ-FU`lJ(;cA=TYhzsKSNUJtEj9)$pVqFxANe2GI8OC>+i>baS_KIe>F}fo5mIx
zLL)O_p=wN5QAm&KyE*9|93LOo3euHdp12OYmov7soLcr@X_8)+Jqo*$*{+PhorNVG
zCm!Z}fDE&&!-#u>$SNJ3JUP?azL*3^oIBJcIi`FuADLaA*`Nl5jm(BF8_oFN-8f6eGYSMa`;CVF}2
zJMQ)I*@%{vpZ#JVc%t4F?wh!P{<=)4TWl1~tlQJZe1f_#;F2}Z(d7;4nu?4kW=!JK
z=u1zxH~3(WO`1N~$UO<{TA!&(Fq{3>IEMJ^ax0m|<^?h4Emvh5d%oH2%?q{VG1LJ~
z?YOA*?Mg~piq9BrPey*de#QN#>q~er^@teYud6z?le%HyasIboJ6qS_rtZ%*mX7pt
zUY+cXO|C5+_p=G@T`$)u;q5uZd4ErpT(l=DAeg$X?J75Z-mGM!?ngs#fWC4~?q=lQ
z5}Ov>LeZ;@t-IwbuR4u6=xOb7siY3SH4E6(_ILf4l$WCR)B}OT>M!d!pL>c?H&I4|
zjEI~B-eqhiY>+il74aT>p_7tTUqN&Ku`qwY5xn!=t&$j*nfC1!(6FneYH`b`xuIlw
z%%f^_fyi9IGZBW%hHpkxgJq&&VJ*h@k2d4eol(XCDKcNT>ETw+d(Hg$hh5dY>&XYr%u)O
zl9hDZ?wiq${J%7tPk0oEK~=-^v_%TvEWnBn3Z61EeGILgI$L+H24nmq@_#sEt_t~rq
zS6#}-0c3F=w7hNmw>hAqHU|&PvMA|gKtcye__e#fw20BX+)}66VGTP6wLV;eZHK>y
z7JHay0Jm7_cN{NiLO;|5wJ%GP{q0F8bViSrz>J=sb$=)kA#*zN8E>p<@*j=dD#);F
zG&n!wExL}K$k7rV4*YFSKy?WRWkdFbWMuWkN$qfzHrhWOYT{@N;h)-*eK>67#1<^x
zkqiD~{~gh?C}Z>4k+1)YUK`cYUEI%}at`R7u|U}>wuY}T>K}JYpK5SUrX-m0?64rc
zUflYm!V(``QSH5=;o+18vHOVo1S!|-8Zw9lmwt`DU=p;E!vANuz_(zGWk@rgnYC0J
z&?Nnpg{jKWvXfzB2c-F-L<5)sGf-Li``6_ugohp50m(kT2Z;>f4aTLa@{*~D&>tCl
z)x(qxZ)QKlWx?Mkv{!*yX6b>|(JJpwAH7La8G8IKLlCeR0~?FFKr6?1P!{rW1D*nx
zR~{mIiTG5_P88W2V*Fc$9pfILI+yT2L!pcgti6i}t6Yd;6)_F6#
z7p=s){`$szo(s}U*+9}j?)rN-5Izg%fS1jz(xRtf^kFjCFF%|Uh5fFSPf57OE$o6q
z=Nnx7(B0*Bp4lZ0R5ow0n2Z^B>85^yWHhllxbCpUMZ;>NV_`{9n;WWjP8P2tSsr&a
zWHy}mvEr==3&RBI2#CqmcC8u?*m|@MNsth8)DUA~lckhElfe5*9n61B7b@>fbqqjq
zzc|92QybEj9TouqXdkEW*`cdj5L%f_r4jG%qaU5myxG>TN0~xp=HU`%b-gLocx5A-
zH4a_YlO=NaDeHQw)`^tD&8c
zkH|6imW{;0Y$4nw%6W|c$kd^6ht+Ya5@^Qfd~)<;$+1a{PGB5SHZ
zaZQ>F|5*gWBQ%BI&UiQ)SCjLLDk@mTs`a1PwV2&^m|e_i7Zz&eg+QhnA#vYi=Xv8d
zgg?wfr?nkh8GsYnVDw{K_+waz$-AE1vv0^k$W2Kc$|DpheP&hJTQd<%=M@y{d2aSQ
zSOn(!QqeeJj*Jd+xDxM4e8*^1kYey8;ka<^VY68uh#2I|Yi$IcKYDMkO#C4Fls&=}
ziT*AF6}8n#!_*Bl4v{-p9wwz`c2-IjsxHDpi1wjCS$Y8p6qz24NWOIgmM)OFh}q{O
zPFfLk6Eqc95zhg~p9U(ydr#ozaBg7jKnDtHi$%{RPwBY$SO5Y8w(+{Nk0>;4EBkC_AbT8Mq^q_(yPv9XXMLplDT
z6`Y0?co_Ud85s`b)VY0ZRC`%^R2FdUnn#Kfy7>+W
zb8H7AYXn7{L_Z`z0RiS^5`AcOV-%lhU<+eE3G9-P9cTTsaB6l>)4vo`K&?9;DomcJ
zEI8)Eq#KYr^r^EPD#B^a+G70OzWEsCkm$6+z!*e+yJ%?v>MfSp^A#4VSH~r$M@b1I
z!b6Q)zquOxci666OxJ{gC{RSfx)>L~-OLCJGQ4o+aB|mr#vIHHKrmLnvb=j9Cq%8i
zm~p1HmVnOSM}F0{SYlqQGE@q;j8Y53^A|m?lzD8Pp)QsAC6_Z8?fBvkm;q=hs2g^j
z<#sZh^GmCk{GIaSJ5F5+PmuT`aD2kZ$De3%!)2N*5)2KjN6;+H}vY
zfc5-7R!s{D37fFh#J=72#a=u*3bH}4jU7D%OxNHXtt5|A0rxE?2-iS16ilJE*)bQc
z$a$3^K2)M+FKK>`Y?XvGXF_p31#0dBFJ`WO@fSWV1cox}xqbE%U~PU)O*V(og}E(!
zee`<V5oh<)gs(Bpi{EtM4}kf;1-MICXI|N0lMHTMwL)Jo-TDCTg^aVeA^B%im%EU@_W?#gF4Y
zObfCv+82pqZ+GF{f=U(GWG9~qeQO>-iU{Zwxm`S!LQ|F=g!8d@2|)9+I9*BB;=jxH
zQC4*t>ab3&q4Nu6jJ|a>ttY{if;F=GQ4Rp?yxE
zS>=vxoIA8&VCp*MQ{^RcvXS&a^>7I_#1owzr9U{k@Te1GHYUMLBTuuT%75}YC4i}nay%5Zz|Q?78(Wkyq-mPh)FvqpZ`v71Q}Bnbk3VO5FNX&`Pf}2
zNN}_8Cnwlmuq&VpO!K%BgGxs7d&HAUCZlbIqaVvkoZAJR_n-p3I%V?FE;B2XBF}X-HGCbZ`4ZxIWf`#sLR608
zX7`=IjGTk=eIO1$cfq(-vj(RgYkZE*n`j0$*`td@Jd(cE$>1^xQ_OA9t8)jS01Dj@
z9$&xj4)r=t#+D=mqg`$T#bs4#9{W-?xGVF%O1MxRdQK=TfYQ4YYAO|tteThKfMjES
zj_OI`nC>vy!PkmAU$4M`c}^p<`NZI2M%NYj7dvD2#KAg9gm$RGW~EBt&hEj!)tH5;RGkd
z0)@h#D9SCj(Yw&+(0SrKfp+Isk^Bu&XW=V^Ut`YfuUO$q@E-UC%iAZXZev?R_3__W
zcU)n6r}R+=QRNwtWwfYIT6$zqJ^JBU$o^7FIJ&!{at#(0(1L*XNxrrkDxs~w7hv39
zv7oL81#ll{68av#N=S6#D(2Kh-%|%VD-R7mcA(^Rm0lCHlV4MTts8Svm*}crN%{aP
zHNX8#;0pNSnyqa-BujYdxE2d90w3q4g9Ut~k0aJTC0qu|pVm}bVb`$qF;=sD7h+E>
z%!h@*teG!3d)oTYzP=_7O3XY%J1&N6!!9n}yRG~JXFiM0TF}du?DjvunX2j$3vEH_NaF
zr#=Ms8^(Nb2;UtyCi^z9DpHj+A`15xjtP6Ne4|Yn#AC2MIRzMsa90lJRw`g&^TeUE
zy`4{!VT9cjO}F@XDTnuros5j0-t{uEfbz^=!VIJ3CwvM}$y@=UZz#u(-rC?}MQcj3
zql2|z`8OADhu+)R2tZaey=l3YXvymL*ChDXJmIuag`pBFF=0{FQO{|ztU>I{3fwO)
zc6SpbM3f3%8w6zXa*U(K%v{rw7LN_W-*l4+%WbWypgiSp4pab?N+*MKXS!!^NP3@>t>Iml!^-$})M9
zcauK2vmz`G9c&drWYteJ>90poF+My|2&D%WtBFKEzhA#s$_ojY1JHG-vWIK2o
zs-2c$BXHZm?nCEO0J8+f&OhIoY6Kzo!q8z4_Ueonqv(m~G&;?^uNBOcZ}gBGFye8W
zeU_agxA!pz%AxlcXjZS8hm%!*oKL>Jm>bmXyp3~1j0nNqqjS=oKPYpK$P!#Wuv?X5
z0Qn>P_FCZaY}SO~5-gElMjXYEABlavIa#tXIkUzcsrZ+If3I1!R2_;g{(%%8*7d&f
zrEK@6gdCuo5t#w9__dDFUD3^l>Pli9ugtUPst;WWyD=NPge64+JCu*t&yIxPznp0o`=*7<(tchqdbeQTZ
zrTR2R1KwK2KS=O35Q3S01`N66(U-3o_ZCWmJ&om*XdW$Bi$6>FLJkyQ
z8N=G25hXi0CG?%$m{Yn}Uob_sMH$2PdZWQs#v_q{WBQ-gw1^K|u+&~gpj3$+L(4jb
z2`yP;W_TgFIgn&L6T
z2W2PRc3CiaZr|gC_S7?1`+6$Vra=uUex>A9VOQ4!ypZ?7Jg%%jY6vKCGq`VOwglc1
z`=IL;4dJ$vt`ySw2h@>o_+^8`$BCpZEYtYr*MFSvZst1-!h
zh?gv+(p;1M$llH=*+drmD9A%nyS;
zo-?HnWaphAb(9Oq)dxXAupq~a1U4uK!+=%GCxQ3^v8_A8W*!-2(
zxY#e*cFgQVUF9^FdC_`#cVyp@LmvPiRPkq|y$%!72RVN#M9Ok&?WyQpIAm&LuA@
z;241dxRL648xqI*q!2mc>GS(TB6v`hxgG1?J*wi1s*4snw?8w^x_d4FOy}xWZW`W8ByhSUsNtXX}!Ii)EQ)2*!0Wdh#S9V_%R9M6a5g=@ONS++{T|Z
zIn@&~?SLS(fB{4xTDCugwsk-m`7%b>g~Saylrmav_|ec>n2r&P9|3j?Adp*;vB94;
zId-$(Z~um=(@hOWq`r|m=%byCkWaHj^PgVCXy?+A-*a7mdAxJUVcHGNu?r9PIDDGd
zj~K=fH&Dn*ge~In=~eD$Htsr7uRFW2L=e+FohLDN0ELkeKb0*zX?=f};~GAx#XpNx
zC)70Kj|)kHz}-lJ6XX!H00*r@G+|$}Lo@>G5iHKa#}F@uP0^#{5x3WAdC(DM32_{@
z`dx`{fxJF}UDPR*YSdEdDW84Usd)5cbo#tK?YzM}njfaFj<$%Ok#^|wbfsAb0
z6ZA^ff=%zDJqx~%yRC_ClZL-HfF@lT`Jd&47pu!=nBID*G5CYhG;%tkZ|T5!n}#vj
zGe)6buB(bEqaE=uAMFmq_}x|7-(rm25sdGxfB$H+P8}mwq_go9aBY6bq{a1yat?{Jf?ef0^bA$
z7DKf~n(BIS0Zql}Z2^*5_kv9?{c(jTK&?1F==S%8}5X`j0
zu=f5{jydI}oKHDa)&*oZwjbr?wkg;&fo?lNACIY)KYzKTK*&a{+y02rwp>**`fTXX
zs=1Hg>&E033B*gC>@QW>*DJq!kJcE*8#jeF&fPRB{c_ZJI1wVYh-|~RYasc2sdv&SM0-@#*K|kYG`Y>*ypY&!?7A2
z(BcSrr1wG`?D|-;`=ywRs{EbsT&emM3ZOH7{aWaihuqmRB5
zzb(wfGTEck)UIm4TcNQ|fohjTa$FUDBm@HdarIe$1tEVw@BwDbiLB?$;4z9fZ5B4?
z4IrqPj94gC6_A?n4q}7F){`y&Al#H4$YH?b6Qj?8qM;Q)me&2yW-ZYkk%ou;;43yo
z#XWR@^fE#&f6u@3@j9%79FHV>dEn>t_GHLoyEH9#&iq`=&w2BK#8N41zGkN~`0=eM
zoyUJ&(zBE|xF4d?eH}$Cn9o47Pyq4TEH*&@P=bXV;h}iQRK;@Fr~Q#mwM{Qapmtw*
zwd|nq`*_wFC}U2G`4aR_SiB@i9ycD-dP-~xhl89OVqli8ccT9U)G8^*3F+}zSpjzE
zAGRkRZ40hdE-8=_-dwN{`UP{f(&-2_ExYFl%Di%`erdy`wVbb2@koO3lEX)&
zc-{uo>ZGzzI1myu*lNUGk0I8CjZTu3dCJz4>k~0g($jzW3hYe&%DM={2G;p$Z4S>`
zL)LMtX!)jXup{ADtAFwk1t84Ez#8JlKlD8-K1d6lA!|BEI)SEqqd77~0;ssMzQa_$!tjJ>)csNNdn9%QeSDgD_GH
znyR6Vt^@q=s`1d*b5Y`We2fR3ri-!st{2J0_3;n6t@prYU5YmV^x!c>9rifxc+Q#P
zI2_?&xb}tsW{bwp#->-7eKySH>!Bt1d4*nnF`)x5o7TPMH0-^Odgv5F2e&titECpo
z$2{to_tR%z;c8+<{ZfYKx&qMlhP@_DBvZoZ{=luTjmj)8<&$
zkkYW)t}-3lU3xVws+p3MhGLX2ybhVVxkh<{IJSu2fc6hy{*GrkF4*;>9-lF!rCdcn
zZC3=|T;#)#@P_l;)h!H=QjlTbRXdD`y%y`t6j`X_LR}$UF6H8(w~5vKRqWfzHTcR!
zd>b3h2Dc8UmmnE4J5!_&7RxrKc}c(eLXhwHf^t}h|8Bnv1GtSL|A~GC4^=~oJBA+T
zLJLXDr#9Cm!bvb~a3TqL1zc@`rXoK>n08cwxa3uHks9h-p$$^UA)K{3o5};*+5`{u
zA}AY1n)_(kmtX(w_p4NkHuOE-7ST!B1r6~2$<82r3(iM51Ym6N#qOL>KeLu9CGgQ7D1j3Ky54-k
zI@imckGzcFR8(({R7bX1)K0%X3j*458u7@iQ_P7YYVsF6Y_RSKWUy|?f?Z+MnxTa4
z1NO_G!n+Y3>~`e1mDwaopCWCkt|I3$39KM7m(rQ+*kUu4R{9`hg8O%mkw~FdQ%9
z@OO}0Vl=#fv9g5_;_RwxVDJ?FG04y(DTxzDP|}C*Gcikz;Kv6Z=et^loOl4&Q5mxdx$}MGh*v!!k0s2IAYTJVL-nh8*gca>%>BHq6z+QB9+cRiE7#n(
z)+tQV#cDpO{Dth4oe)JFjCtDP7_aYYQh3$1Bao{6Ki~
zwyJbC1U|xcJF29Gtd03J)J6Y&MYm=2o?B4y#je#F-V4)ZDfn9mRrVP=kVnHp37L#@
zrsJ338Udi)djp`j&anA?M&bI>?^9%jz&+L>8{Hipv4`66UU(afosEyj)d`rwFx)-y
zq;BIOB;z@jnB!$#GHtZ3riC?ff<5GNJ5Yo@I&1uF37xQC2ekFAddkFM^J_rn_bl-d
zU|x}QLZ=-lX?;T)TafPy6UD%jl6c(y@JnrDx)koJo+5Oy9I#@Qo(Jt$(o1bWqZvWy
zns?@aFr1UlA%qsx%H8n#<@6{q&GIMP=rK0ysj4WLI2%0<-4Qhv>5XLPt4o`M=!utM
zUAg%_0$|-5oXX_jzV^I~rC9hO#H!kkT~^11^7*vFVG=Qo@u_hC(Dl!Wz{eHZ~PZ7ba^d(yZWa!DUGX!>@arRWvz*(XE
zk$`T81cTS1uDXdr#bhtVS0f|`Bog|_)>QwYS)zI;Ac%0#2bB}%F^2}pVt`ZPO|^qF
z*CRx8C(>6KW_0~p9M2}M3YB>EJS`c~Kw{J-v7;Hz(a&?hO*wC1<}tM0+!nQv1okac
zDfN)w?L^Pykw-)fncze^y4wm{B_y&Sy?P8pyJgiPZP&mIizmE5O6y1By*!kcm4zlC~kz(nb2F^e`<
zoiTAWI>+?Mqk>DDc$gJT#C3cpzakOYfs>CvmeY%rNx6V|YkW9>!)nt640KcCmf
z+q4-xG?POh=;4CXohgD>*4DUm`O?|^POCJgc%XiST=MD=nXYaY;3VJ0qNOX!bsHL<>S#I)|444>aT|^FZU04!B7SG?n}z@%RtpgPEfotdV$5WTmRxX(A(VK$^)FK>A
z4JcH96oz0#A9f~wX9=wm4)Eb31|vi0N9^%WGRJumo2)+!_ifO%FmM(~nZAPgSCli(
z`otBEHFUjHm1meqMB(Hog>qV`)i+GH;?h~aRErk2D~H=hX8FfxX4|9hFwJS&5eP9b
za&Z8-t;kuZpO_duJ&}8XW+@eu@o5ttoFeGjrYKW3bCxDnCp`spre6~SRC_2o+Y|p$9)%#uPiw0h5FW`;ZPxJqY2l7pY^^L2<{;95
zK?D_++zwliF?KISgpSmyVJ-AJG}S`B0zP3U!L6Iw0#AIpD*|mn@Xmvm5!vwVv#yNf
z_lu)@mmE+W|0in!Q>)poWdTo-rC(^>jbAWF(l4gqHc9v-LTjNc4{r&@Pw;p6HogUZ
z`Pkg^<@mB&^INFhh*%_UFA-22?YVj;ltdm7L_#uAS=*YQb(4p_lFNAu2Wo;mzSrHLOm2;&t?IbK8n$GA$Ob45&BUiM`rFXhx
zVLPBeMmdg8Vd(OKlOePxuo?IJyA-iVu@4s)#Np&VK=sg12!7_}AU9hiE_!$z7%x1(bk*MmJL
z`R^O|Y!QH|g+BIXvQVNR471mhZ}0d3VHoZB?da_$NbA(SGhUR-qF_*v*ntt>`*3@weXU04Lz&R-wqGv>EwE*&AhPF>T(_GP%
zlCRIOW;qf2=|lR<47CYfo-Nku(mLOr*D~NggCFgxuR9|t>@>~*^XOmm>~8MrB^_yB
z7~^4*w|bvkJ@-%EG)=WQa3BI$$}pqn4!jn1Z8>CJ@`tf`%?dVYJE)je@8fcP3yu2x
zkZ0p_(VuT#i4A1Yx5yAaleQltO9T#2
zC%R~oBAhK*vOCI)BKw{K?NXGbaomEnXRF<3^etbX6~N?xT|f((uV|?9IOVy}^VM-g
z@8o(*b(bnK1fgA2m2q7$3Y-1W7gF@n=<}c>!h<2a>~UEu3ZK)R-%7_|{^{;j;_aOrU6i{iu#Y({3S5$?q5-6x~fUnHZ>
zreyIrGRmcX5CUanyBC07@dO-iYkt5^n_+=r%IVb)ThL`5%0HQUBg0{O_nxS9RT>($
z&=8j+U^`)Aml6Y8WV=;In#90PsNlMI2VM0}ga>M%*6;^&wQCH(?M9tAQ32PP@=6vC
z@tar@|`qSg&}1k-qE>wQ!u}gW2>l(!r8G?q!=f7_FG8m<&Qqi-`TtAd`{0
zx&^(5W|3MG^l-cy+Uw6e%pA34WQ5PIxiYX9Q|8V(>xK|poF!6Dq;1V5&zC>jx-;Ko
z%xOyQEPaDb5llE+g-PhJ_Plir=OJm-DPP4YNU!*EAhQ%F%HWTDf?uPbU`Sa1`b-;0
zODF>EE65
zU&p{~^XFY-Qd6WFxQ?;y!~xO-m*!*K;!UXCu-8gieRujb{g{VP8e2Rxq8QR%MV>^~
z9U(SGudaPkqbMbKw?i?TWLRauIemWW#aS3%0JgB_5Y@C((P8Sz@)pn2wF@bTY@3pQ
zD@X{j5e5vFTX&{E^)S7Ad<+0sqF>V4*T3UPig)ySLFNaT8MYyxlY+LIE-SBAcKV8y
z(2F_g^^YJtRDdL6zGJ;G({P)$XEHXwlqwaalh*=rOSAkWve7uuEur%(kRk-V9z9pN
zNAKAtu^ko_>lef_Vm8I`2d4qVG{CVNs{N5(d0DW@I65#@xQ?}`9B6}IQ!w-5USMNk
zkYz_~pkkB4M7SwVw`puY0zN`M7mgzV&@Ww6&TR%bkz+!!^JSy;EAu_^Kwy8brrB>4(9?p;m{;4Vr
zZH*eHB?ft2pspO6l|87^uvEGT0{>Yq@MjZqY@!|-ePM`a_+DeixaY~}2XtkBx3sAq
z9cO(c$28HQbP3@|y5m!V@3cJ=
zJf3C#6;-uOr3oa5l^HkL;!U-*;k6@Ymi52R-!pDao?a^;3GK+&T9+CLQ3>s4;~>oW
z2|n+0H(9cA#IX3uf>2CVH9lpmp%2F$f*{&D%E=E`pZu3EGGrdex$WxgscYfLJ~f{x
z{D2$*RvSVLzn1g;Aq9M{G0jC0nkw<(_`xM-<8YoiYq4)YowBF6=6B*Zss-zBgxn|_
zpnOl?*5V)2MH=RRj?7h>Cy9dfp>5zZ3!2LLAf@}(;Q;iTF)&mvS
z1~XF%L#us?c8Z5+ZbNY(u~~%?cgVtkj#TZMD6o-RWetg{xJ(D;
z4^=knXP_p$6##uKlwRo(tHlqQ)G_*}DH2gXe~abnLg$~WYgE4d>Bej|4=ktjgUybJrLMo-cc6-s
z$r(|D(Z9(>exao@?lP{UZ(L$|My;xMa_Tz@I>}>wihP6t)I|@2&f~{~RUeGr7ckpF
zpwBrj8489KNno^p0c!OOJ&d{7oW@G&
zlm76&EJKF}{6b+T1kQ%6`XJ{CvZdWB0~w{&=m!@bryFungttHH!z+
z^-1N?Q(HVml7j*t_p3D)ln=q-gGZxG%Sbjtu$0DauB;1+$BAV7VSSn>Eo=KG$ib8QDD*sFl6J;qBq$
zFW}|;_lyMExD?e|2Tu{LU#*Rpw6Hp4yWmI>g
zyrhj8EaXOcFFgh}$8OEGV+V96_h9Y9&8Eh3Db-AALfU
z>1*|MMXRx+j#rdZB+`WyoJ0aeo3d9}fh1FxgI`=~+(4ey3BpZT(b|hGMdX!PI;WV|
zXZP_?Pa@vpius)2h>~<{faNM8Rir6Dx{p+6G>D0C>9&E2@@6c2jxJZ|bGvL4jix5$mNKl2
zwA@~J1^W#2UZiX1U?}f$KN7$(@LCKhx
z38f}V_`E=YhljYb9}W7cWUU@hGVL(Ju@i+Yq2~8%nLSalOkN#kZ;@dXGWB&;i#D
z1#f?e_%Jufrz~I4xq&vSlD)BHc*Kg_)?4NzYb9q9a!0TkQcx@4I2~&34Z5C#kJQjY
z3xaQN5FM-PvUcI>$PbA$rTV{=?9~w-#sKLdO|@3rrvcXNr8sempW>Kx`${|
zg}DbsiV+zmm`_v>mOrRKiv9$}Bd>LBo^Il4U&5cNI#L^B9_+x{-0V9ViKQpRQH*)>
z-qke9q>C?fN(QUyaeN4l>1m32#VD@HZay36Zdd(ectT+@jF3}w(O$qXOPjs8l7a7l
z#3Cya$Ba?uE~Kg@VPCW;M`JG|iWr?h;w_F9$xuFwn;0L``!AQyC{RQzVA+|ia{PhK
zw(J0E!(h}&pO@vxG^{3k{yI2$;Y~HVc}qgqrHn?l+l4#rp;J_xP;B
zWc#UETPWWY$3{1y3i!Y=BVv(H6VaKYN#?K5w9a^!016=LwJ$?@cT78R$|;KdS!SEZ
z{%WI6(Vy41^*3kYK&=?ZtZJj;(fKqHjWElxeK|#GP3{Mn+j;XN?6)5jyxDZt3n}N4
z$b09AMVjQ%oKbZkSyNx$<#AUSd&4YxDn{m;6K)^Bfpa31&q^2pi?5FhGFLwG!XK?FBQeGjly?=C!OzxxC?2DR3dZY`oJ2!Jb*nMU{*xFaaA73!&PEF%jS
zh;k+uHCUVzczyQlt!gO>wM%p7Wg2h&aK1H#7_LBrt?}C7s8Wp80#9YGKPk`>^_;^Y
z)a1w|XApaX+EP#l6`L?XzR!Z0CfhCjr95ZH1*UXcuqWlan>{q~&?So8`4^x-ob!CF
z#fObQcSs&91sDB<8dfkv7_hwRpN3MdUH#zMNQKtwO5mAInO|K|)j_o$O|E^Yf@_0X
zvr0KYVy4}=_p0PMe0ck+>MS?&h+c2d(P?t^;_EYl-z2{l=6g|Tdzw8cDR=%G9209X
z?n^f;n}x3PuFDY5u@G$IgRGQAo%S+;TFpdU<#~g6V~d>QV7-4YZ;C#u#?|H@4`y`A
zq};S!PC8Gc`=o}yOuT{z_)bS?Mxu0(EQ#fKw^^6^y(UUZT*rl*VprWbV>Fwspjj8t
zv?+@<=HUyt_Fhx9!zLM1D45^JZgkiq+?L4ZXm%)a0BM%L`aqCf4eY|Tg-%MIG(fH0
zK$d00GfG+<&E;EbUck9l_r~{(p|}9cVFU*{3AxPBu!!&Px9|_3UoTBMAL9%O${){|
z)H4pP7J}V$QHShN&{|EG$8^P#nTqHd4+8|RrQJeSo7-7;gzd^Qma=OzTQx(;SB0;m
zd7nNCxZe(T6s+p-l}TKhNAR;RP1hRhdr0nJ-o3WBX6=b>)T@A0UPf>bf6#&VfC77C
zUE5H*zoTQzPz36I_TMs?$ucZEb9^?}j%!X6c6f4K*O(X3`TJHRap*q#_*;S`H>{
zbNihgLlDX{ABG|*9DeRf*)=XTQV_t&AZ6RcZ&AB$7+!{gOmONhM0lkjX#!Rdf-i2g
z>i%tEGzM2l;Ha^mSE*g-vJ5JVhCpM$0+D^Xre-!$uTjaBX?>>RJB~GYZ;(lge9IQCTo#vu4}*-^4}CsCc^LzqTR_BN*9IH
z-|p;IN3zMffkx0*!O7*tD$y^aC-UcI;Vm&2NBl3G=Xj&c0w9x_s2rD?zgrKGiXMeK1M|10dA&B?K8USK2X{gb@Y}Btgo6g~*%Mvs;8$n(
zEou*|#$-4eh+^?bHoU9TMVsbheu+%retMm&?cb{q3rA(53zn7sk%h4kZnY$I6FH!Y5PH
zxDmkmhs124>zHXl|Eb>ifT&UY+HBb*n0VCGV)s72r_B)`>S59?6?Rp;*BvvMO1WO_
zRKXvDeOyh@;;sg?BbpHT1nXCn*20LASw`
ztRv0yc0BVely;7X!a@~E4ws8D>9tvpTni>Cxnx=#GtPNFTz=bY3MIU0(so~F+i4Z6
z6=g%2gA?La))iSNfONEZ#~v+;1rmGh@YSXQS1t4VOatAIih%4=lP-w|@`gvA4>>mI
zh;CM%qz?Qj&^}(Q%$q;^N~B+Mnn+TBi@d8!wCcv#-zadA%M@g9TntA4YKYYAz}zun
zlhwH9mfc++HTtC#^fRD}{_cy;c*+zYEDjYJG0+tB-eT!gMf9(2!8SzNB5h0az(eC*
z|I%r}#<>X8Y1B=##F&tr!~sySU%*H!yl?TfPmcxirKefBo{tI=ik0zQ+;0Sl)620#
zrQ82i>KwSnth791mc}3Ir^?#veZUkP2l}x(<(oo0ZV0fy{z1~D1xyT9^bBkKX=?0aO(B*2KQ*x9W
z)!1?w#lbS7BBJN~Mhut@*>1fl2Tr6
zoh(%Eq>|tbqDu^~eOYX8QO4GQV+Y!JQu{Kt8-X#)Gg_@bKcZj#>C0Xg%Z}=r7iWht
z!XqihY#cjspF-1k37FeD^@Y=`QFynCASXA`Hoz8@>H?k779Vn)1<)F@wS2e!$^`+D
zuJrX8cj$aLldqw!SG6rOsgTW2-Z~gW?cG5vJIZVF{v%&lI5l^_I_FYoVC)@$L#bLP
z=Vb_z(=vt$22r)KXcFnsTgvv2KpyHM!*vTc)_pZ(TXboG!^xKK8u^!_5?USo>YDUC
z?wv7$^9Ql5q_T}-I97}M!v2agqbO`y#_~{gZq>adm(W7$`r{&F3$y|TAC_r$*0UV2
zp@Ln9ErR5dzwnF7YcDxx$_S2)Q*k+qr10$iz@0K#p$jA>5?I(Ljg&J
z0clib=uYWwDFqqY0i{!rI5g5ZgoLEvkWzvILpPFleD8ff_kRC{@AI5r&U5xUXYF;?
zUVH78d?$hu;l7$j00#x$dXcX=yI~19jtn6L`2H3%lB*=3Jpgp^p(x|9OI9I*
zdrN5rfr)7NEYHRprDXE{gsO)4fOB5zX(fp{b|?SVik~o33Nbrwolc~4vO@$b_l-Y>
zCqU}DdW)+Tl?yY&|IoP!e@_+k7!&^F!B}HLFV|JCrEWQDg)vN!$PYu6exr_CaLZ)v
z8?kEQQhsLnbTgQ#>*5&540SN8Da@t$NLzX7vdRhGQtYtk>RfGI;OQ5|P96?($-jtj
zD|k?%qf8JqbrD;p~#hOGH%IU^}U3fcT?JN@*DN0YOi&uL=gCZ2saOxA@Z4IA#X_
z2=vL{dQo5}k(Y}z*f)p^W3a$AlJduj%3UW?r@@%htLnqGhVr-13h*^Z<>2nEZmy)J8&H<#>UD4<%
zTa#D5UhsBJ{7h~A`N!wPLYcKAU$_COYIdP0tD{1v{%Z;zh0oLc8=so30QcPTNKlY3*#Rho~$Ei&6*f$nU
zS4=3`;}0YiN^R*+OG&nTjt?5G?VYJK8s!5bgf%R`PBDzvUE#Jz{z^bTMRtLbg}!vu
zN3VLW+*dalIQv$xnMxvf(6PGj{e%CWlXgY^1v};dC<{`^GaqM})>1N=%uJ?;t<-2x
zo)kF5a)T+gkJ}QhJy_`?-bc}EYCHy
zB(wV1&P+WI@nOv$Xv9Qi6-=04-c-dJ1s}hr>l&|!x%P5!sk5k};B_($$tp{*s78MNW;|4IJO@ozST
zp`w>nHt%;Z&^G74#N!|W!;zoW=)pK|_z0c@FYy#X_i$c99$-UkuyH2i@V4Ziw$_K^
zyu>Af^SxKQ54H^ntC0WceU_c^*uj1*CnI>~O757eWG}?wY|df7Vdk>Z&+Z5v2yIAv
z=^)eb^%%)z`3A0qc7d^!$UaBSVRBA{BF3@v2>u9q#2F!%!xgd9;sz63tBcm8d+A^~
zG&CU=loIVClqc9KXc
zo#3IzI&Rm244I{94P+xy1_>a=?=_Y4Nj__5*A(`$A)h1V?IAbBma=@TEuMf48jfa!
zhvng|5C{wmMFV5x6*v``U?@YDbjozn;GwR!^6nxwJqPD;gYOTEyjV)Eh%-D42vP|Y
z$OMUB6K$9L>F-Cm+uWey5B8bUqc_(UnWznUVmd?cS2zuq6%@~MM&EINDt&EEc$>)h
zH
z8QVErJ*O&s>X96!3m@1<)(rGN$P9SOky^#_NPrZQ>^^7lfho(;e3l&fimxSK8Qf$~
z2C^{-fN5m@KL7+CxcWG-5C+3aB)0*M4LT~l46THGWl82Xg4Qp#oWtk!X$AimGYpE*
zHI7I}9$M*h77*j28oN4V=^la@JW1&SXVlDot%XZRkjTHfq!<1++)l;z19SENArl70
zl3-8D3OqoDsTn*_W)M5LN%xJBkY!@$v={CTu_X%!&TwfW@V(8i#cm<+d55KJS$%)#OfK2;W5IJ){DQc5RI
z$p;WwJ=%CE9cn2X&&gry+N8fP@j;!by5}s5saso-2xYwpv7SMJk3Q?5c;hgWBbthE
z4o^{8zdb_%vc$N1F;M0z>s(qyQkn(l0ONcqx&V0?W2OhOg=P(JqR-)a3BVb)B90%y
zA0dyeE5lEvYbxvAIKO>w+S+FZ)#iP(;4V<>zy<69Yt?e_Phu8+uz!7*e&SRchKVHC
zN~aB-$~R!imZce!o9$NpKXeR`o=gV?1PeMXg5lct_gat=v+JG0v0#adD%KTN6ZtA}_a0K?
zduMR?KK3$!4q+~yIetH-8w&GX?69O0tfvcT{S}7%Y3m^YWL|_xcyPo<___EPGxiSN
z&uU=%<8!kT&F3hIn&)4oe>u{fjdc>3WVe!$O57OqyV~P+lA0C(-VQAO*;WHP3A&8A
z@WI&?>sI4g;f3%=4eM93iBqZ&+b~!N*@d7-8a#V$ONJb~s@TsuZZ2F!RC$cPOmg!z
z#l>5|jSKwcTegFk>{;{8A1Z+Y
zdDiB+BSdVLdbXcMr{TN3L@lbUzd4(p-+E|8!8mN%PI*m{qA>Ww5QY-LxxzI;NWON(
z&DJn(8}@w1?S=$&6?tkD7&3M*2@1#tJTW=f@dNVa^Fwig`0+4b`Vnv6+P*zg_$26uTlC1U+GyLgHFIaafX%2*>Ly5+K1~DuOdy0>U*sOo9a}3;3EyiL=Cu
zRnDW6L7I+PwlRb33&w#ZQ!K2mUF5G}kg6(w1pH?tqojWywH()JT300?6*u^Kw-Q)8
zp<`1rBm@QOK~!S~)1UI~g+JvhbRe2z#K?DX5aL)Y1fEu?ysU>(k$wL8B@qYi(8OR<
zM4Jp0^E`XCFJMGgc!&lm1NL%~UxUTNO(`qL`^^2kEmZ||JH;T+QK+)9n%9P$YcOh1
z3*PZkuxtynbp0uljE?&nL51)W*m!YJR7mr2HqiQF+%r29kN(=M*5@}Z9Zu)>45p7t
z72Bu%RAdMrmVqsPsIN1y%$wg$j2K#45ij
zMRHjTaQSsmwzDefu{zBDBB-FCi8rv3F-sD*<*>{K6iR@boT~UW>BSiM&o_=r+;g93
zd>_O}|G2wJ{L$md;*d@y-kAe2e!Hn{NeGJR2qonNM`Jsvv`M{yS&XnT39`B_&-C<6
zJwR$B5y&HOojH-VZ?;vOv!yQ)Y!`Q|-={Hq{={nTD-U*Cpr4Wh-zQ+$@=et-&Q$mS
zWIf?2e=yg9x?spvSa=C!{bM&@TY@RMOYW?BOGZ}YzV&0vrz5U+Uj?m}3RDBwg+`w+
z2b3+`?TL0@KNO{wKz9g&!-PC;cGBrasgYzmO}X>^mqHO8U3BW3IlkCq|k!yLQ+stShvjz)z80bjajKg7J3VSG?Sz(aQKRGvW(Ay38|z
zvz!jpobf438`ki%t3g?G!S%P^S{Zkp
z_MqdL3AX7P*FeHIKQ#6D2aG)*{Heb#pX|AJ7c;oFItv))eW69AY+&eTwL)Eymyug&
z{tUOA*N;^M994e~^)*>Bi7{)69ehAOhCMvtXEG)(SzxT}harhxQ5EA3tE-|$mhv^k
zwiVdJZhrtiZ#rHQvpYQpTD_ayqsk%cQuy1AWCwA5RcR_*{>2?D4UO!70&l)=9$W!3
z_|lX#Kf{{T7LD)kEzq+Rd6n}O>W&6H)1^n4iI2_E8B$*0d9bI}9y^>?3B&@4yf
z(N_wrR|+=D%E@1AW3I-4Ah8;YMB2q9#BEOU?@;QgdIs{53~A`r_;jhS>zkkfhXH+k
zi5IAGo3iE^m*@Rp!}&c|%ogi%Kh;0{2W3U_?CpJlB4F>Wc74j5ubygSrbT!C_z|^M
z)Mv5)?|0HTZ9~jV&H;<|7iX+dpQPz!8Sdm2v1FZ%KEnVOeS5RQC-B%}za8~+t
zCv)!hgU4>mwNpTP+y^nj*7*VANV!I>vYIf
z;PP!dql)t5W2^xyno8p?O5}CAR8KJwbibwze$DOv*h~#^uJ(FQBpjnbs;!7l-l!*o
z47=(G&J^a9A#SeEt9@%4^;WY9HXLeQpv%p91kDtr2^vhp`cM>#S(~X>;=p;txv>Y=
zuo*Umr+l*UX|YSVS5pPz=5{WhLZ%efg|oGM(ZU1#E!bq!MahV%Z%XL&ljS%3`NAoR
z`_&=5Lpd+lpT<}4+j8M<1I%~q>BIbwizWU0n_=AF%&;!R8b#Ah!-Mr8Yz8RWny9I7
zf72vo^GHd%)onI>R<_Bj=18+N^@aMl(s6_Br~8&rgt3Fa9|J#hoo({IwP;$cog^@S
zXkxJE`l%0d{~Fr1;r-*wh9`N&Q*Z^9TqJY#{8M(1C}4?BpN^%3mq;}wSk!9PxW7Ez
zE`k~A+a~#;i~Qgjnz=f8gfyE$f2}QJRSpub$ZHfAiX)V*CpoY|hGMIiDyttzZ5
zri0M0=*;%ZL+I)K6-g#tdus)J(?VdN@%b4w5F~M+If>gWH^LtJMYGHm11alaTenEC
z|8c5R@qIOBPYXQ|egy||;{sKuCCtCZcr0YLg|X|t
zT0rvSP3`9FGZ=mM(!R>oW@4Nk`bcqD+Aqr*87zfIp
z9kjQyc{A&<_7KQQS#Gr~_nTMc4e*qb+Tgxlw#j51tz!_yHhGLYMcztCnh?M$K_-}_
z?Xv-|lGlRm(;>Ev`MR|96B?akcL20Kk`~$)-$h^=W0w)cc-5&8(~=%0=(!Y&Yyd9*
z$`we*cy%R^XV=js-n+24xTAR@4s`$l3tAn|bG7ybVDe;xneVlFmvob?g7}W3k1o}j
z<5VqoEki*MGCBN0D?(MyX-bCBgP)*=}+NRJ$ZP&u)XlSlV
zaHVj^-vtXt2WD}RKljEeDMPb@kE|_+HH;7*_!fyt?EV91~
zuv~6^0Px1WvcbJ6vT_K6-8etZN%2fa21F5xRhF5A^Fr41$g6aN$d=v&8Wkz6D$Vxj
zipiIfaEf+RWRO)TS-feu341mp63fVtVy+!$6=ZZ}594Q0UK?6$n3cFO?*AKYIX)d4
zvp8(C>+GV>_^6a@-odhK{DIM`HgHKRI3n0G-yQ|H!E`zK+I5pST-%*~nA;EN_a>
zs<9LTl(A~CWm+Cu`jp&P59}-C9&XFxg|fucJBVA7nPN%HGT=m?o+Kul3=X
zoK>fpGX2T9-LV9qELVaX4Igy>B1}|Z?_jlLM`~FR{h0&2k54%*z+gyqPs`siYlYay
zv#pm=cD7^;*R(JE(235zxrMQrHlWcOj}8%5j{cqANRuvPt(#vOJ>^!k{HSRr12@*}gW|zNwPY}GCSW)XuPLdGvqesC%VNVQnp)Y5zZhDNn6IdOuYk=&3
zT4I}{2tA$bXg@II3+QbGqSYo^a!S#cNS*I{&mvCIj)=g;y?<
z
z(ma%Hl`
z$p#GhwU88BNU}UOhMZOWMsa{CtylSyo<(=EwHviY$*bQLYubbuj7U!|MOEW0yV=P9
zvSkZ%UhB~Ota*7g`CQZXi*Eguor_kAV>=ENBDj{SoRGimTbUIw;vCLyNl?Va-cP5n
z_Y#!`Jr&1jd@uuN<=Pyy-bQbGe7D@y3@t)PW!)AODBb(^(BS*oOfOgs)DKx`h)>(L
z%&bx$!0tS9IltG_6T}*7N*C
z`55LJ4G3)D`GV`jgXmh|^7+AQ?{^AW^@n;qgeiOOn2pJv{43qpy1?Ctj&$SS7U}+K
zY;T92LQ6uIc((g=Ks;Y*)F`L#RNk4#7&ms?-ZeWV1}*Mv9TvkJ2&Fh
zM0m;*NuL(u5EL_-xp%>!zYlA$B?HE?9&dY0s(wa5gF%wNei*O9Ua+!%3aXp181O)#
z%=_=X644V)X!7r=x)K{t4C5NtL;Woc4W*z*9DAi63!a7WCioLRv?AK^-J?RhBlWk!
zVGLVl@8@}C7Gd~jJVfoT*ur4A4?jGU&URAPu(prsQEz|Nee)6Eao~*p?!IAt}F
z^^PR&lID`{QQ#x~KUP>zrp9krs0mZ^Je~ACmj&SZ+!Eyk=!4YHlHJdD1itO0f
zzGdsqPd`z(;yYU!R58@j4wAfKJ(e5(r8Wt2Fo+xUcM`gWoW3SJKG9&h>nut=eI%kc
zq<9vSuyL;5Ne1V&CiP&aN30c*D)kQAH+O6jW>v*9v#UbeYsd689rmSJm9^iCmxJ
zKyb_;7a$K;m|DqPcuT0Yxn4y$>dSsfla)GmPn|V@X8wx0U@b~ThW&yR-seSG1
zkv_wdq(zJqC|k%GF(?~LY~R)-n-*o4tLwf|P)%c;BaB!(%4LXW7>BfxMscQTZ)PRS
zNWO9WE>y^FQ2WyJ;kK>?IUV=31x_Wzaj<&tNdU
zCF2ubOD4@zLjs9(j7FMNW;ZfC%pkK+qCoh%B{j{0pewHNd@zs|Dnge-Ll>+UDT)-~
z@#|1wrCb+$GjJZ+S2b6&%qODKui)ubVjN`s;0@skcVN7iGQO1M$4FxWqH`RypiNDM
zW>cBnomaL_4gMBwFJsYHr(-WiX7tO4DKA}C9Qm)zv8SJ-*0x`V0zlUbl%fq2PVFJu
zPn@8n`;q)v9kWHfm-U=$vbo6d`(^K9cz1zN>F4MBnmd;wqj58Ax?q?j&q=2L$BP%B
z!2Cl;-xdJba&EUHkX$TFS9N3i$EXs-Jf{F#nSbz-bLu4>_~;=IU-ml9VIbq~Z?jlO
zZ|-3^U5Fdt{cZZY-xs5$U$Aqb%ywN}@K+k=KH~eA^U#leM@mx
z#?~pu*CO+|0>>4?g>jcxb+hpLKi{=tqr73#h4QGOB)A-B>WH<9AoFTS5jSz2Au&TW
z;2$+Hr0UbED_8X#YO3$${jK5gv@t5wMq>{Obc_B1nm!mpA2Sj_z$
z@{>*8v%+0p*eMcchLYK|uR~7NzZGYU@Wh67%}|SZg#{G&rSOs0d^bePvc;_L^8POP
zY^k}N@!VYO#RQ?mp20d>OGhUTrOHB_LoP~Tnk3IYfM^Qun{kA3iqE^x29WjI_~Rog
zi*x*yYgPKF=T+Usit|-jFRIzV;>s|0EI;)f^SsyZQ0k)}7!NmaHu^IkeT>fv3>2Ri
zR%REO&L5tH11b`(Tkb^(`bLg@SB1N>$B~bv)UUI3-HsG$U+vFlI6S8Pb#6Kr5@ZFj
zwKw!>Pl`pnR
zwZ!*ZZY=kpG*7@iHv$)Upi+Nj8$vS=BupGZmoq97{mIG|?Q8S?9kS}ua0T4FU&Egj=vwZAdiY_eb<Xx(?e_MVrKC9k@}
zQF!B4OiUl&C%92xYkPr;lc2+*7hA7_i-23sk-(xsT?vBUznbL
z$FJotW!<5iP+vwZ1KuH9m@7}l(`+u@J@;tw(N_{*jbAj(J3Ip+qM@e)>5ZCn1956Q
z+S9_f3EZzrCj?vp6AX{Smm7?78v_HwDaNPzAgFOtcIatJI>nEf(z8J`GK`m3iViWW
z+$?Yj1v&odI1$itD@iW%bb#GFoyY~gN`2Z5S~{ssyHy7+!|=BaIUEPsBJ2t~JGvi@
z#)q8YR`IfaYsXK0dO^FQo9=luzbY5)i>n{#GO{m6(&no9aPj2HVEZA^iG_M5))
zrYHk4n!c2Ym&5|AcQ#0mM_ItwgGb_L;|ogD`WL>Rv1B;lLwz4>#l2#l6zEmqvt}7%RY<>o
zt5bJd+}zP;6}|h*hVhDyEKmRMdq9{GFDqIGL$}|Kgk}-&>>?oRIcsqUZ>nUcU~W%O
z6Ti>AM@pL8*8VV9xa;F>ncCUH)2EQ!9wl%R43$&kuQ3@=kA*qVR%L>KnUoL!E>{lB
zNKjEXGw@*QyBDrV7Aaq{JBr>8ABnoo%(@$Ch+4)B=0SZO1WhoNI9OsBAN%7iQF<|@
zS*~U+iVCwoG{r5)gZgp+%sEpzCpI!h<1IR=denz~52t7Nl;moKm00RNq#63ukDT{w
z8_Jv*=ec9c+U%Xh!3Wd47^?G)KQ!fxLL_swtK}9H95c+jw
zf_TWcurehM7B_=+#YcHnBcxBrSKyl`xx0EQ>oTyAZ0za*U#Rb>G*moNou@-=Ip5e+
z{*T$@?s@<~{$+GhgUDI=&9kLOpj9Tdz>{<&JmV{GxMC@~8|)R7af+tH$Qp`&vS#XG
z$ZX%)6BuhWb6xgy%wm;uNBGf%@XW@l>NVLi7g%vuO`9OikVa6q8KWt0XA#>mYh1@;
z4x{$7{_o&F9toFXHdA*bf1F=ansHzG7~=lJef`kRn2
z_TY4>!jzAnmp^>{@hTX_^9`679Wt=46Q>lWaXk;p!xYHe2quKx+=uAG9D3_(`A2X<
zGuApi*SnpxXKF~P5M8l@G2lAr&v1o)me0(=
z>q94Qz|^`y+qKa8MRGPn%w#j*gTYYeqmT#NrX@CgOLC(Org65@*I2McmJ7G~V0S?u
z{=eBf?32T3-O`f;5iMdidJE4{i{Yoee;mY=r_<@&=3;IY#v&P+^^e}qOh|Ii?-`(a
z5D+V`yTea2k6w(u1~4U|8_~OuQqbqh{DK`bS3llAy`1c;!dG*)+Eu&E3Cx18fA?c?cvOTCMDU0;VK}g2$&|JjO`#n6Q4`+J3GK!pEU|OgqM9kbEwk+q5#R?
ztDk^4+%AsF&pt8mZ1%{6arGT`>}yrng7CZuSmfpIYHbW^B49~(Ej
z@?KueZaYWuuhFrCzbC=xAj6TFZkPqN@`ZJ;U$^
zfupin-L0qes=L?H@%*dcZK_TS2H2upfVn>{*h{K-G26D10&4esD+)WH8WVW-;ZV+l
zs-^<&6HI{Vh@(iSA7EP|@ayE>24rFTrp_iYU|Ll_0ofaG&j)co`5SD7Z{gTu#2H}E7ccnx9;1mpU~|L2t6
z?47Nejd#sC@BaZ{TiWb7pl*wu7T=S$hiFk;{=pi94!fj~!WI$ti(~9Y9zTPvee8By
z+bHtYpu-U+;wU43feI8|v#_u}7u2eFEls01u5z-aQzXOeI6!U~p}#Qv28mA=DJv3Q
znOnkB20r3KrR-vKw6%6xj48DS7EJt`m9{ZwIwO8d2gVS=xX(N;1@pa!>sjF1SNb^UlJFE3tZ?Yl5Vf(K`UM#y|!fY1T@dOo*duOpPP$6ZKM7JE<
zKRG5#ZYAfJm`&QXgKTp-!CwY-SuQb+TIh_Pm{SGw&~=m5x8cq-ERb5jX7o|aV!9)^
zH4xgs-WmgVWAtmDB@Sl{*PTiMIr^TyDtNpZ^N+tQRNtJQ
z(IEtjt#StWKp9l5-e$#PVk7}-X6uWNPZ)gIwStmmaHLgXynr28qks-*RNU&`6Z&l6
z2dA!su|k4=eUbBM0zzxQp8`QtjW}r|Z;pu?(Q^&(K^mwowF2SK@2{dnDrA<(TxeJ?
zJK#U(JB`n{q*6k26+Z)tPCf{LP20~<*MOnM*hNIZ`dw1OC*_iNL$Hx^b%*gx!e&(%
zb5LD5ng{7xB!TF_zb^XTpkt%tS6%*TaiQF4@!)(S&HQO=o(mkPg7~&wb-+z?Uo>H=
z-)1~Ef-O`zbAkP>`kRa1{c=e+nC;D!$To$|Kv7w>Be91?KJD=OuL7mYHz5@_O)MT|
z)5N<_Qn8NQH^~A8@;}*jmspxrV9xg3P}Cgs^dSL=D}xC>`5-jBTmaF7zGDho7TjJ3Pg
z^nyO+G-g{O`wflvEyqb=ehieNRiV*w{bBp>3u`XSM5x-W*_@7!6bNK~xQS9|6ZFFe
ze=rRUpImqyiRr+u#P*w|WX%{$WI+hhACbK_)#a`cuCP;eL7UZu*>5vwWKYcT9#-PO
z-czbd_e;^6u?<#QqPWN=N$Pa&)24QlSOJdUf0Fx3mjR#>uVx
zJ%&mk%_ijc@GMs#zRO7aBiycG(kCo3#wzI(x|a9X0Wa4M_49L4Wk-uybB1HX*_y?W
zI(T+9a7XH^6?9n<9+i@p56oEQs)hBov;XN;;xOp$OnCv_W_aLXd|@&_WO;t>U>&Ed
z9+IyeG0^+#R%mwrFWXtL>$^Z&*tbj#%$979G%Ff-wvClkh7Lrc3YOfhcHM18h?0Mt
z$dJ!=J;_j+!zFb$lc?QSPWL>-g5|*F700br%l?Xv*1^I>B4r!`KeA$6yLLN-L3O&?
zn8R-wx`j;5WkkL8E`vcyJ?_YNr1Tik*C~dy2ZFFYX#V_tNN#v9*t`k6s3UN#4-tO#
ziNY6z;Dw&vTOo{DbjG3t&>4oa>$tOE7mLz0VZ*!R>%`p8@6wi@TdOhE)TqvFYxR;D
z&^YH%k@>RqOtZ!lT=uLCB^c`PfR8v~Hh8Mt!O_tk
zZ{Je4IrI{svVOOZZX+qcM;>k41_WSnO;{I+DUJ(5`k`!hc;>M_C9VnKJ{ciJw_J0|
zYWPCbxE3q~S7KApG~~fEYYwB2o`y4W!v!5Xk=lOAsuiDhf4f;O1hp!3mtJd+q=-3Q
z8$Wt|bf9n$0*YxMSQwQn;_V)tkSJIIAJN0)W6=}cv}NY-n816-_hK3_WsOqnHxC3Y
zmseU$%iX4+zKSCZdKo^|>}Zr<5(v}+f!!rCI_t+%gyBgT?z~t@or(z2$Rwh43KRKf
zXIM(NJTr|^*0k&|4#Lz`5#{V&e7p_K*xZi~e9SHXiVo|HJTE9aHtKPjJ(6VCd-%Cd
z_TRliLk1TFMEpy5Etoob*6!n?W{4BrnpokUDdPaiwgEQYP>xXTEx4>!iaIV)T6&{W
zxY#(Q!WBMP(7i2?q2giXQsGH7P4U4;%`TY{Xy$+KQDn_bg3Jb1$Z5PmL^oBu
z|B(bqv$h%iaM@dUc6bZ%261-~?lIl`L$W^`35i{cf6(NlkoDkM+rmG1WfbQ)&T)gT
zyOpq(NcBO<^zhv_d=Z0@tNgAd^u7ltgJ=`3`KYv{k&E*DFMyML2YLS*FMVSGsbKlube?KzB<{G_rU{Jtxr|jGud!DAq_gF
zv`&|DwS<%Vko8O!-?mgV)m|^O0nTRTrX;oIW=f_ELige4%H8K_#xXe1s@ayF~(KS=c%l9x$_)6TOkG4HNn?&
zKg15^%$^5O9T+BR=Jv*43Bc_#y)={{6kmJdn6`lS2uA;DnqfnOrVhM>qGd!PK_J1@
z;m|OLp-HKz)YrZwQVy^LWIZ~)=>&m%yDp({hr7+GPlH(89(+@u(7m^>vi?%g=kO((
zd35QkoYAy~RwHSW9b}!NVq7}$a^K_Y{2mYZA_GL}g8B#?Y*_ro8z;U3L{8__TgtUgK9w2fTkRax4AC
zYg(}oq}5ZFBzdmqD0L`lm3&f6Bd@Z;Wvy!ad_Gh#%W+m?pcyRkutAH*Aq`Wqj$8|0
z|J*~VBq!1%k(0VjhaMsB%kmEYX{0}{%R$GzV%Q-?G3bcQ<1M`XXA4v6TVuM)gz#}o
zE74=Cl=PXJh%+JiqM0ero}xhc5ltKQ3f57iTs=>WnxMi@z0%M5%T&%H?7j2DZHB=a
zO3Vv!KvisIsz{RE%V73kHVcy9*A1+{rN2H${l>UUXlo|s&TG$Z?t3H{>bF{{P*GYi
zo4hy13*PI7WaMGr3WCr5N`u%%({DNe;lx0-5GIoVnw_hFd(Bnqtc5|pM-#VHE2E+|
zN8f7in!KtSs~ds0Kjsm@GRiS|1h6KH3L
zOH#RNhswNfq9$OZ6gSFPlheb
z2;`(;aY<#Zi3Y=Yy|29nKA=B&l`V$UWbmmsI7cWrY+9I%vUxEHicOe
zt=_ulG8AAhMvn}j3V#RB1+M}pzSMiJD_3e{cNZ03n$EG}
zuN-@8Ka44&O($l_;um>RNlPY6W!#-lOSbdGIKm45t)%5s843b`N2*T;@@H_SJJ?X@
z2YJF~vAe{w!6~qLem*VmN$)(D7nv#UXDih1bC6m+Y$j+UCs9#n68C$-q??{^&I5Mp
zoNSR&)Nm#^w48j+t!%M;u6~=czN{Xqdo&JQ?q|Nk^rxR7$DZ!p8Ji1h{ItLpOItWBoncm8#U^}ZVDS3H+`SM8p1Y=LS(w;W}q0Bz%QE6rZo6Sp&v?r>Wt=Kqx&L}6
z4_%Dxa+wT=j(sTSGLcH7(n)Yo92)mG4NG0kapC>Dojfqp)?{yvX?1`^6V*(=5{z7C
zYTEX2se4zz@)Of`)i^kpBRfd4;flYvqH--O2Q%%pYq4+3A}Kpt?U+`>;h3Jem}pde
zRMKC$awq46-VDFovTDjPiFbwzYvZ~wU%%m&6fX8O$(~Tt@rP|oiTgqB7@U#4#5MY_
z$U@9{=QI@~Q1!!HvQ1GhmVw2!sRUMOT`yKh&gjLJHLa!!2D9+5ubcL;yD}f_J~pQl=4e}(RDOe8#BW+=1W*0OCc0P#dY$4nQ%b%
z`e<>a#F}iTmg{+j`e`vhF>p1)pPKhO1h%{AosJp(lV_@)&9DEqlPf4`glYZnGivL
z0GSFvJ(*oxFuFa{`*JmYdt7|vS8L!XEZLw(00S1lgl9N>cur=fdu(dY$F9iGROq?<
zDKWXd^gkTD@S1gAYtOT54~kNO?b;JzQy%@kYSB1y8}psvnBHpM<{L^){>OO%GJ+hh
z^QY%^-Yu0I2}^v4&Kqg*OXfsf@pF2Rcax?B&is0ilMrBU#q36;rqzV7~23-!Xt#
z+hAl62Cz#!cx&ambm1#RFbnTr~3FzB1XP|<81IG{0!VXO=vKhxx|A9PQY$dE&ZM5H!
zHT`uXGLU?f0icT-{Bqazk~_E+=rLpRnK7^}>9zY)Qa>HU9qv}m=*Rd2FwLp40yI8^
zDn4;`l^t@I^2_56guzJhjn?E9cmhM$ChU@TRrde2IvQ}ZqJH-EbU}KFSjbo?hLz8n3H`J5;VZLH(?HlSCRvq2Jxo{?gHFS-L
z{p+&r!jC=8=~TJP6PUI>CsgvkVT&=VD8HdG#fo6s*6Ca&xfjEdz3>0MwUrzB4=Udo
hNAN$lJpX^cJyT>c$v7H>8~kVb>MA;rDkaM|{|i`_jBEe^
diff --git a/other/logos/appwrite.svg b/other/logos/appwrite.svg
deleted file mode 100644
index b5b8e4ab70..0000000000
--- a/other/logos/appwrite.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
diff --git a/other/logos/arcjet.svg b/other/logos/arcjet.svg
deleted file mode 100644
index 0586403c27..0000000000
--- a/other/logos/arcjet.svg
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/other/logos/bc.png b/other/logos/bc.png
deleted file mode 100644
index ddb5ef07affb12bc5f53e2cdb1ad5e040b078989..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 28644
zcmeEtbx>SQ_vSFTyZd0l2G`*3KEVk#5Zv7c3GVI|bZ`xlz(8;akYE9V1V{*wKnU(j
z-p^~dYU@|E``<^^F!y$!e)^oJ&pFfGw{M(|mNG6D6&3&hz*SXI&;tN~8jshu7-*0G
zy;0m+9=}Ed4UD|?to#_BdaoS_Wf0q#%+sK0|90N}skqT_=1jsfHDh}{?EDs{`l
z`5=AGa+Ds6)uk=xQU-yZetmJG)r5qiWhR`(k&bKDZ7rbO_DVB)DueBEjN*f-1m-AH
zJ3$^xKfLQDX$tzJoIsOV)M@NcsP_B|*fl}Ck{~NpTM?syeC#YS0q}i)R^`6$-QfBO
z?LHgs3jRiP{nlua$m+UrJwBr^aAHK^2lA|FVND)WMgr;JY217l!4Pw2YFLnoiuAaP
ziB}R@*pLo@u`)JYMJ=S$!*HtXA(5HIRT8n44R
zkJTWaYj%yQNtI4Qt~}7OxjAaRFfeRvh;ArLa0~G8b=UJwBYMaoF&XlA|D57?LFab_
z2y2@#XtO8N5tLIta>Ukb@
z4!l&R?Nk(4UQ^Z&Xm@=IS^~H69;^tjqA3HwI2Jp_w)$M0U
zp%lP)pCbgBh6Z>{1Z@g>)7#YhI&7x><_0N8+p}Zp@CWG8_52+kUCc;RL)^yA1#D&O
zW(@`VySP949snRA?eA`7;{^3)u!h<@xJrVKdiy~P4z`jYLm^FGO?P?d3kQ`zPpE#N
zmVr&6lZ}`yNLmU@!e9Imzy<1U#o+Ja?CK@%FA4e!SN!q%PcaXO;V%(yCrOZzrVfL=
zn%q&=YEvn_6l(Iw({q8^ioTB^e^==L*uu-;F;aQ-pk8i1
zo;FZLU#P1$)4xO5+WfPyU*_1_@IalRE{~#KkG=B!N0-W~nmYe%@rMF?2N(Ch
zT0N5eACleOZZVrQ&U{Q&Bo`Cda4SNpg;YK
z+q&5}*oyykDI&mU%WEwv$ZaJgCd4f$%qzxiWh-pUEy^b<#BVETB`Cxz_HR(Cu3p|&
zt~Ss=P>OB<>MB#dIYr=6BXd*<+FwILit1m_;{gzLD|}f
zE4g{PSUnD>gNv0tl*irG{;!HZgp14Ss7iwP!My(}(Q&r&wtH+K3DR(I_3{5#g@J<$
zRNvd`51V`#8PwD3(G&k*^6`QN1plh}Gc4kd#yk>h^~X;i
z0sbm~v_)Lr6Kdt{=4s&O<}3;NqY}fPmjA5Qd<-XBD{m_WD{tr{C@;UDIIplcuaE(s
zu(*JzxDX#FFTXhNzsbAVI@ksL-=zNp4}-+thFrzL>#_fUzl#1AQTkAizuo=q*4g2&
zP-0;CD=5URZ2o3~mz6Kn_AfmjvHn(N^TNv29{QL){_d{-D0lcjxPqOKot>?qkRZ2>
z7#}~kpq;2Fw>6*5<8bov*;?}n+SrIeZT=J8%gxT)&&m@jYyZgOBUg{^`4?9VPyQMx
z_WzXjdjb733Xgs|k)>wm<+|48`1-u3^C
zF06kor=YHnvmn36#Zuz2aM|NR3(Z;(W|6aM)ih1ot&
zdn`ovR@GEQ|Bi-=$0~67{^~0LzyMHHkTvjM`BCIo$P8Jy=-+(?@zX9|e$(8{#l=O*
zfAj`aK{^_MA@l%7flY0-h
znNu9%9#;JGFZw0MJ-u+(wV?g=4aqNlQ4U}i@{P5Rmc7}-)|~_27vr6|;n?-F7=qz9
zb!bT9275B!QN)2+5bFSyVJQ-8I;>ZhW!2hJ?vg^as+x{^8Ts=Stn3O^<_QLshsq*{
z*{W38F{=K~3Ld7f$exx~if=yrWYD%IQMkGP+4MjFGA#34nAm;rM=yDJ(@-n>4+NpS
zbC|;_XX9AZj6FUF+Q4riAD^a4^e;-fL_|jNrDU%xhm-Lw;i#r>`6;KksfJ=i41G2AVC!L|6mlEosLv1H-2;k*hq>Ym5R1
zyRi4J(92wQjv%4L!4=XGcd;9`c(1G_Mw^N;U0n
zrbjH;JL6DaBVAG*gA6uot>eiYWn|Mr$1q@vR7GGTkQtHNXeP2qGB(UtCRA!{@IGHg
z{kgMg%l#m_beMHZ75JYj0_LK|eRuB;aewA*P7cpHvj_t;P;>e4W-V2RbTDMznre{@
zu5V~YsZU$-F{7!4SCSYJ5l0#UxzmyuiIsQMt_^I=Bu>Kd>5lak+N*^B4YzCDj{Fw-
zAjhz~f;eQP`$ZvCibr7F!oX*VDJaWQYKaraj?6LVWJN`BYMzuStM^rYUnUhArGUzb
zCrXN(AjFr(O<+8h1&Uxsj$-~4M)GQqZRzcH>46hm|1W2G>(vt^GMW$AuLrt`y{c%e)hp`QLI;-_s@ic#z!I06c!1X%a8*_
zH?uol7UcJyRIfjLcvVtUtE1^S$OZJ3H%4nOYe&MBc{(9(iTg`?)1tI@(flt)V3ca7VBRnKTX>T0=aaLls8nYB!w~>nzmh{X6}xrYR_s6%fWl`9(C
z;%(C|QxQNl|1tBl`63&DDm
z#GF%a_u2iZk-hwH+2r8P8er=*tg
zqTKE?K}Q;jKSme%7doyBz-#0VhRe8Y7_!h}0i3E@Ca`&4+dYAwLJL)EPT@5b`dSa|
zJ27T6bLt=YiE~fA-i%x)aGV{9Wop8WSe9xR7U7NTo+$3-E(}#ewPsdyHGT2X8+LOx0&92SP-(F~q}lEbiwjrA~mP9atY7bZSqXC$>N
zB3S~$+~)FEoNvt;G0%+R2=}_m`sPEo1dg5tu5ps`;5ReO#&Wi{n5!XQd=KskO=0HxY#iU?r!uGo?7A)Aonxp<(x^{Qz(Er2DrLFPj^C=sSW_jwFp#3t%z9D9mpL!Fq!
zD~$LAlMz@KGK|)!68TuybQ%9M#NRY=xf^f2dmA+U^a_`z!`sUaRnk@ysYO0!zs5+-
zs+jqS_!GPL+0O+0oP$63px?7O)Ur~+7iK_ax+8Cd@{WHaMQv!X8Ub|{ieRfSNhf)o
z$24v$t|}@%`SE>$Pjp}sZoC(&dMN`1d9sU*AR!JC8iwG=i*Pf&3P$j6xEQs^(7;X0
zLAkgI3DvO@LpZO%sU-LMY$i+<1^5$pip*zh299bY!&R0&&Mi+rLvlJAy9mHs%ziPU
z@OEP=$#PrX*ZN_tb9ch@aPywc@FVTKemYKzZE#Lj!!x@0xRe4Sz#I|!GADWP#ku5j
zQJKEb|+Nti*!*^*3`$ho4
zxD?*s!f^v3Vv3m{#S{+>G!4QCl~|x`JrOw;-Vll!4Kp6ZSdoa4nSmjJF;WLjVnjLs
zhUtZ;VLaw<)B*5!QAaE#uM}w0^@?ztr^sG7Qtb=Wbk%UAfs_Jc+f_;x>*G`teHb)f
zC?y#3Tp#+h-OrJzHT0qS2mM^g|B+1pnzKkM%d!?IC8ycdnD
zjL2`f@N9!d-?;F-1&c?LpGU|>|mst@==$zMcmRER6~bv9BoaME~6vy?A7&^ii)
z$;aY`tj7`2i=?Q_wJ)s->%zuD^2U1e!qR1Nb}f|&16eL(Ad_2_jC|pz@i4UXnsd6h
zIwT>fg}}Jx^{k^6UGqbEfSLO>`m#qT(=bGv=tELcM%zu`%dRIh-D+l2bZ}`F7isCd*R_QgvJNU_Gg*;O}O7
ztOU*@dgU>J`qq=*Sn-VCpxPImqMaM3R;Kl>xMGgb--YWv$m@7wP_{lXmZ2`~CA^1z
z*_M7FHI(d4hX7|zGmo`5%_FOFf<4=bkX$ed$_r1vEqVMR^Qy%cE|sO@G$x{wKpog5
z8kB7--dug~7{RMkhcP)eEhVONhnLi9xeg)-Ecdh#9`mhV|IB!&6cFvhexYZ=sVPs9
z^OJu-zw28njg@G>XZW1tFi{&~(2$5B?H$XJpNwAE75Qy>IiGex_KkVnE+xCu3U9
zHn6tF5c&Dd!r5(G-4N>1#+X=tZ(LTFvj{eYX&SCb_LX$F**HI^t{rJY@O78GsQaFr
z-6|NAl!nEm7G@GTF}~5~wujmuG~*2c5C+I9+)vWG5v8TXkBKPmB)6F7$~!&kPKeZ3
z4S&B~p0788)B0u*!
za@R$$TBIx8pMR$6^Z)8|JNb^;`e7T9$cR77*ojcsA$Ux`Cor#z)ucIm2^iU`rr{EY
z20)hJG@@z(`4zL3oV~gKy6?vQ-04&yu{iAEWOOFn4M>lAPLf8exHF=AzGl&}L%wXs7?X1lJ1(AGL(=06c`M`O8izQrkQ
zUgC1AIj&%=eCagFe)`tojuJDiOJQEWqUCK2e*c#WFKKPraa`U@FwDiWa)6>(g!Tw0!rZNJQFV{Vr)umr%{BFr-Ao)IPDw_zNCHH;t%0uWhZ5|4&eSgE8B*~aq~2zR=FEbjGq!8y-v`=)MMr8WXvHORvR
zF`0gM6L-@nLs%v-eSERI(tYYDGFxn$H@B!{AC$&CrHj>y(*4Xe=)3OWnj8JOYos`G
zIG&R+<%gaqQAeP?@xcKc$6bSIp1vKwr2nu37~0*rLdW^}IjjBD{`Kya$8g-3eyG{U)OM-3$>1Al!YgS=(LvK0gZmR+3$81)
zPYcM+=5PC^PGXL?+j^`E?_t}a9GY@ryRbVLvc&9X6hqr?RDVK$GJiaO66IQVa^j4t
z4sLgxW_87lDYV}Rs!hVCei6V!4R_X@8pzUZlh-mK{M@ii+7`
zyCmatBic^NV}uS?Fk3afjh|%3bFKJ;Kjf3rbnMAV1q@9Kni%FT<@ZH(S!p^&hI1YuJx;jF
zMzO!3==OPdkCd{c8{+UqL%F2q_i`lLMPO~Wv*wyVXLJ(>W
zpK^mzfJ~%%E+~t2j;UKc+Lt*2f*(=dkc-lNfTWVQR$@Hg5xX1r6{pVguk_xVFe@l*$Fi_`=2`aoo*T^cV>(S%c%pD_D+iJa)IxaZ4
znmbwZUhMe5lv)FeMiFMFmbd0AqQtIJ(XTyu9wfNycRf5ry07`sRvdzv3$V~=YmQHo
zE`K8oU8N4k2hyweZsPtn3urpsO@3!BL48?RBKnT6eNVXm1s<8s10m#YBcRd=Hj&S*Gq$=Q(@HdMwRzo;j83t#&5Q`&J%P$m2bJma$
zN8rYQ0IaD(g8Q`eSRdZ=UbMYz)D5fe8@H4VA#yN4)P^e%(!zJy#&o;AFMuaMNIH}E4DZ6bT{mmr9C?JzL&QWVAL!==u(GB^O801thS3xpPkU+<8gl7
z#4M~a*=l3*k8->xSBN&7;HmlS#R*
zgyZ1Fv0fRK<1#`BC_M1kh+GI_UIWkZr(MrBET)kdSkk6mY<~L74RUwv4`Y#z_8~pl
zs-_GvF~D~3fQJUv2Yy`@Qit?MwT-0MR!Y1mN2KRa#{}hBu=bh-d(0Q(_Axuw@=)%_
z6NdYAJ1ZS4`l#=ugL-EQCU5YiG8NZbcbXFz%XqqarC)G7sIP5&I{Jb_v^~Z&+%xHo
zd3$)J6?(IIS3jx1teG@4a_Z_bM1Doem6kNV0xFm;d5Ow@SE%f}BacRdEKTp7i7V{;
zE#{*CP{*R9lvJN1T_x7bW`v|%LN#?%rC7(t8q)#)K)Qc-iKnSRmUvutZv$|z^HcnX
z-}|My{Wr(1UFcfmTT^`w33Jovt{U5YHRX~@kPYNpT=EBlb;U#JapE%xGcHZ4D}Hd5
zo%om&?8e~Chu8-hvi1QvQzT{U^aOJDrX}Ks?8-daZSnr6(@Aeawj?j=bCg3Ats0~%
zxCr%6iyU|nu{OG^?m{JT#VRG_4g^kq!o8V?|G5^ftSQrbe&RJ%#pK+`=2-X}@v{~%
zm+_(8j~uz}B~m#vvzpv!cLh@HaLwaR0M(YnQP^7A4?g@>J_WwFEy`I_Ywt|mzDo|#
zV>UB-cV5%qA1gf@`lUCX9_7;)T6jFQa?d!Q-V(qsJhPZUE*_zdU3rT#>VAE02P-=G
zlKBds&5$FFQ8qE1LjA+gkRA$m#7GTAV8nHjq2R8Rggk3n0OGYCdr?|Ucpd!G0ps?g
zX%=fHuP$UG(d%Vp9!=x3g$C9d)k#=ue;7W*rO+19E>U@Kj%gM=>YaLl9HzIRNF2fh
zaXDSA5n$RBII_lMpC43zWU+{S3*P*aitq&)qnxG;
zL#ljUMx6f{D|OqNa~XSd;ThNZ)>dY_i0k=AT9A8ZMlccb7NZf#O7
z!S_sK?*~_6WtbFz^B9hWb@fujX{uPx^Xbr&tFs+@4G~9^NAfc50wfpF1${xxic*&V&(%Z)gmn03r)={nP`J==sk5i;q)9kajCo
zWhmIzt_Z-%F3ihlqG3cU8K{kbXe>_`G%2a@r^iRY>b?lX$MfwkCTdrBc&JLr#kOk}
z0J9jI8+z4gorOrYGR+|1bDEtxmTiaQCQmQ1(?H5^ujU8^nrOUiFjbi=Yzv7sNw5x<
z^p=*#Rbzf=ngXJ`a#Y6i)hKA^HqL}lUhtoepw@=(#{cT3Hya?9RE*cdH&M21L#d2K
zL{pqCJ8g}DuqD^#Ut&IW>0oaF5(daw+3v%vlXSiufI(mWX%Kyu`{yIUyCn1w~Pbk!bR#mFu
z*#_S-ejU7b3qxGFwK3QiIPejZ)Y3r?DI->5WYa_LX+>A`GqEaS?igT>miz6Xdyf|x
zFOk!O{YTq@q!vl_@Ur!?IfD+L2=9IC&9y}P@m<4CABUlrpC$tq?1r^q;P=BH@SO#x
zW=vq(8rE%6Lz9xg7>!?&ZuL~WKi$8$t**3vvw^zX4C~
ze5s<41tUD%aajvCxneTd>FI#C{Xvf|=I5?T(!|^>SccsaTaQLZ@x}h=@#&E!6uoBO
zP89oA$HVU^e{(iG{O9-<5gRM&r)R|Wi${v4#`Lrhj8zL=fYm-uVDoR57=|{BFay;Pmr`{WxjAyqcmW01$Vmy9?lCK4``So?tt+v7r^-%IX
zNYL(iR}2wL9?Y0tD<;N9^sP^@jjf|l1krr5_A9om*7%GzU%Qz|Hw%7jxAZuimQZ4N
zHH-Gfcgf|2T3}5ZD)5Zbvp8eC<(0fGw_2)0lbfV#uyTl_#pBium2#Ab9&R(n7gI+_
zm4C!7O0uXs?=r`*moyWogfPt}7&G;C+?b)lj!9adGZG;?plQ^j%wVDqo}af<n@OHkNBArzBQNG47b
zP}t!w**CvhJqf>f`{>gOZ04UOJq8BP5uno6G>KFIkN9U)}57}F?iEAaqCZVgyw>g8DZ
z6UCxcQr?=EPu&kmm%KJsTzfPG91q5YqlTC*<4Ij;QUl0i=FyRw);y@mkbI0bnpE>j
zN+ZTf4Y|>bdMBg?N~KlOC*;u_$q0yNCGjat6AX)N3xhqGY?5k44a)LFJn_Cp4=oSH+GUmWB*_cAnJXa?(o7tE
z8vI}|kp-0`Ow+zXJtg`abg!1V#!8WxLelT;+M&=D`F+-=3$UjgZtreDt?o|Qtenih
zc;wZ!QqIXKW%`3#$6@81WI8LX_qqGU>CxwG_Vtc#P;0~M*`G#@c)W21lLJU|AKji8
zxV#?t^5T2^wBC@lu0Bc!1|uc4e#z07c^f=;p{;l|0!kvA;3w(jnE`1U^iTK}(Ie1}
zGP{f_7?3Z{2S!=s2!ZLE7%rAV6U8=X+eNQG(
zjWae;AW_@Si3??f1GKDz-7f%6NjM>mKe?}onDiZn;!|gIs
z&@xqp1Je}hhR`vqKEx;B5_Opv#zj(8j9K;m)W~=#
z9$o?J=$B}Nkj-fF4u#tcCG#<3R5B~@Q#zA0<8}QQAQwAe>;IOQ&M4p)zHMC|o8}7a
z*;Aj|v%%(xtVGCtTpRy!E$-{=;w}~|416Ck4r8z09EUOeIx#gu`eAL~&KqaHSATgm
zdHTUaz_?UFA&tuslnTq%P$3569*mj$vJrEZ`N)3x3f3M(%9yl8Gj|}7-x^27VI)LiDcv#m
z3Nts~iI?6Oq}6T$ZOm%4fR*j-i%~ql;P_aID1-+OE|EVikv`i*@hVrPs|?cw)DRf0
z9)o3J=fEM~nj3}l0b`LA*;Ycenm~n~#tGoN7R=s%zxwJFWq+cUB6hfZKc0w_Opui)
zkPGbPq@=bLaneT+OJikDGq=L%j5=EV=9K;x<+PY&_x8<%Vky_?R`5v{k7+)rxgV`B
zu8#DzRWy#ViB7jA*6Q_0X2SR!BAlK4YB!uoac73TmRSn`K6|jp{oOs?v~}|qj^ZXp
z=rF9iRJpK$znPoWA6r)j$r#T73yv3za2?lYuI?E#C(j_W%*W=eO#!quB
zB}4)kK}r(5dq~APmuIvoo+nHxzigF@yIcS(-av<0KrT6%Ul!l=7`{
z7F&+K^F5Rg-P-^3mA(9lQd_RVbw|@h6YLu1ylwpM6+g=M`QYrT>3d%#nw*sxZ_
zNp@Yz&cu@_;M19=SKJwub3NCdm@r);FLaE(5V}l2uZ`*}^miJNc(Pwm6
z>sPO;DMEvzFBex{_`GV5-3i}T*r8|t>=m>5x!}Nqv1p;QEhg;7$N~V-I=bHB&LW
z0r1a=E!^?xtnYuF+DPH3`EgR#!E8VZJD@$P#_u}m%Z0ux#ssXEdpH2!;J6^H3ZT(e
zH3_4H8B1Rs91b(|&Z?Dkunut|H~F1R1%#{V>48L1938oLx55
z|9+$EHs$trW6(A;!;eX&h&Q@4Rw3gz>U4wD1IOtb=CO{Z*9jo96bs3Q-DC
zq>9foWv(4}T;48|fwyNlgj>%nb5&u5MeX%euE<@$q4zEjncF$?y>mHR^0lW)?z3FEJom
zD#tlr^=-cO>`W4n_Y4^NJW)95o(i%CfjlTfnud+z+(xtBEf?f#L{+Te6c3EObco5I
zzy4JHVJbntc4H2W_a%UJ9L!U_V%ow0zFV`5bBSQZJab%j%PA`C9yL7KxSZ!
z+pujyqH{2$o7r6^Sg;|Mr?AJ+kdsOLz@HV)RONlEOqYf`mZ*>agNW~iIkjJX^y*?`
z`Q!494cU79gKDg0&AS)bycmRpLl`3z-&AhImQhnBL8<@ZTA
zKj#Hd;E@VAH8TsuzH3k?*MKe5cvX#vz-&+QU%2rd`(b(J)3bcI0=R-d*+385Y^$x#
z{7D58sn`b=gaIC0l$25`r!O{Nlq6lCn`K?pA(tbv8orCtKKIpfbTTxeLj%kV$|G+gj
z=mHQ%xqU}Mj&uKx!>4o{-MFa$aHmDAzaVOkHWk!5^}F>zHK;+OxMj>FG4loYS@UYW
z9lsH86*>F3N-1VpY(nFkyON8O&(U~+`*ws23xuYt2Wr?{>r`I{;;1&Tp1Wx|L)VKQ
zSaUjw>WzD|J6{$6vYkJ^Y{AU8)pcry*KjzlJs+|j9_B!G93RfU7PT9{
zU8dZ9p`3N&yhc_UMn+}O|e{+^dEdL}bsF>4!CA_>}Dz%CWrD_f1Aid0irc3@wW
z&XLOiocp{&!L#4gt9t(HuI+u4d
zyDtw#4Q{1)lLMwacI-Ma=aoNi9OO9e50o!oAURDy^uO!0$v{IARu^hO#urQ~)B%^FD
zS%i!0JufnAVW_R#Slrk{*3;^>mnghd*`wLr)*Ie*e{3P;vmh_AB?LvrR4nAgJ#ZXj
zBui`?!G(rTd?{bR`(!Qb(>YY%DfV_Il~We%acm-|p>#s+<~J}i>iSZ(7Eabf)YZ7v
z^-;Xp9S`guSjGnZp&>RPtTQfLKS#xjOJ?BT$Rql+Peswk%}iz|P5*Z4qWbpkX;o>G
zgZH-&9&e5^h+m)Z#c?>f4sy8@8hQsq3H}sKnD;k3iS|=y7
z*PKbiGDOSx;y+nsDB6ZMgT8meU#|9;wK_Mg4U@jo1Sa5SgdPfWlF_=KI@Q}B;&n`g
zpu|yFW3uO`mXBZd_%U8F?55yITB#V4e56(Kjv@rFwK
zXBQ3&Px5xiTvuU!b&EyGH_FRV(=bJd^f1bT=`DVG?W~)655