mirror of
https://github.com/ershisan99/coolify.git
synced 2026-01-02 12:33:52 +00:00
Compare commits
17 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc8c6c5d16 | ||
|
|
4782446f42 | ||
|
|
230155312f | ||
|
|
3ab4365fca | ||
|
|
7349068b95 | ||
|
|
da6cc151d1 | ||
|
|
50527cf0a3 | ||
|
|
26f490bb00 | ||
|
|
dc4f412227 | ||
|
|
ec4234e243 | ||
|
|
f47fcb01ce | ||
|
|
02f6673345 | ||
|
|
e6cd8702b5 | ||
|
|
fda4ea8cca | ||
|
|
655d004ce7 | ||
|
|
56981d134c | ||
|
|
b9d49d2951 |
@@ -30,19 +30,19 @@ class StartProxy
|
|||||||
$server->save();
|
$server->save();
|
||||||
|
|
||||||
$activity = remote_process([
|
$activity = remote_process([
|
||||||
"echo 'Creating required Docker networks...'",
|
"echo '####### Creating required Docker networks...'",
|
||||||
...$create_networks_command,
|
...$create_networks_command,
|
||||||
"cd $proxy_path",
|
"cd $proxy_path",
|
||||||
"echo 'Creating Docker Compose file...'",
|
"echo '####### Creating Docker Compose file...'",
|
||||||
"echo 'Pulling docker image...'",
|
"echo '####### Pulling docker image...'",
|
||||||
'docker compose pull -q',
|
'docker compose pull',
|
||||||
"echo 'Stopping existing proxy...'",
|
"echo '####### Stopping existing proxy...'",
|
||||||
'docker compose down -v --remove-orphans',
|
'docker compose down -v --remove-orphans',
|
||||||
"lsof -nt -i:80 | xargs -r kill -9",
|
"lsof -nt -i:80 | xargs -r kill -9",
|
||||||
"lsof -nt -i:443 | xargs -r kill -9",
|
"lsof -nt -i:443 | xargs -r kill -9",
|
||||||
"echo 'Starting proxy...'",
|
"echo '####### Starting proxy...'",
|
||||||
'docker compose up -d --remove-orphans',
|
'docker compose up -d --remove-orphans',
|
||||||
"echo 'Proxy installed successfully...'"
|
"echo '####### Proxy installed successfully...'"
|
||||||
], $server);
|
], $server);
|
||||||
|
|
||||||
return $activity;
|
return $activity;
|
||||||
|
|||||||
@@ -18,42 +18,42 @@ class InstallDocker
|
|||||||
"max-file": "3"
|
"max-file": "3"
|
||||||
}
|
}
|
||||||
}');
|
}');
|
||||||
|
$found = StandaloneDocker::where('server_id', $server->id);
|
||||||
|
if ($found->count() == 0) {
|
||||||
|
StandaloneDocker::create([
|
||||||
|
'name' => 'coolify',
|
||||||
|
'network' => 'coolify',
|
||||||
|
'server_id' => $server->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$activity = remote_process([
|
return remote_process([
|
||||||
"echo ####### Installing Prerequisites...",
|
"echo '####### Installing Prerequisites...'",
|
||||||
"echo ####### Installing/updating Docker Engine...",
|
"sleep 1",
|
||||||
"echo ####### Configuring Docker Engine (merging existing configuration with the required)...",
|
"echo '####### Installing/updating Docker Engine...'",
|
||||||
"echo ####### Restarting Docker Engine...",
|
"echo '####### Configuring Docker Engine (merging existing configuration with the required)...'",
|
||||||
|
"sleep 4",
|
||||||
|
"echo '####### Restarting Docker Engine...'",
|
||||||
|
"ls -l /tmp"
|
||||||
], $server);
|
], $server);
|
||||||
} else {
|
} else {
|
||||||
$activity = remote_process([
|
return remote_process([
|
||||||
"echo ####### Installing Prerequisites...",
|
"echo '####### Installing Prerequisites...'",
|
||||||
"command -v jq >/dev/null || apt-get update",
|
"command -v jq >/dev/null || apt-get update",
|
||||||
"command -v jq >/dev/null || apt install -y jq",
|
"command -v jq >/dev/null || apt install -y jq",
|
||||||
"echo ####### Installing/updating Docker Engine...",
|
"echo '####### Installing/updating Docker Engine...'",
|
||||||
"curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh",
|
"curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh",
|
||||||
"echo ####### Configuring Docker Engine (merging existing configuration with the required)...",
|
"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",
|
"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",
|
"echo '{$config}' | base64 -d > /etc/docker/daemon.json.coolify",
|
||||||
"cat <<< $(jq . /etc/docker/daemon.json.coolify) > /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",
|
"cat <<< $(jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json",
|
||||||
"echo ####### Restarting Docker Engine...",
|
"echo '####### Restarting Docker Engine...'",
|
||||||
"systemctl restart docker",
|
"systemctl restart docker",
|
||||||
"echo ####### Creating default network...",
|
"echo '####### Creating default Docker network (coolify)...'",
|
||||||
"docker network create --attachable coolify >/dev/null 2>&1 || true",
|
"docker network create --attachable coolify >/dev/null 2>&1 || true",
|
||||||
"echo ####### Done!"
|
"echo '####### Done!'"
|
||||||
], $server);
|
], $server);
|
||||||
$found = StandaloneDocker::where('server_id', $server->id);
|
|
||||||
if ($found->count() == 0) {
|
|
||||||
StandaloneDocker::create([
|
|
||||||
'name' => 'coolify',
|
|
||||||
'network' => 'coolify',
|
|
||||||
'server_id' => $server->id,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return $activity;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Jobs\SendConfirmationForWaitlistJob;
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
use App\Models\ScheduledDatabaseBackup;
|
use App\Models\ScheduledDatabaseBackup;
|
||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use App\Models\TeamInvitation;
|
use App\Models\TeamInvitation;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Models\Waitlist;
|
||||||
use App\Notifications\Application\DeploymentFailed;
|
use App\Notifications\Application\DeploymentFailed;
|
||||||
use App\Notifications\Application\DeploymentSuccess;
|
use App\Notifications\Application\DeploymentSuccess;
|
||||||
use App\Notifications\Application\StatusChanged;
|
use App\Notifications\Application\StatusChanged;
|
||||||
@@ -19,6 +21,7 @@ use Exception;
|
|||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Mail\Message;
|
use Illuminate\Mail\Message;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Support\Facades\Process;
|
||||||
use Mail;
|
use Mail;
|
||||||
use Str;
|
use Str;
|
||||||
|
|
||||||
@@ -148,23 +151,20 @@ class TestEmail extends Command
|
|||||||
case 'waitlist-invitation-link':
|
case 'waitlist-invitation-link':
|
||||||
$this->mail = new MailMessage();
|
$this->mail = new MailMessage();
|
||||||
$this->mail->view('emails.waitlist-invitation', [
|
$this->mail->view('emails.waitlist-invitation', [
|
||||||
'email' => 'test2@example.com',
|
'loginLink' => 'https://coolify.io',
|
||||||
'password' => "supersecretpassword",
|
|
||||||
]);
|
]);
|
||||||
$this->mail->subject('Congratulations! You are invited to join Coolify Cloud.');
|
$this->mail->subject('Congratulations! You are invited to join Coolify Cloud.');
|
||||||
$this->sendEmail();
|
$this->sendEmail();
|
||||||
break;
|
break;
|
||||||
case 'waitlist-confirmation':
|
case 'waitlist-confirmation':
|
||||||
$this->mail = new MailMessage();
|
$found = Waitlist::where('email', $this->email)->first();
|
||||||
$this->mail->view(
|
if ($found) {
|
||||||
'emails.waitlist-confirmation',
|
SendConfirmationForWaitlistJob::dispatch($this->email, $found->uuid);
|
||||||
[
|
|
||||||
'confirmation_url' => 'http://example.com',
|
} else {
|
||||||
'cancel_url' => 'http://example.com',
|
throw new Exception('Waitlist not found');
|
||||||
]
|
}
|
||||||
);
|
|
||||||
$this->mail->subject('You are on the waitlist!');
|
|
||||||
$this->sendEmail();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ class WaitlistInvite extends Command
|
|||||||
$loginLink = route('auth.link', ['token' => $token]);
|
$loginLink = route('auth.link', ['token' => $token]);
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage();
|
||||||
$mail->view('emails.waitlist-invitation', [
|
$mail->view('emails.waitlist-invitation', [
|
||||||
'email' => $this->next_patient->email,
|
|
||||||
'password' => $this->password,
|
|
||||||
'loginLink' => $loginLink,
|
'loginLink' => $loginLink,
|
||||||
]);
|
]);
|
||||||
$mail->subject('Congratulations! You are invited to join Coolify Cloud.');
|
$mail->subject('Congratulations! You are invited to join Coolify Cloud.');
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
{
|
{
|
||||||
$this->selectedExistingPrivateKey = null;
|
$this->selectedExistingPrivateKey = null;
|
||||||
$this->privateKeyType = $type;
|
$this->privateKeyType = $type;
|
||||||
if ($type === 'create' && !isDev()) {
|
if ($type === 'create') {
|
||||||
$this->createNewPrivateKey();
|
$this->createNewPrivateKey();
|
||||||
}
|
}
|
||||||
$this->currentState = 'create-private-key';
|
$this->currentState = 'create-private-key';
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use Livewire\Component;
|
|||||||
class Change extends Component
|
class Change extends Component
|
||||||
{
|
{
|
||||||
public PrivateKey $private_key;
|
public PrivateKey $private_key;
|
||||||
|
public $public_key;
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'private_key.name' => 'required|string',
|
'private_key.name' => 'required|string',
|
||||||
'private_key.description' => 'nullable|string',
|
'private_key.description' => 'nullable|string',
|
||||||
@@ -21,6 +21,14 @@ class Change extends Component
|
|||||||
'private_key.private_key' => 'private key'
|
'private_key.private_key' => 'private key'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->public_key = $this->private_key->publicKey();
|
||||||
|
}catch(\Exception $e) {
|
||||||
|
return general_error_handler(err: $e, that: $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class Create extends Component
|
|||||||
if ($this->from === 'server') {
|
if ($this->from === 'server') {
|
||||||
return redirect()->route('server.create');
|
return redirect()->route('server.create');
|
||||||
}
|
}
|
||||||
return redirect()->route('private-key.show', ['private_key_uuid' => $private_key->uuid]);
|
return redirect()->route('security.private-key.show', ['private_key_uuid' => $private_key->uuid]);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return general_error_handler(err: $e, that: $this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,13 +54,19 @@ class Form extends Component
|
|||||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
|
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
|
||||||
if ($uptime) {
|
if ($uptime) {
|
||||||
$this->uptime = $uptime;
|
$this->uptime = $uptime;
|
||||||
|
$this->emit('success', 'Server is reachable!');
|
||||||
|
} else {
|
||||||
|
throw new \Exception('Server is not rachable');
|
||||||
}
|
}
|
||||||
if ($dockerVersion) {
|
if ($dockerVersion) {
|
||||||
$this->dockerVersion = $dockerVersion;
|
$this->dockerVersion = $dockerVersion;
|
||||||
$this->emit('proxyStatusUpdated');
|
$this->emit('proxyStatusUpdated');
|
||||||
|
$this->emit('success', 'Docker Engine 23+ is installed!');
|
||||||
|
} else {
|
||||||
|
throw new \Exception('Old Docker version detected (lower than 23).');
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
return general_error_handler($e, that: $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,8 +83,6 @@ class Form extends Component
|
|||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return general_error_handler(err: $e, that: $this);
|
return general_error_handler(err: $e, that: $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ namespace App\Http\Livewire\Server;
|
|||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Masmerise\Toaster\Toaster;
|
|
||||||
|
|
||||||
class ShowPrivateKey extends Component
|
class ShowPrivateKey extends Component
|
||||||
{
|
{
|
||||||
@@ -12,14 +11,24 @@ class ShowPrivateKey extends Component
|
|||||||
public $privateKeys;
|
public $privateKeys;
|
||||||
public $parameters;
|
public $parameters;
|
||||||
|
|
||||||
public function setPrivateKey($private_key_id)
|
public function setPrivateKey($newPrivateKeyId)
|
||||||
{
|
{
|
||||||
$this->server->update([
|
try {
|
||||||
'private_key_id' => $private_key_id
|
$oldPrivateKeyId = $this->server->private_key_id;
|
||||||
]);
|
$this->server->update([
|
||||||
refresh_server_connection($this->server->privateKey);
|
'private_key_id' => $newPrivateKeyId
|
||||||
$this->server->refresh();
|
]);
|
||||||
$this->checkConnection();
|
$this->server->refresh();
|
||||||
|
refresh_server_connection($this->server->privateKey);
|
||||||
|
$this->checkConnection();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->server->update([
|
||||||
|
'private_key_id' => $oldPrivateKeyId
|
||||||
|
]);
|
||||||
|
$this->server->refresh();
|
||||||
|
refresh_server_connection($this->server->privateKey);
|
||||||
|
return general_error_handler($e, that: $this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkConnection()
|
public function checkConnection()
|
||||||
@@ -27,13 +36,17 @@ class ShowPrivateKey extends Component
|
|||||||
try {
|
try {
|
||||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
|
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
|
||||||
if ($uptime) {
|
if ($uptime) {
|
||||||
Toaster::success('Server is reachable with this private key.');
|
$this->emit('success', 'Server is reachable with this private key.');
|
||||||
|
} else {
|
||||||
|
throw new \Exception('Server is not reachable with this private key.');
|
||||||
}
|
}
|
||||||
if ($dockerVersion) {
|
if ($dockerVersion) {
|
||||||
Toaster::success('Server is usable for Coolify.');
|
$this->emit('success', 'Server is usable for Coolify.');
|
||||||
|
} else {
|
||||||
|
throw new \Exception('Old Docker version detected (lower than 23).');
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
throw new \Exception($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use Livewire\Component;
|
|||||||
class Index extends Component
|
class Index extends Component
|
||||||
{
|
{
|
||||||
public string $email;
|
public string $email;
|
||||||
|
public int $users = 0;
|
||||||
public int $waitingInLine = 0;
|
public int $waitingInLine = 0;
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
@@ -22,6 +23,7 @@ class Index extends Component
|
|||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->waitingInLine = Waitlist::whereVerified(true)->count();
|
$this->waitingInLine = Waitlist::whereVerified(true)->count();
|
||||||
|
$this->users = User::count();
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$this->email = 'waitlist@example.com';
|
$this->email = 'waitlist@example.com';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class CleanupInstanceStuffsJob implements ShouldQueue, ShouldBeUnique
|
|||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->cleanup_waitlist();
|
// $this->cleanup_waitlist();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
send_internal_notification('CleanupInstanceStuffsJob failed with error: ' . $e->getMessage());
|
send_internal_notification('CleanupInstanceStuffsJob failed with error: ' . $e->getMessage());
|
||||||
ray($e->getMessage());
|
ray($e->getMessage());
|
||||||
|
|||||||
@@ -25,10 +25,8 @@ class SendConfirmationForWaitlistJob implements ShouldQueue
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage();
|
||||||
|
|
||||||
$confirmation_url = base_url() . '/webhooks/waitlist/confirm?email=' . $this->email . '&confirmation_code=' . $this->uuid;
|
$confirmation_url = base_url() . '/webhooks/waitlist/confirm?email=' . $this->email . '&confirmation_code=' . $this->uuid;
|
||||||
$cancel_url = base_url() . '/webhooks/waitlist/cancel?email=' . $this->email . '&confirmation_code=' . $this->uuid;
|
$cancel_url = base_url() . '/webhooks/waitlist/cancel?email=' . $this->email . '&confirmation_code=' . $this->uuid;
|
||||||
|
|
||||||
$mail->view('emails.waitlist-confirmation',
|
$mail->view('emails.waitlist-confirmation',
|
||||||
[
|
[
|
||||||
'confirmation_url' => $confirmation_url,
|
'confirmation_url' => $confirmation_url,
|
||||||
@@ -37,7 +35,7 @@ class SendConfirmationForWaitlistJob implements ShouldQueue
|
|||||||
$mail->subject('You are on the waitlist!');
|
$mail->subject('You are on the waitlist!');
|
||||||
send_user_an_email($mail, $this->email);
|
send_user_an_email($mail, $this->email);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
send_internal_notification("SendConfirmationForWaitlistJob failed for {$mail} with error: " . $th->getMessage());
|
send_internal_notification("SendConfirmationForWaitlistJob failed for {$this->email} with error: " . $th->getMessage());
|
||||||
ray($th->getMessage());
|
ray($th->getMessage());
|
||||||
throw $th;
|
throw $th;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use phpseclib3\Crypt\PublicKeyLoader;
|
||||||
|
|
||||||
class PrivateKey extends BaseModel
|
class PrivateKey extends BaseModel
|
||||||
{
|
{
|
||||||
@@ -19,6 +20,15 @@ class PrivateKey extends BaseModel
|
|||||||
return PrivateKey::whereTeamId(currentTeam()->id)->select($selectArray->all());
|
return PrivateKey::whereTeamId(currentTeam()->id)->select($selectArray->all());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function publicKey()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return PublicKeyLoader::load($this->private_key)->getPublicKey()->toString('OpenSSH',['comment' => '']);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return 'Error loading private key';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function isEmpty()
|
public function isEmpty()
|
||||||
{
|
{
|
||||||
if ($this->servers()->count() === 0 && $this->applications()->count() === 0 && $this->githubApps()->count() === 0 && $this->gitlabApps()->count() === 0) {
|
if ($this->servers()->count() === 0 && $this->applications()->count() === 0 && $this->githubApps()->count() === 0 && $this->gitlabApps()->count() === 0) {
|
||||||
|
|||||||
@@ -19,7 +19,17 @@ class GeneralNotification extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function via(object $notifiable): array
|
public function via(object $notifiable): array
|
||||||
{
|
{
|
||||||
return [TelegramChannel::class, DiscordChannel::class];
|
$channels = [];
|
||||||
|
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||||
|
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||||
|
|
||||||
|
if ($isDiscordEnabled) {
|
||||||
|
$channels[] = DiscordChannel::class;
|
||||||
|
}
|
||||||
|
if ($isTelegramEnabled) {
|
||||||
|
$channels[] = TelegramChannel::class;
|
||||||
|
}
|
||||||
|
return $channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toDiscord(): string
|
public function toDiscord(): string
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class Modal extends Component
|
|||||||
public string|null $modalTitle = null,
|
public string|null $modalTitle = null,
|
||||||
public string|null $modalBody = null,
|
public string|null $modalBody = null,
|
||||||
public string|null $modalSubmit = null,
|
public string|null $modalSubmit = null,
|
||||||
|
public bool $noSubmit = false,
|
||||||
public bool $yesOrNo = false,
|
public bool $yesOrNo = false,
|
||||||
public string $action = 'delete'
|
public string $action = 'delete'
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -164,9 +164,9 @@ function refresh_server_connection(PrivateKey $private_key)
|
|||||||
// Delete the old ssh mux file to force a new one to be created
|
// Delete the old ssh mux file to force a new one to be created
|
||||||
Storage::disk('ssh-mux')->delete($server->muxFilename());
|
Storage::disk('ssh-mux')->delete($server->muxFilename());
|
||||||
// check if user is authenticated
|
// check if user is authenticated
|
||||||
if (currentTeam()->id) {
|
// if (currentTeam()->id) {
|
||||||
currentTeam()->privateKeys = PrivateKey::where('team_id', currentTeam()->id)->get();
|
// currentTeam()->privateKeys = PrivateKey::where('team_id', currentTeam()->id)->get();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ function validateServer(Server $server)
|
|||||||
}
|
}
|
||||||
$server->settings->is_reachable = true;
|
$server->settings->is_reachable = true;
|
||||||
|
|
||||||
$dockerVersion = instant_remote_process(['docker version|head -2|grep -i version'], $server, false);
|
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $server, false);
|
||||||
if (!$dockerVersion) {
|
if (!$dockerVersion) {
|
||||||
$dockerVersion = null;
|
$dockerVersion = null;
|
||||||
return [
|
return [
|
||||||
@@ -192,7 +192,13 @@ function validateServer(Server $server)
|
|||||||
"dockerVersion" => null,
|
"dockerVersion" => null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$server->settings->is_usable = true;
|
$majorDockerVersion = Str::of($dockerVersion)->before('.')->value();
|
||||||
|
if ($majorDockerVersion <= 22) {
|
||||||
|
$dockerVersion = null;
|
||||||
|
$server->settings->is_usable = false;
|
||||||
|
} else {
|
||||||
|
$server->settings->is_usable = true;
|
||||||
|
}
|
||||||
return [
|
return [
|
||||||
"uptime" => $uptime,
|
"uptime" => $uptime,
|
||||||
"dockerVersion" => $dockerVersion,
|
"dockerVersion" => $dockerVersion,
|
||||||
@@ -202,7 +208,7 @@ function validateServer(Server $server)
|
|||||||
$server->settings->is_usable = false;
|
$server->settings->is_usable = false;
|
||||||
throw $e;
|
throw $e;
|
||||||
} finally {
|
} finally {
|
||||||
$server->settings->save();
|
if(data_get($server,'settings')) $server->settings->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.30',
|
'release' => '4.0.0-beta.33',
|
||||||
'server_name' => env('APP_ID', 'coolify'),
|
'server_name' => env('APP_ID', 'coolify'),
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.30';
|
return '4.0.0-beta.33';
|
||||||
|
|||||||
@@ -8,13 +8,14 @@
|
|||||||
<div class="w-96">
|
<div class="w-96">
|
||||||
<form action="/user/confirm-password" method="POST" class="flex flex-col gap-2">
|
<form action="/user/confirm-password" method="POST" class="flex flex-col gap-2">
|
||||||
@csrf
|
@csrf
|
||||||
<x-forms.input required type="password" name="password" label="{{ __('input.password') }}"
|
<x-forms.input required type="password" name="password" label="{{ __('input.password') }}" autofocus />
|
||||||
autofocus />
|
|
||||||
<x-forms.button type="submit">{{ __('auth.confirm_password') }}</x-forms.button>
|
<x-forms.button type="submit">{{ __('auth.confirm_password') }}</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
@if ($errors->any())
|
@if ($errors->any())
|
||||||
<div class="text-center text-error">
|
<div class="text-xs text-center text-error">
|
||||||
<span>{{ __('auth.failed') }}</span>
|
@foreach ($errors->all() as $error)
|
||||||
|
<p>{{ $error }}</p>
|
||||||
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if (session('status'))
|
@if (session('status'))
|
||||||
|
|||||||
@@ -28,7 +28,9 @@
|
|||||||
@endif
|
@endif
|
||||||
@if ($errors->any())
|
@if ($errors->any())
|
||||||
<div class="text-xs text-center text-error">
|
<div class="text-xs text-center text-error">
|
||||||
<span>{{ __('auth.failed') }}</span>
|
@foreach ($errors->all() as $error)
|
||||||
|
<p>{{ $error }}</p>
|
||||||
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if (session('status'))
|
@if (session('status'))
|
||||||
|
|||||||
@@ -43,7 +43,9 @@
|
|||||||
@endif
|
@endif
|
||||||
@if ($errors->any())
|
@if ($errors->any())
|
||||||
<div class="text-xs text-center text-error">
|
<div class="text-xs text-center text-error">
|
||||||
<span>{{ __('auth.failed') }}</span>
|
@foreach ($errors->all() as $error)
|
||||||
|
<p>{{ $error }}</p>
|
||||||
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if (session('status'))
|
@if (session('status'))
|
||||||
|
|||||||
@@ -38,7 +38,9 @@
|
|||||||
</form>
|
</form>
|
||||||
@if ($errors->any())
|
@if ($errors->any())
|
||||||
<div class="text-xs text-center text-error">
|
<div class="text-xs text-center text-error">
|
||||||
<span>{{ __('auth.failed') }}</span>
|
@foreach ($errors->all() as $error)
|
||||||
|
<p>{{ $error }}</p>
|
||||||
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,8 +24,10 @@
|
|||||||
<x-forms.button type="submit">{{ __('auth.reset_password') }}</x-forms.button>
|
<x-forms.button type="submit">{{ __('auth.reset_password') }}</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
@if ($errors->any())
|
@if ($errors->any())
|
||||||
<div class="text-center text-error">
|
<div class="text-xs text-center text-error">
|
||||||
<span>{{ __('auth.failed') }}</span>
|
@foreach ($errors->all() as $error)
|
||||||
|
<p>{{ $error }}</p>
|
||||||
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if (session('status'))
|
@if (session('status'))
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template x-if="showRecovery">
|
<template x-if="showRecovery">
|
||||||
<div>
|
<div>
|
||||||
<x-forms.input required type="text" name="recovery_code "
|
<x-forms.input required type="text" name="recovery_code"
|
||||||
label="{{ __('input.recovery_code') }}" />
|
label="{{ __('input.recovery_code') }}" />
|
||||||
<div class="pt-2 text-xs cursor-pointer hover:underline hover:text-white"
|
<div class="pt-2 text-xs cursor-pointer hover:underline hover:text-white"
|
||||||
x-on:click="showRecovery = !showRecovery">Use
|
x-on:click="showRecovery = !showRecovery">Use
|
||||||
@@ -31,8 +31,10 @@
|
|||||||
<x-forms.button type="submit">{{ __('auth.login') }}</x-forms.button>
|
<x-forms.button type="submit">{{ __('auth.login') }}</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
@if ($errors->any())
|
@if ($errors->any())
|
||||||
<div class="text-center text-error">
|
<div class="text-xs text-center text-error">
|
||||||
<span>{{ __('auth.failed') }}</span>
|
@foreach ($errors->all() as $error)
|
||||||
|
<p>{{ $error }}</p>
|
||||||
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if (session('status'))
|
@if (session('status'))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<dialog id="{{ $modalId }}" class="modal">
|
<dialog id="{{ $modalId }}" class="modal">
|
||||||
@if ($yesOrNo)
|
@if ($yesOrNo)
|
||||||
<form method="dialog" class="rounded modal-box" wire:submit.prevent='submit'>
|
<form method="dialog" class="rounded modal-box" @if(!$noSubmit) wire:submit.prevent='submit' @endif>
|
||||||
<div class="flex items-start">
|
<div class="flex items-start">
|
||||||
<div class="flex items-center justify-center flex-shrink-0 w-10 h-10 mr-4 rounded-full">
|
<div class="flex items-center justify-center flex-shrink-0 w-10 h-10 mr-4 rounded-full">
|
||||||
<svg class="w-8 h-8 text-error" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
<svg class="w-8 h-8 text-error" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
</form>
|
</form>
|
||||||
@else
|
@else
|
||||||
<form method="dialog" class="flex flex-col w-11/12 max-w-5xl gap-2 rounded modal-box"
|
<form method="dialog" class="flex flex-col w-11/12 max-w-5xl gap-2 rounded modal-box"
|
||||||
wire:submit.prevent='submit'>
|
@if(!$noSubmit) wire:submit.prevent='submit' @endif>
|
||||||
@isset($modalTitle)
|
@isset($modalTitle)
|
||||||
<h3 class="text-lg font-bold">{{ $modalTitle }}</h3>
|
<h3 class="text-lg font-bold">{{ $modalTitle }}</h3>
|
||||||
@endisset
|
@endisset
|
||||||
|
|||||||
@@ -114,10 +114,10 @@
|
|||||||
label="Description" id="privateKeyDescription" />
|
label="Description" id="privateKeyDescription" />
|
||||||
<x-forms.textarea required placeholder="-----BEGIN OPENSSH PRIVATE KEY-----" label="Private Key"
|
<x-forms.textarea required placeholder="-----BEGIN OPENSSH PRIVATE KEY-----" label="Private Key"
|
||||||
id="privateKey" />
|
id="privateKey" />
|
||||||
@if ($privateKeyType === 'create' && !isDev())
|
@if ($privateKeyType === 'create')
|
||||||
<span class="font-bold text-warning">Copy this to your server's ~/.ssh/authorized_keys
|
<x-forms.textarea rows="7" readonly label="Public Key" id="publicKey" />
|
||||||
file.</span>
|
<span class="font-bold text-warning">ACTION REQUIRED: Copy the 'Public Key' to your server's ~/.ssh/authorized_keys
|
||||||
<x-forms.textarea rows="7" readonly label="Public Key" id="publicKey" />
|
file.</span>
|
||||||
@endif
|
@endif
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -19,6 +19,10 @@
|
|||||||
<x-forms.input id="private_key.name" label="Name" required />
|
<x-forms.input id="private_key.name" label="Name" required />
|
||||||
<x-forms.input id="private_key.description" label="Description" />
|
<x-forms.input id="private_key.description" label="Description" />
|
||||||
<div>
|
<div>
|
||||||
|
<div class="flex items-end gap-2 py-2 ">
|
||||||
|
<div class="pl-1 ">Public Key</div>
|
||||||
|
</div>
|
||||||
|
<x-forms.input readonly id="public_key" />
|
||||||
<div class="flex items-end gap-2 py-2 ">
|
<div class="flex items-end gap-2 py-2 ">
|
||||||
<div class="pl-1 ">Private Key <span class='text-helper'>*</span></div>
|
<div class="pl-1 ">Private Key <span class='text-helper'>*</span></div>
|
||||||
<div class="text-xs text-white underline cursor-pointer" x-cloak x-show="!showPrivateKey"
|
<div class="text-xs text-white underline cursor-pointer" x-cloak x-show="!showPrivateKey"
|
||||||
@@ -43,5 +47,6 @@
|
|||||||
<x-forms.textarea rows="10" id="private_key.private_key" required />
|
<x-forms.textarea rows="10" id="private_key.private_key" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -76,6 +76,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div> --}}
|
</div> --}}
|
||||||
</div>
|
</div>
|
||||||
|
<h2 class="py-4">Services</h2>
|
||||||
|
<div class="grid justify-start grid-cols-1 gap-2 text-left xl:grid-cols-3">
|
||||||
|
Ghost, Plausible, Wordpress, etc... Coming very very soon...
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if ($current_step === 'servers')
|
@if ($current_step === 'servers')
|
||||||
<ul class="pb-10 steps">
|
<ul class="pb-10 steps">
|
||||||
@@ -135,10 +139,11 @@
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if ($current_step === 'existing-postgresql')
|
@if ($current_step === 'existing-postgresql')
|
||||||
<form wire:submit.prevent='addExistingPostgresql' class="flex items-end gap-2">
|
<form wire:submit.prevent='addExistingPostgresql' class="flex items-end gap-2">
|
||||||
<x-forms.input placeholder="postgres://username:password@database:5432" label="Database URL" id="existingPostgresqlUrl" />
|
<x-forms.input placeholder="postgres://username:password@database:5432" label="Database URL"
|
||||||
<x-forms.button type="submit">Add Database</x-forms.button>
|
id="existingPostgresqlUrl" />
|
||||||
</form>
|
<x-forms.button type="submit">Add Database</x-forms.button>
|
||||||
|
</form>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,11 +18,6 @@
|
|||||||
@else
|
@else
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
@endif
|
@endif
|
||||||
@if (!$server->settings->is_reachable || !$server->settings->is_usable)
|
|
||||||
<x-forms.button wire:click.prevent='validateServer'>
|
|
||||||
Validate Server
|
|
||||||
</x-forms.button>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@if (!$server->settings->is_reachable || !$server->settings->is_usable)
|
@if (!$server->settings->is_reachable || !$server->settings->is_usable)
|
||||||
@@ -51,43 +46,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if ($server->settings->is_reachable)
|
@if (!$server->settings->is_reachable)
|
||||||
|
<x-forms.button class="mt-8 mb-4 box" wire:click.prevent='validateServer'>
|
||||||
|
Validate Server
|
||||||
|
</x-forms.button>
|
||||||
|
@endif
|
||||||
|
@if ($server->settings->is_reachable && !$server->settings->is_usable && $server->id !== 0)
|
||||||
|
<x-forms.button wire:poll.2000ms='validateServer' class="mt-8 mb-4 box" onclick="installDocker.showModal()" wire:click.prevent='installDocker' isHighlighted>
|
||||||
|
Install Docker Engine 24.0
|
||||||
|
</x-forms.button>
|
||||||
|
@endif
|
||||||
|
@if ($server->settings->is_usable)
|
||||||
<h3 class="py-4">Settings</h3>
|
<h3 class="py-4">Settings</h3>
|
||||||
<div class="flex items-center w-64 gap-2">
|
<div class="flex items-center w-64 gap-2">
|
||||||
<x-forms.input id="cleanup_after_percentage" label="Disk Cleanup threshold (%)" required
|
<x-forms.input id="cleanup_after_percentage" label="Disk Cleanup threshold (%)" required
|
||||||
helper="Disk cleanup job will be executed if disk usage is more than this number." />
|
helper="Disk cleanup job will be executed if disk usage is more than this number." />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="py-4">Actions</h3>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<x-forms.button wire:click.prevent='validateServer'>
|
|
||||||
Check Server Details
|
|
||||||
</x-forms.button>
|
|
||||||
@if ($server->id !== 0)
|
|
||||||
<x-forms.button wire:click.prevent='installDocker' isHighlighted>
|
|
||||||
@if ($server->settings->is_usable)
|
|
||||||
Reconfigure Docker Engine
|
|
||||||
@else
|
|
||||||
Install Docker Engine
|
|
||||||
@endif
|
|
||||||
</x-forms.button>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
<div class="container w-full py-4 mx-auto">
|
|
||||||
<livewire:activity-monitor header="Logs" />
|
|
||||||
</div>
|
|
||||||
@isset($uptime)
|
|
||||||
<h3 class="pb-3">Server Info</h3>
|
|
||||||
<div class="py-2 pb-4">
|
|
||||||
<p>Uptime: {{ $uptime }}</p>
|
|
||||||
@isset($dockerVersion)
|
|
||||||
<p>Docker Engine {{ $dockerVersion }}</p>
|
|
||||||
@endisset
|
|
||||||
</div>
|
|
||||||
@endisset
|
|
||||||
</form>
|
</form>
|
||||||
<h2>Danger Zone</h2>
|
<h2 class="pt-4">Danger Zone</h2>
|
||||||
<div class="">Woah. I hope you know what are you doing.</div>
|
<div class="">Woah. I hope you know what are you doing.</div>
|
||||||
<h4 class="pt-4">Delete Server</h4>
|
<h4 class="pt-4">Delete Server</h4>
|
||||||
<div class="pb-4">This will remove this server from Coolify. Beware! There is no coming
|
<div class="pb-4">This will remove this server from Coolify. Beware! There is no coming
|
||||||
|
|||||||
@@ -22,11 +22,13 @@
|
|||||||
@endif
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<h3 class="pb-4">Select a different Private Key</h3>
|
<h3 class="pb-4">Choose another Key</h3>
|
||||||
<div class="grid gap-2">
|
<div class="grid grid-cols-3 gap-2">
|
||||||
@forelse ($privateKeys as $private_key)
|
@forelse ($privateKeys as $private_key)
|
||||||
<div class="cursor-pointer box" wire:click='setPrivateKey({{ $private_key->id }})'>{{ $private_key->name }}
|
<x-forms.button class="flex flex-col box" wire:click='setPrivateKey({{ $private_key->id }})'>
|
||||||
</div>
|
<div>{{ $private_key->name }}</div>
|
||||||
|
<div class="text-xs">{{ $private_key->description }}</div>
|
||||||
|
</x-forms.button>
|
||||||
@empty
|
@empty
|
||||||
<div>No private keys found.
|
<div>No private keys found.
|
||||||
<x-use-magic-bar link="/security/private-key/new" />
|
<x-use-magic-bar link="/security/private-key/new" />
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
<div>
|
<div>
|
||||||
|
<x-modal noSubmit modalId="installDocker">
|
||||||
|
<x-slot:modalBody>
|
||||||
|
<livewire:activity-monitor header="Installation Logs" />
|
||||||
|
</x-slot:modalBody>
|
||||||
|
<x-slot:modalSubmit>
|
||||||
|
<x-forms.button onclick="installDocker.close()" type="submit">
|
||||||
|
Close
|
||||||
|
</x-forms.button>
|
||||||
|
</x-slot:modalSubmit>
|
||||||
|
</x-modal>
|
||||||
<x-server.navbar :server="$server" />
|
<x-server.navbar :server="$server" />
|
||||||
<livewire:server.form :server="$server" />
|
<livewire:server.form :server="$server" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,7 +23,8 @@
|
|||||||
<x-forms.input id="email" type="email" label="Email" placeholder="youareawesome@protonmail.com" />
|
<x-forms.input id="email" type="email" label="Email" placeholder="youareawesome@protonmail.com" />
|
||||||
<x-forms.button type="submit">Join Waitlist</x-forms.button>
|
<x-forms.button type="submit">Join Waitlist</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
Waiting in the line: <span class="font-bold text-warning">{{ $waitingInLine }}</span>
|
<div>People waiting in the line: <span class="font-bold text-warning">{{ $waitingInLine }}</div>
|
||||||
|
<div>Already using Coolify Cloud: <span class="font-bold text-warning">{{ $users }}</div>
|
||||||
<div class="pt-8">
|
<div class="pt-8">
|
||||||
This is a paid & hosted version of Coolify.<br> See the pricing <a href="https://coolify.io/pricing" class="text-warning">here</a>.
|
This is a paid & hosted version of Coolify.<br> See the pricing <a href="https://coolify.io/pricing" class="text-warning">here</a>.
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -181,14 +181,24 @@ Route::get('/waitlist/confirm', function () {
|
|||||||
ray($email, $confirmation_code);
|
ray($email, $confirmation_code);
|
||||||
try {
|
try {
|
||||||
$found = Waitlist::where('uuid', $confirmation_code)->where('email', $email)->first();
|
$found = Waitlist::where('uuid', $confirmation_code)->where('email', $email)->first();
|
||||||
if ($found && !$found->verified && $found->created_at > now()->subMinutes(config('constants.waitlist.expiration'))) {
|
if ($found) {
|
||||||
$found->verified = true;
|
if (!$found->verified) {
|
||||||
$found->save();
|
if ($found->created_at > now()->subMinutes(config('constants.waitlist.expiration'))) {
|
||||||
send_internal_notification('Waitlist confirmed: ' . $email);
|
$found->verified = true;
|
||||||
return 'Thank you for confirming your email address. We will notify you when you are next in line.';
|
$found->save();
|
||||||
|
send_internal_notification('Waitlist confirmed: ' . $email);
|
||||||
|
return 'Thank you for confirming your email address. We will notify you when you are next in line.';
|
||||||
|
} else {
|
||||||
|
$found->delete();
|
||||||
|
send_internal_notification('Waitlist expired: ' . $email);
|
||||||
|
return 'Your confirmation code has expired. Please sign up again.';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
} catch (error) {
|
} catch (Exception $e) {
|
||||||
|
send_internal_notification('Waitlist confirmation failed: ' . $e->getMessage());
|
||||||
|
ray($e->getMessage());
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
})->name('webhooks.waitlist.confirm');
|
})->name('webhooks.waitlist.confirm');
|
||||||
@@ -203,7 +213,9 @@ Route::get('/waitlist/cancel', function () {
|
|||||||
return 'Your email address has been removed from the waitlist.';
|
return 'Your email address has been removed from the waitlist.';
|
||||||
}
|
}
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
} catch (error) {
|
} catch (Exception $e) {
|
||||||
|
send_internal_notification('Waitlist cancellation failed: ' . $e->getMessage());
|
||||||
|
ray($e->getMessage());
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
})->name('webhooks.waitlist.cancel');
|
})->name('webhooks.waitlist.cancel');
|
||||||
@@ -225,7 +237,7 @@ Route::post('/payments/stripe/events', function () {
|
|||||||
]);
|
]);
|
||||||
$type = data_get($event, 'type');
|
$type = data_get($event, 'type');
|
||||||
$data = data_get($event, 'data.object');
|
$data = data_get($event, 'data.object');
|
||||||
ray('Event: '. $type);
|
ray('Event: ' . $type);
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case 'checkout.session.completed':
|
case 'checkout.session.completed':
|
||||||
$clientReferenceId = data_get($data, 'client_reference_id');
|
$clientReferenceId = data_get($data, 'client_reference_id');
|
||||||
@@ -263,13 +275,13 @@ Route::post('/payments/stripe/events', function () {
|
|||||||
'stripe_invoice_paid' => true,
|
'stripe_invoice_paid' => true,
|
||||||
]);
|
]);
|
||||||
break;
|
break;
|
||||||
// case 'invoice.payment_failed':
|
// case 'invoice.payment_failed':
|
||||||
// $customerId = data_get($data, 'customer');
|
// $customerId = data_get($data, 'customer');
|
||||||
// $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
// $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||||
// if ($subscription) {
|
// if ($subscription) {
|
||||||
// SubscriptionInvoiceFailedJob::dispatch($subscription->team);
|
// SubscriptionInvoiceFailedJob::dispatch($subscription->team);
|
||||||
// }
|
// }
|
||||||
// break;
|
// break;
|
||||||
case 'customer.subscription.updated':
|
case 'customer.subscription.updated':
|
||||||
$customerId = data_get($data, 'customer');
|
$customerId = data_get($data, 'customer');
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||||
@@ -287,9 +299,9 @@ Route::post('/payments/stripe/events', function () {
|
|||||||
]);
|
]);
|
||||||
ray($feedback, $comment, $alreadyCancelAtPeriodEnd, $cancelAtPeriodEnd);
|
ray($feedback, $comment, $alreadyCancelAtPeriodEnd, $cancelAtPeriodEnd);
|
||||||
if ($feedback) {
|
if ($feedback) {
|
||||||
$reason = "Cancellation feedback for {$subscription->team->id}: '" . $feedback ."'";
|
$reason = "Cancellation feedback for {$subscription->team->id}: '" . $feedback . "'";
|
||||||
if ($comment) {
|
if ($comment) {
|
||||||
$reason .= ' with comment: \'' . $comment ."'";
|
$reason .= ' with comment: \'' . $comment . "'";
|
||||||
}
|
}
|
||||||
send_internal_notification($reason);
|
send_internal_notification($reason);
|
||||||
}
|
}
|
||||||
@@ -307,7 +319,7 @@ Route::post('/payments/stripe/events', function () {
|
|||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||||
$subscription->update([
|
$subscription->update([
|
||||||
'stripe_subscription_id' => null,
|
'stripe_subscription_id' => null,
|
||||||
'stripe_plan_id'=> null,
|
'stripe_plan_id' => null,
|
||||||
'stripe_cancel_at_period_end' => false,
|
'stripe_cancel_at_period_end' => false,
|
||||||
'stripe_invoice_paid' => false,
|
'stripe_invoice_paid' => false,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"version": "3.12.36"
|
"version": "3.12.36"
|
||||||
},
|
},
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.30"
|
"version": "4.0.0-beta.33"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user