commit
41101217c6
@ -20,3 +20,5 @@ yarn-error.log
|
||||
/.npm
|
||||
/.bash_history
|
||||
/_data
|
||||
.rnd
|
||||
/.ssh
|
||||
|
@ -14,3 +14,9 @@ APP_URL=http://localhost
|
||||
APP_PORT=8000
|
||||
|
||||
DUSK_DRIVER_URL=http://selenium:4444
|
||||
|
||||
## For Andras only
|
||||
# To purge cache
|
||||
BUNNY_API_KEY=
|
||||
# To upload assets
|
||||
BUNNY_STORAGE_API_KEY=
|
||||
|
@ -1,6 +0,0 @@
|
||||
# Secrets related to pushing to GH, Sync files to BunnyCDN etc. Only for maintainers.
|
||||
# Not related to Coolify, but to how we publish new versions.
|
||||
|
||||
GITHUB_TOKEN=
|
||||
BUNNY_API_KEY=
|
||||
BUNNY_STORAGE_API_KEY=
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -29,3 +29,5 @@ _ide_helper.php
|
||||
.gitignore
|
||||
.phpstorm.meta.php
|
||||
_ide_helper_models.php
|
||||
.rnd
|
||||
/.ssh
|
||||
|
@ -17,7 +17,7 @@ class StartPostgresql
|
||||
public function __invoke(Server $server, StandalonePostgresql $database)
|
||||
{
|
||||
$this->database = $database;
|
||||
$container_name = generate_container_name($this->database->uuid);
|
||||
$container_name = $this->database->uuid;
|
||||
$this->configuration_dir = database_configuration_dir() . '/' . $container_name;
|
||||
|
||||
$this->commands = [
|
||||
@ -36,7 +36,7 @@ class StartPostgresql
|
||||
'image' => $this->database->image,
|
||||
'container_name' => $container_name,
|
||||
'environment' => $environment_variables,
|
||||
'restart' => 'always',
|
||||
'restart' => RESTART_MODE,
|
||||
'networks' => [
|
||||
$this->database->destination->network,
|
||||
],
|
||||
|
@ -14,14 +14,14 @@ class CheckResaleLicense
|
||||
$settings->update([
|
||||
'is_resale_license_active' => false,
|
||||
]);
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
return;
|
||||
}
|
||||
if (!$settings->resale_license) {
|
||||
return;
|
||||
}
|
||||
$base_url = config('coolify.license_url');
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
$base_url = 'http://host.docker.internal:8787';
|
||||
}
|
||||
$instance_id = config('app.id');
|
||||
|
@ -12,29 +12,38 @@ class InstallDocker
|
||||
{
|
||||
$dockerVersion = '23.0';
|
||||
$config = base64_encode('{ "live-restore": true }');
|
||||
$activity = remote_process([
|
||||
"echo ####### Installing Prerequisites...",
|
||||
"command -v jq >/dev/null || apt-get update",
|
||||
"command -v jq >/dev/null || apt install -y jq",
|
||||
"echo ####### Installing/updating Docker Engine...",
|
||||
"curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh",
|
||||
"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\"`\" || echo '{$config}' | base64 -d > /etc/docker/daemon.json",
|
||||
"echo '{$config}' | base64 -d > /etc/docker/daemon.json.coolify",
|
||||
"cat <<< $(jq . /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json.coolify",
|
||||
"cat <<< $(jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json",
|
||||
"echo ####### Restarting Docker Engine...",
|
||||
"systemctl restart docker",
|
||||
"echo ####### Creating default network...",
|
||||
"docker network create --attachable coolify",
|
||||
"echo ####### Done!"
|
||||
], $server);
|
||||
StandaloneDocker::create([
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify',
|
||||
'server_id' => $server->id,
|
||||
'team_id' => $team->id
|
||||
]);
|
||||
if (isDev()) {
|
||||
$activity = remote_process([
|
||||
"echo ####### Installing Prerequisites...",
|
||||
"echo ####### Installing/updating Docker Engine...",
|
||||
"echo ####### Configuring Docker Engine (merging existing configuration with the required)...",
|
||||
"echo ####### Restarting Docker Engine...",
|
||||
], $server);
|
||||
} else {
|
||||
$activity = remote_process([
|
||||
"echo ####### Installing Prerequisites...",
|
||||
"command -v jq >/dev/null || apt-get update",
|
||||
"command -v jq >/dev/null || apt install -y jq",
|
||||
"echo ####### Installing/updating Docker Engine...",
|
||||
"curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh",
|
||||
"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\"`\" || echo '{$config}' | base64 -d > /etc/docker/daemon.json",
|
||||
"echo '{$config}' | base64 -d > /etc/docker/daemon.json.coolify",
|
||||
"cat <<< $(jq . /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json.coolify",
|
||||
"cat <<< $(jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json",
|
||||
"echo ####### Restarting Docker Engine...",
|
||||
"systemctl restart docker",
|
||||
"echo ####### Creating default network...",
|
||||
"docker network create --attachable coolify",
|
||||
"echo ####### Done!"
|
||||
], $server);
|
||||
StandaloneDocker::create([
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify',
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
return $activity;
|
||||
}
|
||||
|
@ -17,9 +17,6 @@ class UpdateCoolify
|
||||
$settings = InstanceSettings::get();
|
||||
ray('Running InstanceAutoUpdateJob');
|
||||
$localhost_name = 'localhost';
|
||||
if (is_dev()) {
|
||||
$localhost_name = 'testing-local-docker-container';
|
||||
}
|
||||
$this->server = Server::where('name', $localhost_name)->firstOrFail();
|
||||
$this->latest_version = get_latest_version_of_coolify();
|
||||
$this->current_version = config('version');
|
||||
@ -32,27 +29,28 @@ class UpdateCoolify
|
||||
$this->update();
|
||||
} else {
|
||||
if (!$settings->is_auto_update_enabled) {
|
||||
throw new \Exception('Auto update is disabled');
|
||||
return 'Auto update is disabled';
|
||||
}
|
||||
if ($this->latest_version === $this->current_version) {
|
||||
throw new \Exception('Already on latest version');
|
||||
return 'Already on latest version';
|
||||
}
|
||||
if (version_compare($this->latest_version, $this->current_version, '<')) {
|
||||
throw new \Exception('Latest version is lower than current version?!');
|
||||
return 'Latest version is lower than current version?!';
|
||||
}
|
||||
$this->update();
|
||||
}
|
||||
return;
|
||||
} catch (\Exception $e) {
|
||||
send_internal_notification('InstanceAutoUpdateJob done to version: ' . $this->latest_version . ' from version: ' . $this->current_version);
|
||||
} catch (\Exception $th) {
|
||||
ray('InstanceAutoUpdateJob failed');
|
||||
ray($e->getMessage());
|
||||
return;
|
||||
ray($th->getMessage());
|
||||
send_internal_notification('InstanceAutoUpdateJob failed: ' . $th->getMessage());
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
private function update()
|
||||
{
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
ray("Running update on local docker container. Updating to $this->latest_version");
|
||||
remote_process([
|
||||
"sleep 10"
|
||||
|
@ -19,21 +19,29 @@ class InviteFromWaitlist extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'app:invite-from-waitlist';
|
||||
protected $signature = 'app:invite-from-waitlist {email?}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Send invitation to the next user in the waitlist';
|
||||
protected $description = 'Send invitation to the next user (or by email) in the waitlist';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->next_patient = Waitlist::orderBy('created_at', 'asc')->where('verified', true)->first();
|
||||
if ($this->argument('email')) {
|
||||
$this->next_patient = Waitlist::where('email', $this->argument('email'))->first();
|
||||
if (!$this->next_patient) {
|
||||
$this->error("{$this->argument('email')} not found in the waitlist.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$this->next_patient = Waitlist::orderBy('created_at', 'asc')->where('verified', true)->first();
|
||||
}
|
||||
if ($this->next_patient) {
|
||||
$this->register_user();
|
||||
$this->remove_from_waitlist();
|
||||
|
@ -18,7 +18,7 @@ class Kernel extends ConsoleKernel
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
// $schedule->call(fn() => $this->check_scheduled_backups($schedule))->everyTenSeconds();
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
$schedule->command('horizon:snapshot')->everyMinute();
|
||||
$schedule->job(new ResourceStatusJob)->everyMinute();
|
||||
$schedule->job(new ProxyCheckJob)->everyFiveMinutes();
|
||||
|
@ -45,7 +45,7 @@ class Handler extends ExceptionHandler
|
||||
{
|
||||
$this->reportable(function (Throwable $e) {
|
||||
$this->settings = InstanceSettings::get();
|
||||
if ($this->settings->do_not_track || is_dev()) {
|
||||
if ($this->settings->do_not_track || isDev()) {
|
||||
return;
|
||||
}
|
||||
Integration::captureUnhandledException($e);
|
||||
|
@ -12,7 +12,7 @@ class ApplicationController extends Controller
|
||||
|
||||
public function configuration()
|
||||
{
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
@ -29,7 +29,7 @@ class ApplicationController extends Controller
|
||||
|
||||
public function deployments()
|
||||
{
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
@ -49,7 +49,7 @@ class ApplicationController extends Controller
|
||||
{
|
||||
$deploymentUuid = request()->route('deployment_uuid');
|
||||
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ class Controller extends BaseController
|
||||
if (!is_cloud()) {
|
||||
abort(404);
|
||||
}
|
||||
return view('subscription', [
|
||||
return view('subscription.show', [
|
||||
'settings' => InstanceSettings::get(),
|
||||
]);
|
||||
}
|
||||
@ -58,7 +58,6 @@ class Controller extends BaseController
|
||||
$resources += $project->applications->count();
|
||||
$resources += $project->postgresqls->count();
|
||||
}
|
||||
|
||||
return view('dashboard', [
|
||||
'servers' => $servers->count(),
|
||||
'projects' => $projects->count(),
|
||||
@ -66,10 +65,17 @@ class Controller extends BaseController
|
||||
's3s' => $s3s,
|
||||
]);
|
||||
}
|
||||
public function boarding() {
|
||||
if (currentTeam()->boarding || isDev()) {
|
||||
return view('boarding');
|
||||
} else {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
}
|
||||
|
||||
public function settings()
|
||||
{
|
||||
if (is_instance_admin()) {
|
||||
if (isInstanceAdmin()) {
|
||||
$settings = InstanceSettings::get();
|
||||
$database = StandalonePostgresql::whereName('coolify-db')->first();
|
||||
if ($database) {
|
||||
@ -89,7 +95,7 @@ class Controller extends BaseController
|
||||
{
|
||||
$invitations = [];
|
||||
if (auth()->user()->isAdminFromSession()) {
|
||||
$invitations = TeamInvitation::whereTeamId(auth()->user()->currentTeam()->id)->get();
|
||||
$invitations = TeamInvitation::whereTeamId(currentTeam()->id)->get();
|
||||
}
|
||||
return view('team.show', [
|
||||
'invitations' => $invitations,
|
||||
@ -116,7 +122,7 @@ class Controller extends BaseController
|
||||
{
|
||||
$invitations = [];
|
||||
if (auth()->user()->isAdminFromSession()) {
|
||||
$invitations = TeamInvitation::whereTeamId(auth()->user()->currentTeam()->id)->get();
|
||||
$invitations = TeamInvitation::whereTeamId(currentTeam()->id)->get();
|
||||
}
|
||||
return view('team.members', [
|
||||
'invitations' => $invitations,
|
||||
|
@ -11,7 +11,7 @@ class DatabaseController extends Controller
|
||||
|
||||
public function configuration()
|
||||
{
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
@ -29,7 +29,7 @@ class DatabaseController extends Controller
|
||||
public function executions()
|
||||
{
|
||||
$backup_uuid = request()->route('backup_uuid');
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
@ -50,13 +50,13 @@ class DatabaseController extends Controller
|
||||
'database' => $database,
|
||||
'backup' => $backup,
|
||||
'executions' => $executions,
|
||||
's3s' => auth()->user()->currentTeam()->s3s,
|
||||
's3s' => currentTeam()->s3s,
|
||||
]);
|
||||
}
|
||||
|
||||
public function backups()
|
||||
{
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
@ -70,7 +70,7 @@ class DatabaseController extends Controller
|
||||
}
|
||||
return view('project.database.backups.all', [
|
||||
'database' => $database,
|
||||
's3s' => auth()->user()->currentTeam()->s3s,
|
||||
's3s' => currentTeam()->s3s,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class MagicController extends Controller
|
||||
{
|
||||
$project = Project::firstOrCreate(
|
||||
['name' => request()->query('name') ?? generate_random_name()],
|
||||
['team_id' => auth()->user()->currentTeam()->id]
|
||||
['team_id' => currentTeam()->id]
|
||||
);
|
||||
return response()->json([
|
||||
'project_uuid' => $project->uuid
|
||||
@ -68,7 +68,7 @@ class MagicController extends Controller
|
||||
],
|
||||
);
|
||||
auth()->user()->teams()->attach($team, ['role' => 'admin']);
|
||||
session(['currentTeam' => $team]);
|
||||
refreshSession();
|
||||
return redirect(request()->header('Referer'));
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ class ProjectController extends Controller
|
||||
public function edit()
|
||||
{
|
||||
$projectUuid = request()->route('project_uuid');
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
$teamId = currentTeam()->id;
|
||||
$project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
@ -29,7 +29,7 @@ class ProjectController extends Controller
|
||||
public function show()
|
||||
{
|
||||
$projectUuid = request()->route('project_uuid');
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
$teamId = currentTeam()->id;
|
||||
|
||||
$project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first();
|
||||
if (!$project) {
|
||||
@ -44,7 +44,7 @@ class ProjectController extends Controller
|
||||
$type = request()->query('type');
|
||||
$destination_uuid = request()->query('destination');
|
||||
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
@ -67,7 +67,7 @@ class ProjectController extends Controller
|
||||
|
||||
public function resources()
|
||||
{
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
|
@ -12,16 +12,16 @@ class ServerController extends Controller
|
||||
|
||||
public function new_server()
|
||||
{
|
||||
if (!is_cloud() || is_instance_admin()) {
|
||||
if (!is_cloud() || isInstanceAdmin()) {
|
||||
return view('server.create', [
|
||||
'limit_reached' => false,
|
||||
'private_keys' => PrivateKey::ownedByCurrentTeam()->get(),
|
||||
]);
|
||||
}
|
||||
$servers = auth()->user()->currentTeam()->servers->count();
|
||||
$subscription = auth()->user()->currentTeam()?->subscription->type();
|
||||
$limits = config('constants.limits.server')[strtolower($subscription)];
|
||||
$limit_reached = true ?? $servers >= $limits[$subscription];
|
||||
$servers = currentTeam()->servers->count();
|
||||
$subscription = currentTeam()?->subscription->type();
|
||||
$your_limit = config('constants.limits.server')[strtolower($subscription)];
|
||||
$limit_reached = $servers >= $your_limit;
|
||||
|
||||
return view('server.create', [
|
||||
'limit_reached' => $limit_reached,
|
||||
|
@ -39,6 +39,7 @@ class Kernel extends HttpKernel
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\CheckForcePasswordReset::class,
|
||||
\App\Http\Middleware\SubscriptionValid::class,
|
||||
\App\Http\Middleware\IsBoardingFlow::class,
|
||||
|
||||
],
|
||||
|
||||
|
181
app/Http/Livewire/Boarding.php
Normal file
181
app/Http/Livewire/Boarding.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Actions\Server\InstallDocker;
|
||||
use App\Models\PrivateKey;
|
||||
use App\Models\Project;
|
||||
use App\Models\Server;
|
||||
use Livewire\Component;
|
||||
|
||||
class Boarding extends Component
|
||||
{
|
||||
public string $currentState = 'welcome';
|
||||
|
||||
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 ?string $remoteServerName = null;
|
||||
public ?string $remoteServerDescription = null;
|
||||
public ?string $remoteServerHost = null;
|
||||
public ?int $remoteServerPort = 22;
|
||||
public ?string $remoteServerUser = 'root';
|
||||
public ?Server $createdServer = null;
|
||||
|
||||
public ?Project $createdProject = null;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$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 restartBoarding()
|
||||
{
|
||||
if ($this->createdServer) {
|
||||
$this->createdServer->delete();
|
||||
}
|
||||
if ($this->createdPrivateKey) {
|
||||
$this->createdPrivateKey->delete();
|
||||
}
|
||||
return redirect()->route('boarding');
|
||||
}
|
||||
public function skipBoarding()
|
||||
{
|
||||
currentTeam()->update([
|
||||
'show_boarding' => false
|
||||
]);
|
||||
refreshSession();
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
public function setServer(string $type)
|
||||
{
|
||||
if ($type === 'localhost') {
|
||||
$this->createdServer = Server::find(0);
|
||||
if (!$this->createdServer) {
|
||||
return $this->emit('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.');
|
||||
}
|
||||
$this->currentState = 'select-proxy';
|
||||
} elseif ($type === 'remote') {
|
||||
$this->currentState = 'private-key';
|
||||
}
|
||||
}
|
||||
public function setPrivateKey(string $type)
|
||||
{
|
||||
$this->privateKeyType = $type;
|
||||
if ($type === 'create' && !isDev()) {
|
||||
$this->createNewPrivateKey();
|
||||
}
|
||||
$this->currentState = 'create-private-key';
|
||||
}
|
||||
public function savePrivateKey()
|
||||
{
|
||||
$this->validate([
|
||||
'privateKeyName' => 'required',
|
||||
'privateKey' => 'required',
|
||||
]);
|
||||
$this->currentState = 'create-server';
|
||||
}
|
||||
public function saveServer()
|
||||
{
|
||||
$this->validate([
|
||||
'remoteServerName' => 'required',
|
||||
'remoteServerHost' => 'required',
|
||||
'remoteServerPort' => 'required',
|
||||
'remoteServerUser' => 'required',
|
||||
]);
|
||||
$this->privateKey = formatPrivateKey($this->privateKey);
|
||||
$this->createdPrivateKey = PrivateKey::create([
|
||||
'name' => $this->privateKeyName,
|
||||
'description' => $this->privateKeyDescription,
|
||||
'private_key' => $this->privateKey,
|
||||
'team_id' => currentTeam()->id
|
||||
]);
|
||||
$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
|
||||
]);
|
||||
try {
|
||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->createdServer);
|
||||
if (!$uptime) {
|
||||
$this->createdServer->delete();
|
||||
$this->createdPrivateKey->delete();
|
||||
throw new \Exception('Server is not reachable.');
|
||||
} else {
|
||||
$this->createdServer->settings->update([
|
||||
'is_reachable' => true,
|
||||
]);
|
||||
$this->emit('success', 'Server is reachable.');
|
||||
}
|
||||
if ($dockerVersion) {
|
||||
$this->emit('error', 'Docker is not installed on the server.');
|
||||
$this->currentState = 'install-docker';
|
||||
return;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
||||
}
|
||||
}
|
||||
public function installDocker()
|
||||
{
|
||||
$activity = resolve(InstallDocker::class)($this->createdServer, currentTeam());
|
||||
$this->emit('newMonitorActivity', $activity->id);
|
||||
$this->currentState = 'select-proxy';
|
||||
}
|
||||
public function selectProxy(string|null $proxyType = null)
|
||||
{
|
||||
if (!$proxyType) {
|
||||
return $this->currentState = 'create-project';
|
||||
}
|
||||
$this->createdServer->proxy->type = $proxyType;
|
||||
$this->createdServer->proxy->status = 'exited';
|
||||
$this->createdServer->save();
|
||||
$this->currentState = 'create-project';
|
||||
}
|
||||
public function createNewProject()
|
||||
{
|
||||
$this->createdProject = Project::create([
|
||||
'name' => "My first project",
|
||||
'team_id' => currentTeam()->id
|
||||
]);
|
||||
$this->currentState = 'create-resource';
|
||||
}
|
||||
public function showNewResource()
|
||||
{
|
||||
$this->skipBoarding();
|
||||
return redirect()->route(
|
||||
'project.resources.new',
|
||||
[
|
||||
'project_uuid' => $this->createdProject->uuid,
|
||||
'environment_name' => 'production',
|
||||
|
||||
]
|
||||
);
|
||||
}
|
||||
private function createNewPrivateKey()
|
||||
{
|
||||
$this->privateKeyName = generate_random_name();
|
||||
$this->privateKeyDescription = 'Created by Coolify';
|
||||
['private' => $this->privateKey, 'public'=> $this->publicKey] = generateSSHKey();
|
||||
}
|
||||
}
|
@ -60,20 +60,19 @@ class StandaloneDocker extends Component
|
||||
$found = $this->server->standaloneDockers()->where('network', $this->network)->first();
|
||||
if ($found) {
|
||||
$this->createNetworkAndAttachToProxy();
|
||||
$this->addError('network', 'Network already added to this server.');
|
||||
$this->emit('error', 'Network already added to this server.');
|
||||
return;
|
||||
} else {
|
||||
$docker = ModelsStandaloneDocker::create([
|
||||
'name' => $this->name,
|
||||
'network' => $this->network,
|
||||
'server_id' => $this->server_id,
|
||||
'team_id' => auth()->user()->currentTeam()->id
|
||||
]);
|
||||
}
|
||||
$this->createNetworkAndAttachToProxy();
|
||||
return redirect()->route('destination.show', $docker->uuid);
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e);
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,10 +41,9 @@ class DiscordSettings extends Component
|
||||
|
||||
public function saveModel()
|
||||
{
|
||||
ray($this->model);
|
||||
$this->model->save();
|
||||
if (is_a($this->model, Team::class)) {
|
||||
session(['currentTeam' => $this->model]);
|
||||
refreshSession();
|
||||
}
|
||||
$this->emit('success', 'Settings saved.');
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ class EmailSettings extends Component
|
||||
{
|
||||
$settings = InstanceSettings::get();
|
||||
if ($settings->smtp_enabled) {
|
||||
$team = auth()->user()->currentTeam();
|
||||
$team = currentTeam();
|
||||
$team->update([
|
||||
'smtp_enabled' => $settings->smtp_enabled,
|
||||
'smtp_from_address' => $settings->smtp_from_address,
|
||||
@ -74,7 +74,7 @@ class EmailSettings extends Component
|
||||
]);
|
||||
$this->decrypt();
|
||||
if (is_a($team, Team::class)) {
|
||||
session(['currentTeam' => $team]);
|
||||
refreshSession();
|
||||
}
|
||||
$this->model = $team;
|
||||
$this->emit('success', 'Settings saved.');
|
||||
@ -119,7 +119,7 @@ class EmailSettings extends Component
|
||||
$this->model->save();
|
||||
$this->decrypt();
|
||||
if (is_a($this->model, Team::class)) {
|
||||
session(['currentTeam' => $this->model]);
|
||||
refreshSession();
|
||||
}
|
||||
$this->emit('success', 'Settings saved.');
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class Change extends Component
|
||||
try {
|
||||
if ($this->private_key->isEmpty()) {
|
||||
$this->private_key->delete();
|
||||
auth()->user()->currentTeam()->privateKeys = PrivateKey::where('team_id', auth()->user()->currentTeam()->id)->get();
|
||||
currentTeam()->privateKeys = PrivateKey::where('team_id', currentTeam()->id)->get();
|
||||
return redirect()->route('private-key.all');
|
||||
}
|
||||
$this->emit('error', 'This private key is in use and cannot be deleted. Please delete all servers, applications, and GitHub/GitLab apps that use this private key before deleting it.');
|
||||
@ -38,10 +38,7 @@ class Change extends Component
|
||||
public function changePrivateKey()
|
||||
{
|
||||
try {
|
||||
$this->private_key->private_key = trim($this->private_key->private_key);
|
||||
if (!str_ends_with($this->private_key->private_key, "\n")) {
|
||||
$this->private_key->private_key .= "\n";
|
||||
}
|
||||
$this->private_key->private_key = formatPrivateKey($this->private_key->private_key);
|
||||
$this->private_key->save();
|
||||
refresh_server_connection($this->private_key);
|
||||
} catch (\Exception $e) {
|
||||
|
@ -32,7 +32,7 @@ class Create extends Component
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'private_key' => $this->value,
|
||||
'team_id' => auth()->user()->currentTeam()->id
|
||||
'team_id' => currentTeam()->id
|
||||
]);
|
||||
if ($this->from === 'server') {
|
||||
return redirect()->route('server.create');
|
||||
|
@ -25,7 +25,7 @@ class AddEmpty extends Component
|
||||
$project = Project::create([
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
'team_id' => currentTeam()->id,
|
||||
]);
|
||||
return redirect()->route('project.show', $project->uuid);
|
||||
} catch (\Exception $e) {
|
||||
|
@ -136,15 +136,20 @@ class General extends Component
|
||||
|
||||
public function submit()
|
||||
{
|
||||
ray($this->application);
|
||||
try {
|
||||
$this->validate();
|
||||
|
||||
$domains = Str::of($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
|
||||
return Str::of($domain)->trim()->lower();
|
||||
});
|
||||
$port = get_port_from_dockerfile($this->application->dockerfile);
|
||||
if ($port) {
|
||||
$this->application->ports_exposes = $port;
|
||||
if (data_get($this->application,'fqdn')) {
|
||||
$domains = Str::of($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
|
||||
return Str::of($domain)->trim()->lower();
|
||||
});
|
||||
$this->application->fqdn = $domains->implode(',');
|
||||
}
|
||||
if ($this->application->dockerfile) {
|
||||
$port = get_port_from_dockerfile($this->application->dockerfile);
|
||||
if ($port) {
|
||||
$this->application->ports_exposes = $port;
|
||||
}
|
||||
}
|
||||
if ($this->application->base_directory && $this->application->base_directory !== '/') {
|
||||
$this->application->base_directory = rtrim($this->application->base_directory, '/');
|
||||
@ -152,7 +157,6 @@ class General extends Component
|
||||
if ($this->application->publish_directory && $this->application->publish_directory !== '/') {
|
||||
$this->application->publish_directory = rtrim($this->application->publish_directory, '/');
|
||||
}
|
||||
$this->application->fqdn = data_get($domains->implode(','), '', null);
|
||||
$this->application->save();
|
||||
$this->emit('success', 'Application settings updated!');
|
||||
} catch (\Exception $e) {
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Livewire\Project\Application;
|
||||
|
||||
use App\Jobs\ContainerStatusJob;
|
||||
use App\Jobs\ApplicationContainerStatusJob;
|
||||
use App\Models\Application;
|
||||
use App\Notifications\Application\StatusChanged;
|
||||
use Livewire\Component;
|
||||
@ -22,9 +22,8 @@ class Heading extends Component
|
||||
|
||||
public function check_status()
|
||||
{
|
||||
dispatch_sync(new ContainerStatusJob(
|
||||
resource: $this->application,
|
||||
container_name: generate_container_name($this->application->uuid),
|
||||
dispatch_sync(new ApplicationContainerStatusJob(
|
||||
application: $this->application,
|
||||
));
|
||||
$this->application->refresh();
|
||||
}
|
||||
@ -58,12 +57,21 @@ class Heading extends Component
|
||||
|
||||
public function stop()
|
||||
{
|
||||
remote_process(
|
||||
["docker rm -f {$this->application->uuid}"],
|
||||
$this->application->destination->server
|
||||
);
|
||||
$this->application->status = 'stopped';
|
||||
$this->application->save();
|
||||
$this->application->environment->project->team->notify(new StatusChanged($this->application));
|
||||
$containers = getCurrentApplicationContainerStatus($this->application->destination->server, $this->application->id);
|
||||
if ($containers->count() === 0) {
|
||||
return;
|
||||
}
|
||||
foreach ($containers as $container) {
|
||||
$containerName = data_get($container, 'Names');
|
||||
if ($containerName) {
|
||||
remote_process(
|
||||
["docker rm -f {$containerName}"],
|
||||
$this->application->destination->server
|
||||
);
|
||||
$this->application->status = 'stopped';
|
||||
$this->application->save();
|
||||
// $this->application->environment->project->team->notify(new StatusChanged($this->application));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Livewire\Project\Application;
|
||||
|
||||
use App\Jobs\ContainerStatusJob;
|
||||
use App\Jobs\ApplicationContainerStatusJob;
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationPreview;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -25,10 +25,9 @@ class Previews extends Component
|
||||
|
||||
public function loadStatus($pull_request_id)
|
||||
{
|
||||
dispatch(new ContainerStatusJob(
|
||||
resource: $this->application,
|
||||
container_name: generate_container_name($this->application->uuid, $pull_request_id),
|
||||
pull_request_id: $pull_request_id
|
||||
dispatch(new ApplicationContainerStatusJob(
|
||||
application: $this->application,
|
||||
pullRequestId: $pull_request_id
|
||||
));
|
||||
}
|
||||
|
||||
@ -82,7 +81,7 @@ class Previews extends Component
|
||||
public function stop(int $pull_request_id)
|
||||
{
|
||||
try {
|
||||
$container_name = generate_container_name($this->application->uuid, $pull_request_id);
|
||||
$container_name = generateApplicationContainerName($this->application->uuid, $pull_request_id);
|
||||
ray('Stopping container: ' . $container_name);
|
||||
|
||||
instant_remote_process(["docker rm -f $container_name"], $this->application->destination->server, throwError: false);
|
||||
|
@ -29,7 +29,7 @@ class Source extends Component
|
||||
|
||||
private function get_private_keys()
|
||||
{
|
||||
$this->private_keys = PrivateKey::whereTeamId(auth()->user()->currentTeam()->id)->get()->reject(function ($key) {
|
||||
$this->private_keys = PrivateKey::whereTeamId(currentTeam()->id)->get()->reject(function ($key) {
|
||||
return $key->id == $this->application->private_key_id;
|
||||
});
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ class CreateScheduledBackup extends Component
|
||||
's3_storage_id' => $this->s3_storage_id,
|
||||
'database_id' => $this->database->id,
|
||||
'database_type' => $this->database->getMorphClass(),
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
'team_id' => currentTeam()->id,
|
||||
]);
|
||||
$this->emit('refreshScheduledBackups');
|
||||
} catch (\Exception $e) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace App\Http\Livewire\Project\Database;
|
||||
|
||||
use App\Actions\Database\StartPostgresql;
|
||||
use App\Jobs\ContainerStatusJob;
|
||||
use App\Jobs\DatabaseContainerStatusJob;
|
||||
use App\Notifications\Application\StatusChanged;
|
||||
use Livewire\Component;
|
||||
|
||||
@ -25,9 +25,8 @@ class Heading extends Component
|
||||
|
||||
public function check_status()
|
||||
{
|
||||
dispatch_sync(new ContainerStatusJob(
|
||||
resource: $this->database,
|
||||
container_name: generate_container_name($this->database->uuid),
|
||||
dispatch_sync(new DatabaseContainerStatusJob(
|
||||
database: $this->database,
|
||||
));
|
||||
$this->database->refresh();
|
||||
}
|
||||
@ -45,7 +44,7 @@ class Heading extends Component
|
||||
);
|
||||
$this->database->status = 'stopped';
|
||||
$this->database->save();
|
||||
$this->database->environment->project->team->notify(new StatusChanged($this->database));
|
||||
// $this->database->environment->project->team->notify(new StatusChanged($this->database));
|
||||
}
|
||||
|
||||
public function start()
|
||||
|
@ -11,7 +11,7 @@ class EmptyProject extends Component
|
||||
{
|
||||
$project = Project::create([
|
||||
'name' => generate_random_name(),
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
'team_id' => currentTeam()->id,
|
||||
]);
|
||||
return redirect()->route('project.show', ['project_uuid' => $project->uuid, 'environment_name' => 'production']);
|
||||
}
|
||||
|
@ -43,19 +43,19 @@ class GithubPrivateRepositoryDeployKey extends Component
|
||||
'publish_directory' => 'Publish directory',
|
||||
];
|
||||
private object $repository_url_parsed;
|
||||
private GithubApp|GitlabApp $git_source;
|
||||
private GithubApp|GitlabApp|null $git_source = null;
|
||||
private string $git_host;
|
||||
private string $git_repository;
|
||||
private string $git_branch;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
$this->repository_url = 'https://github.com/coollabsio/coolify-examples';
|
||||
}
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->query = request()->query();
|
||||
$this->private_keys = PrivateKey::where('team_id', auth()->user()->currentTeam()->id)->where('id', '!=', 0)->get();
|
||||
$this->private_keys = PrivateKey::where('team_id', currentTeam()->id)->where('id', '!=', 0)->get();
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
|
@ -45,7 +45,7 @@ class PublicGitRepository extends Component
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
$this->repository_url = 'https://github.com/coollabsio/coolify-examples';
|
||||
$this->port = 3000;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Http\Livewire\Project\New;
|
||||
|
||||
use App\Models\Server;
|
||||
use Countable;
|
||||
use Livewire\Component;
|
||||
|
||||
class Select extends Component
|
||||
@ -11,7 +12,7 @@ class Select extends Component
|
||||
public string $type;
|
||||
public string $server_id;
|
||||
public string $destination_uuid;
|
||||
public $servers = [];
|
||||
public Countable|array|Server $servers;
|
||||
public $destinations = [];
|
||||
public array $parameters;
|
||||
|
||||
@ -23,6 +24,13 @@ class Select extends Component
|
||||
public function set_type(string $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
if (count($this->servers) === 1) {
|
||||
$server = $this->servers->first();
|
||||
$this->set_server($server);
|
||||
if (count($server->destinations()) === 1) {
|
||||
$this->set_destination($server->destinations()->first()->uuid);
|
||||
}
|
||||
}
|
||||
$this->current_step = 'servers';
|
||||
}
|
||||
|
||||
@ -46,6 +54,6 @@ class Select extends Component
|
||||
|
||||
public function load_servers()
|
||||
{
|
||||
$this->servers = Server::ownedByCurrentTeam()->get();
|
||||
$this->servers = Server::isUsable()->get();
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class SimpleDockerfile extends Component
|
||||
{
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->query = request()->query();
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
$this->dockerfile = 'FROM nginx
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@ -59,6 +59,10 @@ CMD ["nginx", "-g", "daemon off;"]
|
||||
'source_id' => 0,
|
||||
'source_type' => GithubApp::class
|
||||
]);
|
||||
$application->update([
|
||||
'name' => 'dockerfile-' . $application->id
|
||||
]);
|
||||
|
||||
redirect()->route('project.application.configuration', [
|
||||
'application_uuid' => $application->uuid,
|
||||
'environment_name' => $environment->name,
|
||||
|
@ -42,7 +42,7 @@ class Form extends Component
|
||||
|
||||
public function installDocker()
|
||||
{
|
||||
$activity = resolve(InstallDocker::class)($this->server, auth()->user()->currentTeam());
|
||||
$activity = resolve(InstallDocker::class)($this->server, currentTeam());
|
||||
$this->emit('newMonitorActivity', $activity->id);
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ class ByIp extends Component
|
||||
'ip' => $this->ip,
|
||||
'user' => $this->user,
|
||||
'port' => $this->port,
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
'team_id' => currentTeam()->id,
|
||||
'private_key_id' => $this->private_key_id,
|
||||
]);
|
||||
$server->settings->is_part_of_swarm = $this->is_part_of_swarm;
|
||||
|
@ -35,7 +35,7 @@ class Proxy extends Component
|
||||
$this->emit('proxyStatusUpdated');
|
||||
}
|
||||
|
||||
public function select_proxy(string $proxy_type)
|
||||
public function select_proxy(ProxyTypes $proxy_type)
|
||||
{
|
||||
$this->server->proxy->type = $proxy_type;
|
||||
$this->server->proxy->status = 'exited';
|
||||
|
@ -17,7 +17,7 @@ class Deploy extends Component
|
||||
$this->server->proxy->last_applied_settings &&
|
||||
$this->server->proxy->last_saved_settings !== $this->server->proxy->last_applied_settings
|
||||
) {
|
||||
$this->emit('saveConfiguration', $server);
|
||||
$this->emit('saveConfiguration', $this->server);
|
||||
}
|
||||
$activity = resolve(StartProxy::class)($this->server);
|
||||
$this->emit('newMonitorActivity', $activity->id);
|
||||
|
@ -65,7 +65,7 @@ class Backup extends Component
|
||||
'frequency' => '0 0 * * *',
|
||||
'database_id' => $this->database->id,
|
||||
'database_type' => 'App\Models\StandalonePostgresql',
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
'team_id' => currentTeam()->id,
|
||||
]);
|
||||
$this->database->refresh();
|
||||
$this->backup->refresh();
|
||||
|
@ -40,7 +40,7 @@ class Create extends Component
|
||||
'custom_user' => $this->custom_user,
|
||||
'custom_port' => $this->custom_port,
|
||||
'is_system_wide' => $this->is_system_wide,
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
'team_id' => currentTeam()->id,
|
||||
]);
|
||||
redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
|
||||
} catch (\Exception $e) {
|
||||
|
@ -10,14 +10,14 @@ class Actions extends Component
|
||||
public function cancel()
|
||||
{
|
||||
try {
|
||||
$subscription_id = auth()->user()->currentTeam()->subscription->lemon_subscription_id;
|
||||
$subscription_id = currentTeam()->subscription->lemon_subscription_id;
|
||||
if (!$subscription_id) {
|
||||
throw new \Exception('No subscription found');
|
||||
}
|
||||
$response = Http::withHeaders([
|
||||
'Accept' => 'application/vnd.api+json',
|
||||
'Content-Type' => 'application/vnd.api+json',
|
||||
'Authorization' => 'Bearer ' . config('coolify.lemon_squeezy_api_key'),
|
||||
'Authorization' => 'Bearer ' . config('subscription.lemon_squeezy_api_key'),
|
||||
])->delete('https://api.lemonsqueezy.com/v1/subscriptions/' . $subscription_id);
|
||||
$json = $response->json();
|
||||
if ($response->failed()) {
|
||||
@ -37,14 +37,14 @@ class Actions extends Component
|
||||
public function resume()
|
||||
{
|
||||
try {
|
||||
$subscription_id = auth()->user()->currentTeam()->subscription->lemon_subscription_id;
|
||||
$subscription_id = currentTeam()->subscription->lemon_subscription_id;
|
||||
if (!$subscription_id) {
|
||||
throw new \Exception('No subscription found');
|
||||
}
|
||||
$response = Http::withHeaders([
|
||||
'Accept' => 'application/vnd.api+json',
|
||||
'Content-Type' => 'application/vnd.api+json',
|
||||
'Authorization' => 'Bearer ' . config('coolify.lemon_squeezy_api_key'),
|
||||
'Authorization' => 'Bearer ' . config('subscription.lemon_squeezy_api_key'),
|
||||
])->patch('https://api.lemonsqueezy.com/v1/subscriptions/' . $subscription_id, [
|
||||
'data' => [
|
||||
'type' => 'subscriptions',
|
||||
@ -69,4 +69,8 @@ class Actions extends Component
|
||||
return general_error_handler($e, $this);
|
||||
}
|
||||
}
|
||||
public function stripeCustomerPortal() {
|
||||
$session = getStripeCustomerPortalSession(currentTeam());
|
||||
redirect($session->url);
|
||||
}
|
||||
}
|
||||
|
66
app/Http/Livewire/Subscription/PricingPlans.php
Normal file
66
app/Http/Livewire/Subscription/PricingPlans.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Subscription;
|
||||
|
||||
use Livewire\Component;
|
||||
use Stripe\Stripe;
|
||||
use Stripe\Checkout\Session;
|
||||
|
||||
class PricingPlans extends Component
|
||||
{
|
||||
public function subscribeStripe($type)
|
||||
{
|
||||
Stripe::setApiKey(config('subscription.stripe_api_key'));
|
||||
switch ($type) {
|
||||
case 'basic-monthly':
|
||||
$priceId = config('subscription.stripe_price_id_basic_monthly');
|
||||
break;
|
||||
case 'basic-yearly':
|
||||
$priceId = config('subscription.stripe_price_id_basic_yearly');
|
||||
break;
|
||||
case 'ultimate-monthly':
|
||||
$priceId = config('subscription.stripe_price_id_ultimate_monthly');
|
||||
break;
|
||||
case 'pro-monthly':
|
||||
$priceId = config('subscription.stripe_price_id_pro_monthly');
|
||||
break;
|
||||
case 'pro-yearly':
|
||||
$priceId = config('subscription.stripe_price_id_pro_yearly');
|
||||
break;
|
||||
case 'ultimate-yearly':
|
||||
$priceId = config('subscription.stripe_price_id_ultimate_yearly');
|
||||
break;
|
||||
default:
|
||||
$priceId = config('subscription.stripe_price_id_basic_monthly');
|
||||
break;
|
||||
}
|
||||
if (!$priceId) {
|
||||
$this->emit('error', 'Price ID not found! Please contact the administrator.');
|
||||
return;
|
||||
}
|
||||
$payload = [
|
||||
'client_reference_id' => auth()->user()->id . ':' . currentTeam()->id,
|
||||
'line_items' => [[
|
||||
'price' => $priceId,
|
||||
'quantity' => 1,
|
||||
]],
|
||||
'tax_id_collection' => [
|
||||
'enabled' => true,
|
||||
],
|
||||
'mode' => 'subscription',
|
||||
'success_url' => route('subscription.success'),
|
||||
'cancel_url' => route('subscription.show',['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);
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ class Create extends Component
|
||||
'personal_team' => false,
|
||||
]);
|
||||
auth()->user()->teams()->attach($team, ['role' => 'admin']);
|
||||
session(['currentTeam' => $team]);
|
||||
refreshSession();
|
||||
return redirect()->route('team.show');
|
||||
} catch (\Throwable $th) {
|
||||
return general_error_handler($th, $this);
|
||||
|
@ -9,7 +9,7 @@ class Delete extends Component
|
||||
{
|
||||
public function delete()
|
||||
{
|
||||
$currentTeam = auth()->user()->currentTeam();
|
||||
$currentTeam = currentTeam();
|
||||
$currentTeam->delete();
|
||||
|
||||
$team = auth()->user()->teams()->first();
|
||||
@ -24,7 +24,7 @@ class Delete extends Component
|
||||
}
|
||||
});
|
||||
|
||||
session(['currentTeam' => $team]);
|
||||
refreshSession();
|
||||
return redirect()->route('team.show');
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class Form extends Component
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->team = auth()->user()->currentTeam();
|
||||
$this->team = currentTeam();
|
||||
}
|
||||
|
||||
public function submit()
|
||||
@ -27,7 +27,7 @@ class Form extends Component
|
||||
$this->validate();
|
||||
try {
|
||||
$this->team->save();
|
||||
session(['currentTeam' => $this->team]);
|
||||
refreshSession();
|
||||
$this->emit('reloadWindow');
|
||||
} catch (\Throwable $th) {
|
||||
return general_error_handler($th, $this);
|
||||
|
@ -18,6 +18,6 @@ class Invitations extends Component
|
||||
|
||||
public function refreshInvitations()
|
||||
{
|
||||
$this->invitations = TeamInvitation::whereTeamId(auth()->user()->currentTeam()->id)->get();
|
||||
$this->invitations = TeamInvitation::whereTeamId(currentTeam()->id)->get();
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ class InviteLink extends Component
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->email = is_dev() ? 'test3@example.com' : '';
|
||||
$this->email = isDev() ? 'test3@example.com' : '';
|
||||
}
|
||||
|
||||
public function viaEmail()
|
||||
@ -35,9 +35,9 @@ class InviteLink extends Component
|
||||
return general_error_handler(that: $this, customErrorMessage: "$this->email must be registered first (or activate transactional emails to invite via email).");
|
||||
}
|
||||
|
||||
$member_emails = auth()->user()->currentTeam()->members()->get()->pluck('email');
|
||||
$member_emails = currentTeam()->members()->get()->pluck('email');
|
||||
if ($member_emails->contains($this->email)) {
|
||||
return general_error_handler(that: $this, customErrorMessage: "$this->email is already a member of " . auth()->user()->currentTeam()->name . ".");
|
||||
return general_error_handler(that: $this, customErrorMessage: "$this->email is already a member of " . currentTeam()->name . ".");
|
||||
}
|
||||
|
||||
$invitation = TeamInvitation::whereEmail($this->email);
|
||||
@ -53,7 +53,7 @@ class InviteLink extends Component
|
||||
}
|
||||
|
||||
TeamInvitation::firstOrCreate([
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
'team_id' => currentTeam()->id,
|
||||
'uuid' => $uuid,
|
||||
'email' => $this->email,
|
||||
'role' => $this->role,
|
||||
|
@ -11,19 +11,19 @@ class Member extends Component
|
||||
|
||||
public function makeAdmin()
|
||||
{
|
||||
$this->member->teams()->updateExistingPivot(auth()->user()->currentTeam()->id, ['role' => 'admin']);
|
||||
$this->member->teams()->updateExistingPivot(currentTeam()->id, ['role' => 'admin']);
|
||||
$this->emit('reloadWindow');
|
||||
}
|
||||
|
||||
public function makeReadonly()
|
||||
{
|
||||
$this->member->teams()->updateExistingPivot(auth()->user()->currentTeam()->id, ['role' => 'member']);
|
||||
$this->member->teams()->updateExistingPivot(currentTeam()->id, ['role' => 'member']);
|
||||
$this->emit('reloadWindow');
|
||||
}
|
||||
|
||||
public function remove()
|
||||
{
|
||||
$this->member->teams()->detach(auth()->user()->currentTeam());
|
||||
$this->member->teams()->detach(currentTeam());
|
||||
$this->emit('reloadWindow');
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ class Create extends Component
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
$this->name = 'Local MinIO';
|
||||
$this->description = 'Local MinIO';
|
||||
$this->key = 'minioadmin';
|
||||
@ -62,7 +62,7 @@ class Create extends Component
|
||||
} else {
|
||||
$this->storage->endpoint = $this->endpoint;
|
||||
}
|
||||
$this->storage->team_id = auth()->user()->currentTeam()->id;
|
||||
$this->storage->team_id = currentTeam()->id;
|
||||
$this->storage->testConnection();
|
||||
$this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
|
||||
$this->storage->save();
|
||||
|
@ -18,7 +18,7 @@ class Upgrade extends Component
|
||||
$this->latestVersion = get_latest_version_of_coolify();
|
||||
$currentVersion = config('version');
|
||||
version_compare($currentVersion, $this->latestVersion, '<') ? $this->isUpgradeAvailable = true : $this->isUpgradeAvailable = false;
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
$this->isUpgradeAvailable = true;
|
||||
}
|
||||
$settings = InstanceSettings::get();
|
||||
|
@ -17,7 +17,7 @@ class Waitlist extends Component
|
||||
];
|
||||
public function mount()
|
||||
{
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
$this->email = 'waitlist@example.com';
|
||||
}
|
||||
}
|
||||
|
24
app/Http/Middleware/IsBoardingFlow.php
Normal file
24
app/Http/Middleware/IsBoardingFlow.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class IsBoardingFlow
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
// ray('IsBoardingFlow Middleware');
|
||||
if (showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) {
|
||||
return redirect('boarding');
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@ -10,6 +10,9 @@ class SubscriptionValid
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (isInstanceAdmin()) {
|
||||
return $next($request);
|
||||
}
|
||||
if (!auth()->user() || !is_cloud()) {
|
||||
if ($request->path() === 'subscription') {
|
||||
return redirect('/');
|
||||
@ -17,32 +20,17 @@ class SubscriptionValid
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
$is_instance_admin = is_instance_admin();
|
||||
if ($is_instance_admin) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
if (is_subscription_active() && $request->path() === 'subscription') {
|
||||
if (isSubscriptionActive() && $request->path() === 'subscription') {
|
||||
// ray('active subscription Middleware');
|
||||
return redirect('/');
|
||||
}
|
||||
if (is_subscription_in_grace_period()) {
|
||||
if (isSubscriptionOnGracePeriod()) {
|
||||
// ray('is_subscription_in_grace_period Middleware');
|
||||
return $next($request);
|
||||
}
|
||||
if (!is_subscription_active() && !is_subscription_in_grace_period()) {
|
||||
ray('SubscriptionValid Middleware');
|
||||
|
||||
$allowed_paths = [
|
||||
'subscription',
|
||||
'login',
|
||||
'register',
|
||||
'waitlist',
|
||||
'force-password-reset',
|
||||
'logout',
|
||||
'livewire/message/force-password-reset',
|
||||
'livewire/message/check-license',
|
||||
'livewire/message/switch-team',
|
||||
];
|
||||
if (!in_array($request->path(), $allowed_paths)) {
|
||||
if (!isSubscriptionActive() && !isSubscriptionOnGracePeriod()) {
|
||||
// ray('SubscriptionValid Middleware');
|
||||
if (!in_array($request->path(), allowedPathsForUnsubscribedAccounts())) {
|
||||
return redirect('subscription');
|
||||
} else {
|
||||
return $next($request);
|
||||
|
54
app/Jobs/ApplicationContainerStatusJob.php
Normal file
54
app/Jobs/ApplicationContainerStatusJob.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationPreview;
|
||||
use App\Notifications\Application\StatusChanged;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ApplicationContainerStatusJob implements ShouldQueue, ShouldBeUnique
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public string $containerName;
|
||||
|
||||
public function __construct(
|
||||
public Application $application,
|
||||
public int $pullRequestId = 0)
|
||||
{
|
||||
$this->containerName = generateApplicationContainerName($application->uuid, $pullRequestId);
|
||||
}
|
||||
|
||||
public function uniqueId(): string
|
||||
{
|
||||
return $this->containerName;
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
$status = getApplicationContainerStatus(application: $this->application);
|
||||
if ($this->application->status === 'running' && $status !== 'running') {
|
||||
// $this->application->environment->project->team->notify(new StatusChanged($this->application));
|
||||
}
|
||||
|
||||
if ($this->pullRequestId !== 0) {
|
||||
$preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->application->id, $this->pullRequestId);
|
||||
$preview->status = $status;
|
||||
$preview->save();
|
||||
} else {
|
||||
$this->application->status = $status;
|
||||
$this->application->save();
|
||||
}
|
||||
} catch (\Exception $th) {
|
||||
ray($th->getMessage());
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
}
|
@ -50,6 +50,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
||||
private ApplicationPreview|null $preview = null;
|
||||
|
||||
private string $container_name;
|
||||
private string|null $currently_running_container_name = null;
|
||||
private string $workdir;
|
||||
private string $configuration_dir;
|
||||
private string $build_workdir;
|
||||
@ -86,7 +87,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
||||
$this->build_workdir = "{$this->workdir}" . rtrim($this->application->base_directory, '/');
|
||||
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
||||
|
||||
$this->container_name = generate_container_name($this->application->uuid, $this->pull_request_id);
|
||||
$this->container_name = generateApplicationContainerName($this->application->uuid, $this->pull_request_id);
|
||||
$this->private_key_location = save_private_key_for_server($this->server);
|
||||
$this->saved_outputs = collect();
|
||||
|
||||
@ -113,6 +114,10 @@ class ApplicationDeploymentJob implements ShouldQueue
|
||||
public function handle(): void
|
||||
{
|
||||
// ray()->measure();
|
||||
$containers = getCurrentApplicationContainerStatus($this->server, $this->application->id);
|
||||
if ($containers->count() > 0) {
|
||||
$this->currently_running_container_name = data_get($containers[0], 'Names');
|
||||
}
|
||||
$this->application_deployment_queue->update([
|
||||
'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
|
||||
]);
|
||||
@ -131,6 +136,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
||||
} catch (Exception $e) {
|
||||
ray($e);
|
||||
$this->fail($e);
|
||||
throw $e;
|
||||
} finally {
|
||||
if (isset($this->docker_compose_base64)) {
|
||||
$readme = generate_readme_file($this->application->name, $this->application_deployment_queue->updated_at);
|
||||
@ -175,9 +181,9 @@ class ApplicationDeploymentJob implements ShouldQueue
|
||||
$this->generate_build_env_variables();
|
||||
$this->add_build_env_variables_to_dockerfile();
|
||||
$this->build_image();
|
||||
$this->stop_running_container();
|
||||
$this->start_by_compose_file();
|
||||
$this->rolling_update();
|
||||
}
|
||||
|
||||
private function deploy()
|
||||
{
|
||||
$this->execute_remote_command(
|
||||
@ -206,8 +212,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
||||
"echo 'Docker Image found locally with the same Git Commit SHA {$this->application->uuid}:{$this->commit}. Build step skipped...'"
|
||||
]);
|
||||
$this->generate_compose_file();
|
||||
$this->stop_running_container();
|
||||
$this->start_by_compose_file();
|
||||
$this->rolling_update();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -219,8 +224,54 @@ class ApplicationDeploymentJob implements ShouldQueue
|
||||
$this->generate_build_env_variables();
|
||||
$this->add_build_env_variables_to_dockerfile();
|
||||
$this->build_image();
|
||||
$this->stop_running_container();
|
||||
$this->rolling_update();
|
||||
}
|
||||
|
||||
private function rolling_update()
|
||||
{
|
||||
$this->start_by_compose_file();
|
||||
$this->health_check();
|
||||
$this->stop_running_container();
|
||||
}
|
||||
private function health_check()
|
||||
{
|
||||
ray('New container name: ',$this->container_name);
|
||||
if ($this->container_name) {
|
||||
$counter = 0;
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo 'Waiting for health check to pass on the new version of your application.'"
|
||||
],
|
||||
);
|
||||
while ($counter < $this->application->health_check_retries) {
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo 'Attempt {$counter} of {$this->application->health_check_retries}'"
|
||||
],
|
||||
[
|
||||
"docker inspect --format='{{json .State.Health.Status}}' {$this->container_name}",
|
||||
"hidden" => true,
|
||||
"save" => "health_check"
|
||||
],
|
||||
|
||||
);
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo 'New application version health check status: {$this->saved_outputs->get('health_check')}'"
|
||||
],
|
||||
);
|
||||
if (Str::of($this->saved_outputs->get('health_check'))->contains('healthy')) {
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo 'Rolling update completed.'"
|
||||
],
|
||||
);
|
||||
break;
|
||||
}
|
||||
$counter++;
|
||||
sleep($this->application->health_check_interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
private function deploy_pull_request()
|
||||
{
|
||||
@ -241,8 +292,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
||||
// $this->generate_build_env_variables();
|
||||
// $this->add_build_env_variables_to_dockerfile();
|
||||
$this->build_image();
|
||||
$this->stop_running_container();
|
||||
$this->start_by_compose_file();
|
||||
$this->rolling_update();
|
||||
}
|
||||
|
||||
private function prepare_builder_image()
|
||||
@ -409,7 +459,7 @@ class ApplicationDeploymentJob implements ShouldQueue
|
||||
$this->container_name => [
|
||||
'image' => $this->production_image_name,
|
||||
'container_name' => $this->container_name,
|
||||
'restart' => 'always',
|
||||
'restart' => RESTART_MODE,
|
||||
'environment' => $environment_variables,
|
||||
'labels' => $this->set_labels_for_applications(),
|
||||
'expose' => $ports,
|
||||
@ -539,8 +589,8 @@ class ApplicationDeploymentJob implements ShouldQueue
|
||||
$schema = $url->getScheme();
|
||||
$slug = Str::slug($host . $path);
|
||||
|
||||
$http_label = "{$this->application->uuid}-{$slug}-http";
|
||||
$https_label = "{$this->application->uuid}-{$slug}-https";
|
||||
$http_label = "{$this->container_name}-{$slug}-http";
|
||||
$https_label = "{$this->container_name}-{$slug}-https";
|
||||
|
||||
if ($schema === 'https') {
|
||||
// Set labels for https
|
||||
@ -647,23 +697,22 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
|
||||
private function stop_running_container()
|
||||
{
|
||||
$this->execute_remote_command(
|
||||
["echo -n 'Removing old running application.'"],
|
||||
[$this->execute_in_builder("docker rm -f $this->container_name >/dev/null 2>&1"), "hidden" => true],
|
||||
);
|
||||
if ($this->currently_running_container_name) {
|
||||
$this->execute_remote_command(
|
||||
["echo -n 'Removing old application version.'"],
|
||||
[$this->execute_in_builder("docker rm -f $this->currently_running_container_name >/dev/null 2>&1"), "hidden" => true],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function start_by_compose_file()
|
||||
{
|
||||
$this->execute_remote_command(
|
||||
["echo -n 'Starting new application... '"],
|
||||
["echo -n 'Rolling update started.'"],
|
||||
[$this->execute_in_builder("docker compose --project-directory {$this->workdir} up -d >/dev/null"), "hidden" => true],
|
||||
["echo 'Done. 🎉'"],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function generate_build_env_variables()
|
||||
{
|
||||
$this->build_args = collect(["--build-arg SOURCE_COMMIT={$this->commit}"]);
|
||||
|
@ -22,7 +22,9 @@ class CheckResaleLicenseJob implements ShouldQueue
|
||||
try {
|
||||
resolve(CheckResaleLicense::class)();
|
||||
} catch (\Throwable $th) {
|
||||
send_internal_notification('CheckResaleLicenseJob failed with: ' . $th->getMessage());
|
||||
ray($th);
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ class CleanupInstanceStuffsJob implements ShouldQueue, ShouldBeUnique
|
||||
} catch (\Exception $e) {
|
||||
send_internal_notification('CleanupInstanceStuffsJob failed with error: ' . $e->getMessage());
|
||||
ray($e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\ApplicationPreview;
|
||||
use App\Notifications\Application\StatusChanged;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ContainerStatusJob implements ShouldQueue, ShouldBeUnique
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public string $container_name;
|
||||
public string|null $pull_request_id;
|
||||
public $resource;
|
||||
|
||||
public function __construct($resource, string $container_name, string|null $pull_request_id = null)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
$this->container_name = $container_name;
|
||||
$this->pull_request_id = $pull_request_id;
|
||||
}
|
||||
|
||||
public function uniqueId(): string
|
||||
{
|
||||
return $this->container_name;
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
$status = get_container_status(server: $this->resource->destination->server, container_id: $this->container_name, throwError: false);
|
||||
if ($this->resource->status === 'running' && $status !== 'running') {
|
||||
$this->resource->environment->project->team->notify(new StatusChanged($this->resource));
|
||||
}
|
||||
|
||||
if ($this->pull_request_id) {
|
||||
$preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->resource->id, $this->pull_request_id);
|
||||
$preview->status = $status;
|
||||
$preview->save();
|
||||
} else {
|
||||
$this->resource->status = $status;
|
||||
$this->resource->save();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
ray($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,6 @@ class CoolifyTask implements ShouldQueue
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
|
||||
$remote_process = resolve(RunRemoteProcess::class, [
|
||||
'activity' => $this->activity,
|
||||
'ignore_errors' => $this->ignore_errors,
|
||||
|
@ -64,35 +64,42 @@ class DatabaseBackupJob implements ShouldQueue
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
if ($this->database_status !== 'running') {
|
||||
ray('database not running');
|
||||
return;
|
||||
}
|
||||
$this->container_name = $this->database->uuid;
|
||||
$this->backup_dir = backup_dir() . "/databases/" . Str::of($this->team->name)->slug() . '-' . $this->team->id . '/' . $this->container_name;
|
||||
try {
|
||||
if ($this->database_status !== 'running') {
|
||||
ray('database not running');
|
||||
return;
|
||||
}
|
||||
$this->container_name = $this->database->uuid;
|
||||
$this->backup_dir = backup_dir() . "/databases/" . Str::of($this->team->name)->slug() . '-' . $this->team->id . '/' . $this->container_name;
|
||||
|
||||
if ($this->database->name === 'coolify-db') {
|
||||
$this->container_name = "coolify-db";
|
||||
$ip = Str::slug($this->server->ip);
|
||||
$this->backup_dir = backup_dir() . "/coolify" . "/coolify-db-$ip";
|
||||
}
|
||||
$this->backup_file = "/dumpall-" . Carbon::now()->timestamp . ".sql";
|
||||
$this->backup_location = $this->backup_dir . $this->backup_file;
|
||||
if ($this->database->name === 'coolify-db') {
|
||||
$this->container_name = "coolify-db";
|
||||
$ip = Str::slug($this->server->ip);
|
||||
$this->backup_dir = backup_dir() . "/coolify" . "/coolify-db-$ip";
|
||||
}
|
||||
$this->backup_file = "/dumpall-" . Carbon::now()->timestamp . ".sql";
|
||||
$this->backup_location = $this->backup_dir . $this->backup_file;
|
||||
|
||||
$this->backup_log = ScheduledDatabaseBackupExecution::create([
|
||||
'filename' => $this->backup_location,
|
||||
'scheduled_database_backup_id' => $this->backup->id,
|
||||
]);
|
||||
if ($this->database_type === 'standalone-postgresql') {
|
||||
$this->backup_standalone_postgresql();
|
||||
$this->backup_log = ScheduledDatabaseBackupExecution::create([
|
||||
'filename' => $this->backup_location,
|
||||
'scheduled_database_backup_id' => $this->backup->id,
|
||||
]);
|
||||
if ($this->database_type === 'standalone-postgresql') {
|
||||
$this->backup_standalone_postgresql();
|
||||
}
|
||||
$this->calculate_size();
|
||||
$this->remove_old_backups();
|
||||
if ($this->backup->save_s3) {
|
||||
$this->upload_to_s3();
|
||||
}
|
||||
$this->save_backup_logs();
|
||||
// TODO: Notify user
|
||||
} catch (\Throwable $th) {
|
||||
ray($th->getMessage());
|
||||
send_internal_notification('DatabaseBackupJob failed with: ' . $th->getMessage());
|
||||
throw $th;
|
||||
}
|
||||
$this->calculate_size();
|
||||
$this->remove_old_backups();
|
||||
if ($this->backup->save_s3) {
|
||||
$this->upload_to_s3();
|
||||
}
|
||||
$this->save_backup_logs();
|
||||
// TODO: Notify user
|
||||
|
||||
}
|
||||
|
||||
private function backup_standalone_postgresql(): void
|
||||
|
56
app/Jobs/DatabaseContainerStatusJob.php
Normal file
56
app/Jobs/DatabaseContainerStatusJob.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\ApplicationPreview;
|
||||
use App\Models\StandalonePostgresql;
|
||||
use App\Notifications\Application\StatusChanged;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class DatabaseContainerStatusJob implements ShouldQueue, ShouldBeUnique
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public string $containerName;
|
||||
|
||||
public function __construct(
|
||||
public StandalonePostgresql $database,
|
||||
) {
|
||||
$this->containerName = $database->uuid;
|
||||
}
|
||||
|
||||
public function uniqueId(): string
|
||||
{
|
||||
return $this->containerName;
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
$status = getContainerStatus(
|
||||
server: $this->database->destination->server,
|
||||
container_id: $this->containerName,
|
||||
throwError: false
|
||||
);
|
||||
|
||||
if ($this->database->status === 'running' && $status !== 'running') {
|
||||
if (data_get($this->database, 'environment.project.team')) {
|
||||
// $this->database->environment->project->team->notify(new StatusChanged($this->database));
|
||||
}
|
||||
}
|
||||
if ($this->database->status !== $status) {
|
||||
$this->database->status = $status;
|
||||
$this->database->save();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
send_internal_notification('DatabaseContainerStatusJob failed with: ' . $e->getMessage());
|
||||
ray($e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@ class DockerCleanupJob implements ShouldQueue
|
||||
try {
|
||||
$servers = Server::all();
|
||||
foreach ($servers as $server) {
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
$docker_root_filesystem = "/";
|
||||
} else {
|
||||
$docker_root_filesystem = instant_remote_process(['stat --printf=%m $(docker info --format "{{json .DockerRootDir}}" |sed \'s/"//g\')'], $server);
|
||||
@ -49,14 +49,17 @@ class DockerCleanupJob implements ShouldQueue
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
send_internal_notification('DockerCleanupJob failed with: ' . $e->getMessage());
|
||||
ray($e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function get_disk_usage(Server $server, string $docker_root_filesystem)
|
||||
{
|
||||
$disk_usage = json_decode(instant_remote_process(['df -hP | awk \'BEGIN {printf"{\"disks\":["}{if($1=="Filesystem")next;if(a)printf",";printf"{\"mount\":\""$6"\",\"size\":\""$2"\",\"used\":\""$3"\",\"avail\":\""$4"\",\"use%\":\""$5"\"}";a++;}END{print"]}";}\''], $server), true);
|
||||
$disk_usage = json_decode(instant_remote_process(['df -hP | awk \'BEGIN {printf"{\\"disks\\":["}{if($1=="Filesystem")next;if(a)printf",";printf"{\\"mount\\":\\""$6"\\",\\"size\\":\\""$2"\\",\\"used\\":\\""$3"\\",\\"avail\\":\\""$4"\\",\\"use%\\":\\""$5"\\"}";a++;}END{print"]}";}\''], $server), true);
|
||||
$mount_point = collect(data_get($disk_usage, 'disks'))->where('mount', $docker_root_filesystem)->first();
|
||||
ray($mount_point);
|
||||
return Str::of(data_get($mount_point, 'use%'))->trim()->replace('%', '')->value();
|
||||
}
|
||||
}
|
||||
|
@ -22,9 +22,14 @@ class ProxyCheckJob implements ShouldQueue
|
||||
{
|
||||
try {
|
||||
$container_name = 'coolify-proxy';
|
||||
$servers = Server::isUsable()->whereNotNull('proxy')->get();
|
||||
$servers = Server::all();
|
||||
foreach ($servers as $server) {
|
||||
$status = get_container_status(server: $server, container_id: $container_name);
|
||||
if (
|
||||
$server->settings->is_reachable === false || $server->settings->is_usable === false
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
$status = getContainerStatus(server: $server, container_id: $container_name);
|
||||
if ($status === 'running') {
|
||||
continue;
|
||||
}
|
||||
@ -33,7 +38,8 @@ class ProxyCheckJob implements ShouldQueue
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
ray($th->getMessage());
|
||||
//throw $th;
|
||||
send_internal_notification('ProxyCheckJob failed with: ' . $th->getMessage());
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,9 +39,9 @@ class ProxyContainerStatusJob implements ShouldQueue, ShouldBeUnique
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
$container = get_container_status(server: $this->server, all_data: true, container_id: 'coolify-proxy', throwError: true);
|
||||
$status = $container['State']['Status'];
|
||||
if ($this->server->proxy->status !== $status) {
|
||||
$container = getContainerStatus(server: $this->server, all_data: true, container_id: 'coolify-proxy', throwError: true);
|
||||
$status = data_get($container, 'State.Status');
|
||||
if (data_get($this->server,'proxy.status') !== $status) {
|
||||
$this->server->proxy->status = $status;
|
||||
if ($this->server->proxy->status === 'running') {
|
||||
$traefik = $container['Config']['Labels']['org.opencontainers.image.title'];
|
||||
@ -57,6 +57,9 @@ class ProxyContainerStatusJob implements ShouldQueue, ShouldBeUnique
|
||||
$this->server->proxy->status = 'exited';
|
||||
$this->server->save();
|
||||
}
|
||||
send_internal_notification('ProxyContainerStatusJob failed with: ' . $e->getMessage());
|
||||
ray($e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,14 +23,15 @@ class ProxyStartJob implements ShouldQueue
|
||||
try {
|
||||
$container_name = 'coolify-proxy';
|
||||
ray('Starting proxy for server: ' . $this->server->name);
|
||||
$status = get_container_status(server: $this->server, container_id: $container_name);
|
||||
$status = getContainerStatus(server: $this->server, container_id: $container_name);
|
||||
if ($status === 'running') {
|
||||
return;
|
||||
}
|
||||
resolve(StartProxy::class)($this->server);
|
||||
} catch (\Throwable $th) {
|
||||
send_internal_notification('ProxyStartJob failed with: ' . $th->getMessage());
|
||||
ray($th->getMessage());
|
||||
//throw $th;
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\StandalonePostgresql;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
@ -15,23 +16,31 @@ class ResourceStatusJob implements ShouldQueue, ShouldBeUnique
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $applications;
|
||||
public $postgresqls;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->applications = Application::all();
|
||||
$this->postgresqls = StandalonePostgresql::all();
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
foreach ($this->applications as $application) {
|
||||
dispatch(new ContainerStatusJob(
|
||||
resource: $application,
|
||||
container_name: generate_container_name($application->uuid),
|
||||
dispatch(new ApplicationContainerStatusJob(
|
||||
application: $application,
|
||||
));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
ray($e->getMessage());
|
||||
foreach ($this->postgresqls as $postgresql) {
|
||||
dispatch(new DatabaseContainerStatusJob(
|
||||
database: $postgresql,
|
||||
));
|
||||
}
|
||||
} catch (\Exception $th) {
|
||||
send_internal_notification('ResourceStatusJob failed with: ' . $th->getMessage());
|
||||
ray($th);
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
app/Jobs/SubscriptionInvoiceFailedJob.php
Executable file
43
app/Jobs/SubscriptionInvoiceFailedJob.php
Executable file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Team;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Stripe\Stripe;
|
||||
|
||||
class SubscriptionInvoiceFailedJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public function __construct(protected Team $team)
|
||||
{
|
||||
}
|
||||
|
||||
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) {
|
||||
ray($member);
|
||||
if ($member->isAdmin()) {
|
||||
send_user_an_email($mail, $member->email);
|
||||
}
|
||||
});
|
||||
} catch (\Throwable $th) {
|
||||
send_internal_notification('SubscriptionInvoiceFailedJob failed with: ' . $th->getMessage());
|
||||
ray($th->getMessage());
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
}
|
@ -41,7 +41,7 @@ class EnvironmentVariable extends Model
|
||||
|
||||
private function get_environment_variables(string $environment_variable): string|null
|
||||
{
|
||||
// $team_id = auth()->user()->currentTeam()->id;
|
||||
// $team_id = currentTeam()->id;
|
||||
if (str_contains(trim($environment_variable), '{{') && str_contains(trim($environment_variable), '}}')) {
|
||||
$environment_variable = preg_replace('/\s+/', '', $environment_variable);
|
||||
$environment_variable = str_replace('{{', '', $environment_variable);
|
||||
|
@ -19,12 +19,12 @@ class GithubApp extends BaseModel
|
||||
|
||||
static public function public()
|
||||
{
|
||||
return GithubApp::whereTeamId(auth()->user()->currentTeam()->id)->whereisPublic(true)->whereNotNull('app_id')->get();
|
||||
return GithubApp::whereTeamId(currentTeam()->id)->whereisPublic(true)->whereNotNull('app_id')->get();
|
||||
}
|
||||
|
||||
static public function private()
|
||||
{
|
||||
return GithubApp::whereTeamId(auth()->user()->currentTeam()->id)->whereisPublic(false)->whereNotNull('app_id')->get();
|
||||
return GithubApp::whereTeamId(currentTeam()->id)->whereisPublic(false)->whereNotNull('app_id')->get();
|
||||
}
|
||||
|
||||
protected static function booted(): void
|
||||
|
@ -16,7 +16,7 @@ class PrivateKey extends BaseModel
|
||||
static public function ownedByCurrentTeam(array $select = ['*'])
|
||||
{
|
||||
$selectArray = collect($select)->concat(['id']);
|
||||
return PrivateKey::whereTeamId(auth()->user()->currentTeam()->id)->select($selectArray->all());
|
||||
return PrivateKey::whereTeamId(currentTeam()->id)->select($selectArray->all());
|
||||
}
|
||||
|
||||
public function isEmpty()
|
||||
|
@ -4,16 +4,11 @@ namespace App\Models;
|
||||
|
||||
class Project extends BaseModel
|
||||
{
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'description',
|
||||
'team_id',
|
||||
'project_id'
|
||||
];
|
||||
protected $guarded = [];
|
||||
|
||||
static public function ownedByCurrentTeam()
|
||||
{
|
||||
return Project::whereTeamId(auth()->user()->currentTeam()->id)->orderBy('name');
|
||||
return Project::whereTeamId(currentTeam()->id)->orderBy('name');
|
||||
}
|
||||
|
||||
protected static function booted()
|
||||
|
@ -17,7 +17,7 @@ class S3Storage extends BaseModel
|
||||
static public function ownedByCurrentTeam(array $select = ['*'])
|
||||
{
|
||||
$selectArray = collect($select)->concat(['id']);
|
||||
return S3Storage::whereTeamId(auth()->user()->currentTeam()->id)->select($selectArray->all())->orderBy('name');
|
||||
return S3Storage::whereTeamId(currentTeam()->id)->select($selectArray->all())->orderBy('name');
|
||||
}
|
||||
|
||||
public function awsUrl()
|
||||
|
@ -10,21 +10,40 @@ class Server extends BaseModel
|
||||
{
|
||||
use SchemalessAttributesTrait;
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::created(function ($server) {
|
||||
ServerSetting::create([
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
if ($server->id === 0) {
|
||||
StandaloneDocker::create([
|
||||
'id' => 0,
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify',
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
} else {
|
||||
StandaloneDocker::create([
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify',
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
}
|
||||
|
||||
});
|
||||
static::deleting(function ($server) {
|
||||
$server->settings()->delete();
|
||||
});
|
||||
}
|
||||
|
||||
public $casts = [
|
||||
'proxy' => SchemalessAttributes::class,
|
||||
];
|
||||
protected $schemalessAttributes = [
|
||||
'proxy',
|
||||
];
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'ip',
|
||||
'user',
|
||||
'port',
|
||||
'team_id',
|
||||
'private_key_id',
|
||||
'proxy',
|
||||
];
|
||||
protected $guarded = [];
|
||||
|
||||
static public function isReachable()
|
||||
{
|
||||
@ -33,8 +52,9 @@ class Server extends BaseModel
|
||||
|
||||
static public function ownedByCurrentTeam(array $select = ['*'])
|
||||
{
|
||||
$teamId = currentTeam()->id;
|
||||
$selectArray = collect($select)->concat(['id']);
|
||||
return Server::whereTeamId(auth()->user()->currentTeam()->id)->with('settings')->select($selectArray->all())->orderBy('name');
|
||||
return Server::whereTeamId($teamId)->with('settings')->select($selectArray->all())->orderBy('name');
|
||||
}
|
||||
|
||||
static public function isUsable()
|
||||
@ -50,17 +70,7 @@ class Server extends BaseModel
|
||||
return $standaloneDocker->concat($swarmDocker);
|
||||
}
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::created(function ($server) {
|
||||
ServerSetting::create([
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
});
|
||||
static::deleting(function ($server) {
|
||||
$server->settings()->delete();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public function settings()
|
||||
{
|
||||
|
@ -14,9 +14,9 @@ class Subscription extends Model
|
||||
}
|
||||
public function type()
|
||||
{
|
||||
$basic = explode(',', config('coolify.lemon_squeezy_basic_plan_ids'));
|
||||
$pro = explode(',', config('coolify.lemon_squeezy_pro_plan_ids'));
|
||||
$ultimate = explode(',', config('coolify.lemon_squeezy_ultimate_plan_ids'));
|
||||
$basic = explode(',', config('subscription.lemon_squeezy_basic_plan_ids'));
|
||||
$pro = explode(',', config('subscription.lemon_squeezy_pro_plan_ids'));
|
||||
$ultimate = explode(',', config('subscription.lemon_squeezy_ultimate_plan_ids'));
|
||||
|
||||
$subscription = $this->lemon_variant_id;
|
||||
if (in_array($subscription, $basic)) {
|
||||
|
@ -22,6 +22,7 @@ class User extends Authenticatable implements SendsEmail
|
||||
protected $casts = [
|
||||
'email_verified_at' => 'datetime',
|
||||
'force_password_reset' => 'boolean',
|
||||
'show_boarding' => 'boolean',
|
||||
];
|
||||
|
||||
protected static function boot()
|
||||
@ -102,7 +103,7 @@ class User extends Authenticatable implements SendsEmail
|
||||
|
||||
public function otherTeams()
|
||||
{
|
||||
$team_id = auth()->user()->currentTeam()->id;
|
||||
$team_id = currentTeam()->id;
|
||||
return auth()->user()->teams->filter(function ($team) use ($team_id) {
|
||||
return $team->id != $team_id;
|
||||
});
|
||||
@ -113,13 +114,6 @@ class User extends Authenticatable implements SendsEmail
|
||||
if ($this->teams()->where('team_id', 0)->first()) {
|
||||
return 'admin';
|
||||
}
|
||||
return $this->teams()->where('team_id', auth()->user()->currentTeam()->id)->first()->pivot->role;
|
||||
}
|
||||
|
||||
public function resources()
|
||||
{
|
||||
$team_id = auth()->user()->currentTeam()->id;
|
||||
$data = Application::where('team_id', $team_id)->get();
|
||||
return $data;
|
||||
return $this->teams()->where('team_id', currentTeam()->id)->first()->pivot->role;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ class Webhook extends Model
|
||||
{
|
||||
protected $guarded = [];
|
||||
protected $casts = [
|
||||
'type' => 'string',
|
||||
'payload' => 'encrypted',
|
||||
];
|
||||
}
|
||||
|
@ -14,6 +14,9 @@ class DiscordChannel
|
||||
{
|
||||
$message = $notification->toDiscord($notifiable);
|
||||
$webhookUrl = $notifiable->routeNotificationForDiscord();
|
||||
if (!$webhookUrl) {
|
||||
return;
|
||||
}
|
||||
dispatch(new SendMessageToDiscordJob($message, $webhookUrl));
|
||||
}
|
||||
}
|
||||
|
@ -6,13 +6,13 @@ use Exception;
|
||||
use Illuminate\Mail\Message;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class EmailChannel
|
||||
{
|
||||
public function send(SendsEmail $notifiable, Notification $notification): void
|
||||
{
|
||||
$this->bootConfigs($notifiable);
|
||||
ray($notification);
|
||||
$recepients = $notifiable->getRecepients($notification);
|
||||
|
||||
if (count($recepients) === 0) {
|
||||
@ -39,16 +39,21 @@ class EmailChannel
|
||||
$password = data_get($notifiable, 'smtp_password');
|
||||
if ($password) $password = decrypt($password);
|
||||
|
||||
config()->set('mail.default', 'smtp');
|
||||
config()->set('mail.mailers.smtp', [
|
||||
"transport" => "smtp",
|
||||
"host" => data_get($notifiable, 'smtp_host'),
|
||||
"port" => data_get($notifiable, 'smtp_port'),
|
||||
"encryption" => data_get($notifiable, 'smtp_encryption'),
|
||||
"username" => data_get($notifiable, 'smtp_username'),
|
||||
"password" => $password,
|
||||
"timeout" => data_get($notifiable, 'smtp_timeout'),
|
||||
"local_domain" => null,
|
||||
]);
|
||||
if (Str::contains(data_get($notifiable, 'smtp_host'),'resend.com')) {
|
||||
config()->set('mail.default', 'resend');
|
||||
config()->set('resend.api_key', $password);
|
||||
} else {
|
||||
config()->set('mail.default', 'smtp');
|
||||
config()->set('mail.mailers.smtp', [
|
||||
"transport" => "smtp",
|
||||
"host" => data_get($notifiable, 'smtp_host'),
|
||||
"port" => data_get($notifiable, 'smtp_port'),
|
||||
"encryption" => data_get($notifiable, 'smtp_encryption'),
|
||||
"username" => data_get($notifiable, 'smtp_username'),
|
||||
"password" => $password,
|
||||
"timeout" => data_get($notifiable, 'smtp_timeout'),
|
||||
"local_domain" => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,3 +9,4 @@ const VALID_CRON_STRINGS = [
|
||||
'monthly' => '0 0 1 * *',
|
||||
'yearly' => '0 0 1 1 *',
|
||||
];
|
||||
const RESTART_MODE = 'unless-stopped';
|
||||
|
@ -1,14 +1,27 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
function getCurrentApplicationContainerStatus(Server $server, int $id): Collection {
|
||||
$containers = instant_remote_process(["docker ps -a --filter='label=coolify.applicationId={$id}' --format '{{json .}}' "], $server);
|
||||
if (!$containers) {
|
||||
return collect([]);
|
||||
}
|
||||
return format_docker_command_output_to_json($containers);
|
||||
}
|
||||
|
||||
function format_docker_command_output_to_json($rawOutput): Collection
|
||||
{
|
||||
$outputLines = explode(PHP_EOL, $rawOutput);
|
||||
|
||||
return collect($outputLines)
|
||||
if (count($outputLines) === 1) {
|
||||
$outputLines = collect($outputLines[0]);
|
||||
} else {
|
||||
$outputLines = collect($outputLines);
|
||||
}
|
||||
return $outputLines
|
||||
->reject(fn ($line) => empty($line))
|
||||
->map(fn ($outputLine) => json_decode($outputLine, true, flags: JSON_THROW_ON_ERROR));
|
||||
}
|
||||
@ -44,9 +57,20 @@ function format_docker_envs_to_json($rawOutput)
|
||||
}
|
||||
}
|
||||
|
||||
function get_container_status(Server $server, string $container_id, bool $all_data = false, bool $throwError = false)
|
||||
function getApplicationContainerStatus(Application $application) {
|
||||
$server = $application->destination->server;
|
||||
$id = $application->id;
|
||||
|
||||
$containers = getCurrentApplicationContainerStatus($server, $id);
|
||||
if ($containers->count() > 0) {
|
||||
$status = data_get($containers[0], 'State', 'exited');
|
||||
return $status;
|
||||
}
|
||||
return 'exited';
|
||||
}
|
||||
function getContainerStatus(Server $server, string $container_id, bool $all_data = false, bool $throwError = false)
|
||||
{
|
||||
check_server_connection($server);
|
||||
// check_server_connection($server);
|
||||
$container = instant_remote_process(["docker inspect --format '{{json .}}' {$container_id}"], $server, $throwError);
|
||||
if (!$container) {
|
||||
return 'exited';
|
||||
@ -58,12 +82,13 @@ function get_container_status(Server $server, string $container_id, bool $all_da
|
||||
return data_get($container[0], 'State.Status', 'exited');
|
||||
}
|
||||
|
||||
function generate_container_name(string $uuid, int $pull_request_id = 0)
|
||||
function generateApplicationContainerName(string $uuid, int $pull_request_id = 0)
|
||||
{
|
||||
if ($pull_request_id !== 0) {
|
||||
return $uuid . '-pr-' . $pull_request_id;
|
||||
$now = now()->format('YmdHis');
|
||||
if ($pull_request_id !== 0 && $pull_request_id !== null) {
|
||||
return $uuid . '-pr-' . $pull_request_id . '-' . $now;
|
||||
} else {
|
||||
return $uuid;
|
||||
return $uuid . '-' . $now;
|
||||
}
|
||||
}
|
||||
function get_port_from_dockerfile($dockerfile): int
|
||||
|
@ -32,7 +32,7 @@ function generate_default_proxy_configuration(Server $server)
|
||||
"traefik" => [
|
||||
"container_name" => "coolify-proxy",
|
||||
"image" => "traefik:v2.10",
|
||||
"restart" => "always",
|
||||
"restart" => RESTART_MODE,
|
||||
"extra_hosts" => [
|
||||
"host.docker.internal:host-gateway",
|
||||
],
|
||||
@ -82,7 +82,7 @@ function generate_default_proxy_configuration(Server $server)
|
||||
],
|
||||
],
|
||||
];
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
$config['services']['traefik']['command'][] = "--log.level=debug";
|
||||
}
|
||||
return Yaml::dump($config, 4, 2);
|
||||
|
@ -66,8 +66,6 @@ function get_private_key_for_server(Server $server)
|
||||
function save_private_key_for_server(Server $server)
|
||||
{
|
||||
if (data_get($server, 'privateKey.private_key') === null) {
|
||||
$server->settings->is_reachable = false;
|
||||
$server->settings->save();
|
||||
throw new \Exception("Server {$server->name} does not have a private key");
|
||||
}
|
||||
$temp_file = "id.root@{$server->ip}";
|
||||
@ -159,8 +157,8 @@ function refresh_server_connection(PrivateKey $private_key)
|
||||
// Delete the old ssh mux file to force a new one to be created
|
||||
Storage::disk('ssh-mux')->delete($server->muxFilename());
|
||||
// check if user is authenticated
|
||||
if (auth()?->user()?->currentTeam()->id) {
|
||||
auth()->user()->currentTeam()->privateKeys = PrivateKey::where('team_id', auth()->user()->currentTeam()->id)->get();
|
||||
if (currentTeam()->id) {
|
||||
currentTeam()->privateKeys = PrivateKey::where('team_id', currentTeam()->id)->get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use Illuminate\Support\Str;
|
||||
use Nubs\RandomNameGenerator\All;
|
||||
use Poliander\Cron\CronExpression;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
use phpseclib3\Crypt\RSA;
|
||||
|
||||
function application_configuration_dir(): string
|
||||
{
|
||||
@ -35,11 +36,25 @@ function generate_readme_file(string $name, string $updated_at): string
|
||||
return "Resource name: $name\nLatest Deployment Date: $updated_at";
|
||||
}
|
||||
|
||||
function is_instance_admin()
|
||||
function isInstanceAdmin()
|
||||
{
|
||||
return auth()->user()?->isInstanceAdmin();
|
||||
return auth()?->user()?->isInstanceAdmin() ?? false;
|
||||
}
|
||||
|
||||
function currentTeam()
|
||||
{
|
||||
return auth()?->user()?->currentTeam() ?? null;
|
||||
}
|
||||
|
||||
function showBoarding(): bool
|
||||
{
|
||||
return currentTeam()->show_boarding ?? false;
|
||||
}
|
||||
function refreshSession(): void
|
||||
{
|
||||
$team = currentTeam();
|
||||
session(['currentTeam' => $team]);
|
||||
}
|
||||
function general_error_handler(Throwable | null $err = null, $that = null, $isJson = false, $customErrorMessage = null): mixed
|
||||
{
|
||||
try {
|
||||
@ -97,7 +112,21 @@ function generate_random_name(): string
|
||||
$cuid = new Cuid2(7);
|
||||
return Str::kebab("{$generator->getName()}-$cuid");
|
||||
}
|
||||
|
||||
function generateSSHKey()
|
||||
{
|
||||
$key = RSA::createKey();
|
||||
return [
|
||||
'private' => $key->toString('PKCS1'),
|
||||
'public' => $key->getPublicKey()->toString('OpenSSH',['comment' => 'coolify-generated-ssh-key'])
|
||||
];
|
||||
}
|
||||
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 = new Cuid2(7);
|
||||
@ -134,7 +163,7 @@ function set_transanctional_email_settings(InstanceSettings | null $settings = n
|
||||
|
||||
function base_ip(): string
|
||||
{
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
return "localhost";
|
||||
}
|
||||
$settings = InstanceSettings::get();
|
||||
@ -159,12 +188,12 @@ function base_url(bool $withPort = true): string
|
||||
$port = config('app.port');
|
||||
if ($settings->public_ipv4) {
|
||||
if ($withPort) {
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
return "http://localhost:$port";
|
||||
}
|
||||
return "http://$settings->public_ipv4:$port";
|
||||
}
|
||||
if (is_dev()) {
|
||||
if (isDev()) {
|
||||
return "http://localhost";
|
||||
}
|
||||
return "http://$settings->public_ipv4";
|
||||
@ -178,7 +207,7 @@ function base_url(bool $withPort = true): string
|
||||
return url('/');
|
||||
}
|
||||
|
||||
function is_dev(): bool
|
||||
function isDev(): bool
|
||||
{
|
||||
return config('app.env') === 'local';
|
||||
}
|
||||
@ -202,8 +231,9 @@ function validate_cron_expression($expression_to_validate): bool
|
||||
function send_internal_notification(string $message): void
|
||||
{
|
||||
try {
|
||||
$baseUrl = base_url(false);
|
||||
$team = Team::find(0);
|
||||
$team->notify(new GeneralNotification('👀 Internal notifications: ' . $message));
|
||||
$team->notify(new GeneralNotification("👀 Internal notifications from {$baseUrl}: " . $message));
|
||||
} catch (\Throwable $th) {
|
||||
ray($th->getMessage());
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Team;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Stripe\Stripe;
|
||||
|
||||
function getSubscriptionLink($type)
|
||||
{
|
||||
$checkout_id = config("coolify.lemon_squeezy_checkout_id_$type");
|
||||
$checkout_id = config("subscription.lemon_squeezy_checkout_id_$type");
|
||||
if (!$checkout_id) {
|
||||
return null;
|
||||
}
|
||||
$user_id = auth()->user()->id;
|
||||
$team_id = auth()->user()->currentTeam()->id ?? null;
|
||||
$team_id = currentTeam()->id ?? null;
|
||||
$email = auth()->user()->email ?? null;
|
||||
$name = auth()->user()->name ?? null;
|
||||
$url = "https://store.coollabs.io/checkout/buy/$checkout_id?";
|
||||
@ -30,53 +32,98 @@ function getSubscriptionLink($type)
|
||||
|
||||
function getPaymentLink()
|
||||
{
|
||||
return auth()->user()->currentTeam()->subscription->lemon_update_payment_menthod_url;
|
||||
return currentTeam()->subscription->lemon_update_payment_menthod_url;
|
||||
}
|
||||
|
||||
function getRenewDate()
|
||||
{
|
||||
return Carbon::parse(auth()->user()->currentTeam()->subscription->lemon_renews_at)->format('Y-M-d H:i:s');
|
||||
return Carbon::parse(currentTeam()->subscription->lemon_renews_at)->format('Y-M-d H:i:s');
|
||||
}
|
||||
|
||||
function getEndDate()
|
||||
{
|
||||
return Carbon::parse(auth()->user()->currentTeam()->subscription->lemon_renews_at)->format('Y-M-d H:i:s');
|
||||
return Carbon::parse(currentTeam()->subscription->lemon_renews_at)->format('Y-M-d H:i:s');
|
||||
}
|
||||
|
||||
function is_subscription_active()
|
||||
function isSubscriptionActive()
|
||||
{
|
||||
$team = auth()->user()?->currentTeam();
|
||||
|
||||
$team = currentTeam();
|
||||
if (!$team) {
|
||||
return false;
|
||||
}
|
||||
if (is_instance_admin()) {
|
||||
return true;
|
||||
}
|
||||
$subscription = $team?->subscription;
|
||||
|
||||
if (!$subscription) {
|
||||
return false;
|
||||
}
|
||||
$is_active = $subscription->lemon_status === 'active';
|
||||
if (config('subscription.provider') === 'lemon') {
|
||||
return $subscription->lemon_status === 'active';
|
||||
}
|
||||
if (config('subscription.provider') === 'stripe') {
|
||||
return $subscription->stripe_invoice_paid === true && $subscription->stripe_cancel_at_period_end === false;
|
||||
}
|
||||
return false;
|
||||
// if (config('subscription.provider') === 'paddle') {
|
||||
// return $subscription->paddle_status === 'active';
|
||||
// }
|
||||
|
||||
return $is_active;
|
||||
}
|
||||
function is_subscription_in_grace_period()
|
||||
function isSubscriptionOnGracePeriod()
|
||||
{
|
||||
$team = auth()->user()?->currentTeam();
|
||||
|
||||
$team = currentTeam();
|
||||
if (!$team) {
|
||||
return false;
|
||||
}
|
||||
if (is_instance_admin()) {
|
||||
return true;
|
||||
}
|
||||
$subscription = $team?->subscription;
|
||||
if (!$subscription) {
|
||||
return false;
|
||||
}
|
||||
$is_still_grace_period = $subscription->lemon_ends_at &&
|
||||
Carbon::parse($subscription->lemon_ends_at) > Carbon::now();
|
||||
|
||||
return $is_still_grace_period;
|
||||
if (config('subscription.provider') === 'lemon') {
|
||||
$is_still_grace_period = $subscription->lemon_ends_at &&
|
||||
Carbon::parse($subscription->lemon_ends_at) > Carbon::now();
|
||||
return $is_still_grace_period;
|
||||
}
|
||||
if (config('subscription.provider') === 'stripe') {
|
||||
return $subscription->stripe_cancel_at_period_end;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function subscriptionProvider()
|
||||
{
|
||||
return config('subscription.provider');
|
||||
}
|
||||
function getStripeCustomerPortalSession(Team $team)
|
||||
{
|
||||
Stripe::setApiKey(config('subscription.stripe_api_key'));
|
||||
$return_url = route('team.show');
|
||||
$stripe_customer_id = $team->subscription->stripe_customer_id;
|
||||
$session = \Stripe\BillingPortal\Session::create([
|
||||
'customer' => $stripe_customer_id,
|
||||
'return_url' => $return_url,
|
||||
]);
|
||||
return $session;
|
||||
}
|
||||
function allowedPathsForUnsubscribedAccounts()
|
||||
{
|
||||
return [
|
||||
'subscription',
|
||||
'login',
|
||||
'register',
|
||||
'waitlist',
|
||||
'force-password-reset',
|
||||
'logout',
|
||||
'livewire/message/force-password-reset',
|
||||
'livewire/message/check-license',
|
||||
'livewire/message/switch-team',
|
||||
'livewire/message/subscription.pricing-plans'
|
||||
];
|
||||
}
|
||||
function allowedPathsForBoardingAccounts()
|
||||
{
|
||||
return [
|
||||
...allowedPathsForUnsubscribedAccounts(),
|
||||
'boarding',
|
||||
'livewire/message/boarding',
|
||||
];
|
||||
}
|
||||
|
@ -23,13 +23,16 @@
|
||||
"livewire/livewire": "^v2.12.3",
|
||||
"masmerise/livewire-toaster": "^1.2",
|
||||
"nubs/random-name-generator": "^2.2",
|
||||
"phpseclib/phpseclib": "~3.0",
|
||||
"poliander/cron": "^3.0",
|
||||
"resend/resend-laravel": "^0.5.0",
|
||||
"sentry/sentry-laravel": "^3.4",
|
||||
"spatie/laravel-activitylog": "^4.7.3",
|
||||
"spatie/laravel-data": "^3.4.3",
|
||||
"spatie/laravel-ray": "^1.32.4",
|
||||
"spatie/laravel-schemaless-attributes": "^2.4",
|
||||
"spatie/url": "^2.2",
|
||||
"stripe/stripe-php": "^12.0",
|
||||
"symfony/yaml": "^6.2",
|
||||
"visus/cuid2": "^2.0.0"
|
||||
},
|
||||
|
667
composer.lock
generated
667
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -4,17 +4,6 @@ return [
|
||||
'self_hosted' => env('SELF_HOSTED', true),
|
||||
'waitlist' => env('WAITLIST', false),
|
||||
'license_url' => 'https://license.coolify.io',
|
||||
'lemon_squeezy_api_key' => env('LEMON_SQUEEZY_API_KEY', null),
|
||||
'lemon_squeezy_webhook_secret' => env('LEMON_SQUEEZY_WEBHOOK_SECRET', null),
|
||||
'lemon_squeezy_checkout_id_monthly_basic' => env('LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY_BASIC', null),
|
||||
'lemon_squeezy_checkout_id_monthly_pro' => env('LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY_PRO', null),
|
||||
'lemon_squeezy_checkout_id_monthly_ultimate' => env('LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY_ULTIMATE', null),
|
||||
'lemon_squeezy_checkout_id_yearly_basic' => env('LEMON_SQUEEZY_CHECKOUT_ID_YEARLY_BASIC', null),
|
||||
'lemon_squeezy_checkout_id_yearly_pro' => env('LEMON_SQUEEZY_CHECKOUT_ID_YEARLY_PRO', null),
|
||||
'lemon_squeezy_checkout_id_yearly_ultimate' => env('LEMON_SQUEEZY_CHECKOUT_ID_YEARLY_ULTIMATE', null),
|
||||
'lemon_squeezy_basic_plan_ids' => env('LEMON_SQUEEZY_BASIC_PLAN_IDS', ""),
|
||||
'lemon_squeezy_pro_plan_ids' => env('LEMON_SQUEEZY_PRO_PLAN_IDS', ""),
|
||||
'lemon_squeezy_ultimate_plan_ids' => env('LEMON_SQUEEZY_ULTIMATE_PLAN_IDS', ""),
|
||||
'mux_enabled' => env('MUX_ENABLED', true),
|
||||
'dev_webhook' => env('SERVEO_URL'),
|
||||
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
|
||||
|
@ -44,7 +44,9 @@ return [
|
||||
'timeout' => null,
|
||||
'local_domain' => env('MAIL_EHLO_DOMAIN'),
|
||||
],
|
||||
|
||||
'resend'=> [
|
||||
'transport' => 'resend'
|
||||
],
|
||||
'ses' => [
|
||||
'transport' => 'ses',
|
||||
],
|
||||
|
42
config/subscription.php
Normal file
42
config/subscription.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'provider'=> env('SUBSCRIPTION_PROVIDER', null), // stripe, paddle, lemon
|
||||
// Stripe
|
||||
'stripe_api_key' => env('STRIPE_API_KEY', null),
|
||||
'stripe_webhook_secret' => env('STRIPE_WEBHOOK_SECRET', null),
|
||||
'stripe_price_id_basic_monthly' => env('STRIPE_PRICE_ID_BASIC_MONTHLY', null),
|
||||
'stripe_price_id_basic_yearly' => env('STRIPE_PRICE_ID_BASIC_YEARLY', null),
|
||||
'stripe_price_id_pro_monthly' => env('STRIPE_PRICE_ID_PRO_MONTHLY', null),
|
||||
'stripe_price_id_pro_yearly' => env('STRIPE_PRICE_ID_PRO_YEARLY', null),
|
||||
'stripe_price_id_ultimate_monthly' => env('STRIPE_PRICE_ID_ULTIMATE_MONTHLY', null),
|
||||
'stripe_price_id_ultimate_yearly' => env('STRIPE_PRICE_ID_ULTIMATE_YEARLY', null),
|
||||
|
||||
|
||||
// Paddle
|
||||
'paddle_vendor_id' => env('PADDLE_VENDOR_ID', null),
|
||||
'paddle_vendor_auth_code' => env('PADDLE_VENDOR_AUTH_CODE', null),
|
||||
'paddle_webhook_secret' => env('PADDLE_WEBHOOK_SECRET', null),
|
||||
'paddle_public_key' => env('PADDLE_PUBLIC_KEY', null),
|
||||
'paddle_price_id_basic_monthly' => env('PADDLE_PRICE_ID_BASIC_MONTHLY', null),
|
||||
'paddle_price_id_basic_yearly' => env('PADDLE_PRICE_ID_BASIC_YEARLY', null),
|
||||
'paddle_price_id_pro_monthly' => env('PADDLE_PRICE_ID_PRO_MONTHLY', null),
|
||||
'paddle_price_id_pro_yearly' => env('PADDLE_PRICE_ID_PRO_YEARLY', null),
|
||||
'paddle_price_id_ultimate_monthly' => env('PADDLE_PRICE_ID_ULTIMATE_MONTHLY', null),
|
||||
'paddle_price_id_ultimate_yearly' => env('PADDLE_PRICE_ID_ULTIMATE_YEARLY', null),
|
||||
|
||||
|
||||
|
||||
// Lemon
|
||||
'lemon_squeezy_api_key' => env('LEMON_SQUEEZY_API_KEY', null),
|
||||
'lemon_squeezy_webhook_secret' => env('LEMON_SQUEEZY_WEBHOOK_SECRET', null),
|
||||
'lemon_squeezy_checkout_id_basic_monthly' => env('LEMON_SQUEEZY_CHECKOUT_ID_BASIC_MONTHLY', null),
|
||||
'lemon_squeezy_checkout_id_basic_yearly' => env('LEMON_SQUEEZY_CHECKOUT_ID_BASIC_YEARLY', null),
|
||||
'lemon_squeezy_checkout_id_pro_monthly' => env('LEMON_SQUEEZY_CHECKOUT_ID_PRO_MONTHLY', null),
|
||||
'lemon_squeezy_checkout_id_pro_yearly' => env('LEMON_SQUEEZY_CHECKOUT_ID_PRO_YEARLY', null),
|
||||
'lemon_squeezy_checkout_id_ultimate_monthly' => env('LEMON_SQUEEZY_CHECKOUT_ID_ULTIMATE_MONTHLY', null),
|
||||
'lemon_squeezy_checkout_id_ultimate_yearly' => env('LEMON_SQUEEZY_CHECKOUT_ID_ULTIMATE_YEARLY', null),
|
||||
'lemon_squeezy_basic_plan_ids' => env('LEMON_SQUEEZY_BASIC_PLAN_IDS', ""),
|
||||
'lemon_squeezy_pro_plan_ids' => env('LEMON_SQUEEZY_PRO_PLAN_IDS', ""),
|
||||
'lemon_squeezy_ultimate_plan_ids' => env('LEMON_SQUEEZY_ULTIMATE_PLAN_IDS', ""),
|
||||
];
|
@ -1,3 +1,3 @@
|
||||
<?php
|
||||
|
||||
return '4.0.0-beta.20';
|
||||
return '4.0.0-beta.21';
|
||||
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('teams', function (Blueprint $table) {
|
||||
$table->boolean('show_boarding')->default(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('teams', function (Blueprint $table) {
|
||||
$table->dropColumn('show_boarding');
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('webhooks', function (Blueprint $table) {
|
||||
$table->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();
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('subscriptions', function (Blueprint $table) {
|
||||
$table->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();
|
||||
});
|
||||
}
|
||||
};
|
@ -17,13 +17,12 @@ class ApplicationSeeder extends Seeder
|
||||
Application::create([
|
||||
'name' => 'coollabsio/coolify-examples:nodejs-fastify',
|
||||
'description' => 'NodeJS Fastify Example',
|
||||
'fqdn' => 'http://foo.com',
|
||||
'fqdn' => 'http://nodejs.127.0.0.1.sslip.io',
|
||||
'repository_project_id' => 603035348,
|
||||
'git_repository' => 'coollabsio/coolify-examples',
|
||||
'git_branch' => 'nodejs-fastify',
|
||||
'build_pack' => 'nixpacks',
|
||||
'ports_exposes' => '3000',
|
||||
'ports_mappings' => '3005:3000',
|
||||
'environment_id' => 1,
|
||||
'destination_id' => 0,
|
||||
'destination_type' => StandaloneDocker::class,
|
||||
@ -33,18 +32,36 @@ class ApplicationSeeder extends Seeder
|
||||
Application::create([
|
||||
'name' => 'coollabsio/coolify-examples:dockerfile',
|
||||
'description' => 'Dockerfile Example',
|
||||
'fqdn' => 'http://foos.com',
|
||||
'fqdn' => 'http://dockerfile.127.0.0.1.sslip.io',
|
||||
'repository_project_id' => 603035348,
|
||||
'git_repository' => 'coollabsio/coolify-examples',
|
||||
'git_branch' => 'dockerfile',
|
||||
'build_pack' => 'dockerfile',
|
||||
'ports_exposes' => '3000',
|
||||
'ports_mappings' => '3080:80',
|
||||
'environment_id' => 1,
|
||||
'destination_id' => 0,
|
||||
'destination_type' => StandaloneDocker::class,
|
||||
'source_id' => 0,
|
||||
'source_type' => GithubApp::class
|
||||
]);
|
||||
Application::create([
|
||||
'name' => 'pure-dockerfile',
|
||||
'description' => '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;"]
|
||||
'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ class InstanceSettingsSeeder extends Seeder
|
||||
InstanceSettings::create([
|
||||
'id' => 0,
|
||||
'is_registration_enabled' => true,
|
||||
'is_resale_license_active' => true,
|
||||
'smtp_enabled' => true,
|
||||
'smtp_host' => 'coolify-mail',
|
||||
'smtp_port' => 1025,
|
||||
|
@ -12,17 +12,17 @@ class ScheduledDatabaseBackupExecutionSeeder extends Seeder
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
ScheduledDatabaseBackupExecution::create([
|
||||
'status' => 'success',
|
||||
'message' => 'Backup created successfully.',
|
||||
'size' => '10243467789556',
|
||||
'scheduled_database_backup_id' => 1,
|
||||
]);
|
||||
ScheduledDatabaseBackupExecution::create([
|
||||
'status' => 'failed',
|
||||
'message' => 'Backup failed.',
|
||||
'size' => '10243456',
|
||||
'scheduled_database_backup_id' => 1,
|
||||
]);
|
||||
// ScheduledDatabaseBackupExecution::create([
|
||||
// 'status' => 'success',
|
||||
// 'message' => 'Backup created successfully.',
|
||||
// 'size' => '10243467789556',
|
||||
// 'scheduled_database_backup_id' => 1,
|
||||
// ]);
|
||||
// ScheduledDatabaseBackupExecution::create([
|
||||
// 'status' => 'failed',
|
||||
// 'message' => 'Backup failed.',
|
||||
// 'size' => '10243456',
|
||||
// 'scheduled_database_backup_id' => 1,
|
||||
// ]);
|
||||
}
|
||||
}
|
||||
|
@ -12,22 +12,22 @@ class ScheduledDatabaseBackupSeeder extends Seeder
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
ScheduledDatabaseBackup::create([
|
||||
'enabled' => true,
|
||||
'frequency' => '* * * * *',
|
||||
'number_of_backups_locally' => 2,
|
||||
'database_id' => 1,
|
||||
'database_type' => 'App\Models\StandalonePostgresql',
|
||||
's3_storage_id' => 1,
|
||||
'team_id' => 0,
|
||||
]);
|
||||
ScheduledDatabaseBackup::create([
|
||||
'enabled' => true,
|
||||
'frequency' => '* * * * *',
|
||||
'number_of_backups_locally' => 3,
|
||||
'database_id' => 1,
|
||||
'database_type' => 'App\Models\StandalonePostgresql',
|
||||
'team_id' => 0,
|
||||
]);
|
||||
// ScheduledDatabaseBackup::create([
|
||||
// 'enabled' => true,
|
||||
// 'frequency' => '* * * * *',
|
||||
// 'number_of_backups_locally' => 2,
|
||||
// 'database_id' => 1,
|
||||
// 'database_type' => 'App\Models\StandalonePostgresql',
|
||||
// 's3_storage_id' => 1,
|
||||
// 'team_id' => 0,
|
||||
// ]);
|
||||
// ScheduledDatabaseBackup::create([
|
||||
// 'enabled' => true,
|
||||
// 'frequency' => '* * * * *',
|
||||
// 'number_of_backups_locally' => 3,
|
||||
// 'database_id' => 1,
|
||||
// 'database_type' => 'App\Models\StandalonePostgresql',
|
||||
// 'team_id' => 0,
|
||||
// ]);
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ class ServerSeeder extends Seeder
|
||||
{
|
||||
Server::create([
|
||||
'id' => 0,
|
||||
'name' => "testing-local-docker-container",
|
||||
'description' => "This is a test docker container",
|
||||
'name' => "localhost",
|
||||
'description' => "This is a test docker container in development mode",
|
||||
'ip' => "coolify-testing-host",
|
||||
'team_id' => 0,
|
||||
'private_key_id' => 0,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user