Merge pull request #1297 from coollabsio/next

v4.0.0-beta.71
This commit is contained in:
Andras Bacsai 2023-10-09 15:19:35 +02:00 committed by GitHub
commit 6c3f97d9ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 401 additions and 234 deletions

View File

@ -36,7 +36,7 @@ You can find the installation script [here](./scripts/install.sh).
## Support ## Support
Contact us [here](https://docs.coollabs.io/contact). Contact us [here](https://coolify.io/contact).
## Recognitions ## Recognitions

View File

@ -58,6 +58,11 @@ class CreateNewUser implements CreatesNewUsers
'password' => Hash::make($input['password']), 'password' => Hash::make($input['password']),
]); ]);
$team = $user->teams()->first(); $team = $user->teams()->first();
if (isCloud()) {
$user->sendVerificationEmail();
} else {
$user->markEmailAsVerified();
}
} }
// Set session variable // Set session variable
session(['currentTeam' => $user->currentTeam = $team]); session(['currentTeam' => $user->currentTeam = $team]);

View File

@ -38,8 +38,7 @@ class Kernel extends HttpKernel
\App\Http\Middleware\VerifyCsrfToken::class, \App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\CheckForcePasswordReset::class, \App\Http\Middleware\CheckForcePasswordReset::class,
\App\Http\Middleware\IsSubscriptionValid::class, \App\Http\Middleware\DecideWhatToDoWithUser::class,
\App\Http\Middleware\IsBoardingFlow::class,
], ],

View File

@ -21,12 +21,14 @@ class Heading extends Component
public function check_status() public function check_status()
{ {
if ($this->application->destination->server->isFunctional()) {
dispatch(new ContainerStatusJob($this->application->destination->server)); dispatch(new ContainerStatusJob($this->application->destination->server));
$this->application->refresh(); $this->application->refresh();
$this->application->previews->each(function ($preview) { $this->application->previews->each(function ($preview) {
$preview->refresh(); $preview->refresh();
}); });
} }
}
public function force_deploy_without_cache() public function force_deploy_without_cache()
{ {

View File

@ -31,8 +31,10 @@ class Danger extends Component
$destination = $this->resource->destination->getMorphClass()::where('id', $this->resource->destination->id)->first(); $destination = $this->resource->destination->getMorphClass()::where('id', $this->resource->destination->id)->first();
$server = $destination->server; $server = $destination->server;
} }
if ($this->resource->destination->server->isFunctional()) {
instant_remote_process(["docker rm -f {$this->resource->uuid}"], $server); instant_remote_process(["docker rm -f {$this->resource->uuid}"], $server);
} }
}
$this->resource->delete(); $this->resource->delete();
return redirect()->route('project.resources', [ return redirect()->route('project.resources', [
'project_uuid' => $this->parameters['project_uuid'], 'project_uuid' => $this->parameters['project_uuid'],

View File

@ -15,7 +15,7 @@ class Show extends Component
{ {
$this->parameters = get_route_parameters(); $this->parameters = get_route_parameters();
try { try {
$this->server = Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->first(); $this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) { if (is_null($this->server)) {
return redirect()->route('server.all'); return redirect()->route('server.all');
} }

View File

@ -32,34 +32,18 @@ class ShowPrivateKey extends Component
} }
} }
public function checkConnection($install = false) public function checkConnection()
{ {
try { try {
$uptime = $this->server->validateConnection(); $uptime = $this->server->validateConnection();
if ($uptime) { if ($uptime) {
$install && $this->emit('success', 'Server is reachable.'); $this->emit('success', 'Server is reachable.');
} else { } else {
$install && $this->emit('error', 'Server is not reachable. Please check your connection and private key configuration.'); $this->emit('error', 'Server is not reachable. Please check your connection and private key configuration.');
return;
}
$dockerInstalled = $this->server->validateDockerEngine();
if ($dockerInstalled) {
$install && $this->emit('success', 'Docker Engine is installed.<br> Checking version.');
} else {
$install && $this->installDocker();
return;
}
$dockerVersion = $this->server->validateDockerEngineVersion();
if ($dockerVersion) {
$install && $this->emit('success', 'Docker Engine version is 23+.');
} else {
$install && $this->installDocker();
return; return;
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);
} finally {
$this->emit('proxyStatusUpdated');
} }
} }

View File

@ -5,10 +5,11 @@ namespace App\Http\Livewire;
use App\Actions\Server\UpdateCoolify; use App\Actions\Server\UpdateCoolify;
use App\Models\InstanceSettings; use App\Models\InstanceSettings;
use Livewire\Component; use Livewire\Component;
use Masmerise\Toaster\Toaster; use DanHarrin\LivewireRateLimiting\WithRateLimiting;
class Upgrade extends Component class Upgrade extends Component
{ {
use WithRateLimiting;
public bool $showProgress = false; public bool $showProgress = false;
public bool $isUpgradeAvailable = false; public bool $isUpgradeAvailable = false;
public string $latestVersion = ''; public string $latestVersion = '';
@ -31,6 +32,7 @@ class Upgrade extends Component
public function upgrade() public function upgrade()
{ {
try { try {
$this->rateLimit(1, 30);
if ($this->showProgress) { if ($this->showProgress) {
return; return;
} }

View File

@ -0,0 +1,26 @@
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
class VerifyEmail extends Component
{
use WithRateLimiting;
public function again() {
try {
$this->rateLimit(1, 300);
auth()->user()->sendVerificationEmail();
$this->emit('success', 'Email verification link sent!');
} catch(\Exception $e) {
ray($e);
return handleError($e,$this);
}
}
public function render()
{
return view('livewire.verify-email');
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Str;
class DecideWhatToDoWithUser
{
public function handle(Request $request, Closure $next): Response
{
if (!auth()->user() || !isCloud() || isInstanceAdmin()) {
return $next($request);
}
if (!auth()->user()->hasVerifiedEmail()) {
if ($request->path() === 'verify' || in_array($request->path(), allowedPathsForInvalidAccounts()) || $request->routeIs('verify.verify')) {
return $next($request);
}
return redirect('/verify');
}
if (!isSubscriptionActive() && !isSubscriptionOnGracePeriod()) {
if (!in_array($request->path(), allowedPathsForUnsubscribedAccounts())) {
if (Str::startsWith($request->path(), 'invitations')) {
return $next($request);
}
return redirect('subscription');
}
}
if (showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) {
if (Str::startsWith($request->path(), 'invitations')) {
return $next($request);
}
return redirect('boarding');
}
if (auth()->user()->hasVerifiedEmail() && $request->path() === 'verify') {
return redirect('/');
}
if (isSubscriptionActive() && $request->path() === 'subscription') {
return redirect('/');
}
return $next($request);
}
}

View File

@ -46,32 +46,43 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
try { try {
ray("checking server status for {$this->server->name}"); ray("checking server status for {$this->server->name}");
// ray()->clearAll(); // ray()->clearAll();
$serverUptimeCheckNumber = 0; $serverUptimeCheckNumber = $this->server->unreachable_count;
$serverUptimeCheckNumberMax = 3; $serverUptimeCheckNumberMax = 3;
while (true) {
ray('checking # ' . $serverUptimeCheckNumber); ray('checking # ' . $serverUptimeCheckNumber);
if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) { if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) {
send_internal_notification('Server unreachable: ' . $this->server->name);
if ($this->server->unreachable_email_sent === false) { if ($this->server->unreachable_email_sent === false) {
ray('Server unreachable, sending notification...'); ray('Server unreachable, sending notification...');
$this->server->team->notify(new Unreachable($this->server)); // $this->server->team->notify(new Unreachable($this->server));
$this->server->update(['unreachable_email_sent' => true]);
} }
$this->server->settings()->update([ $this->server->settings()->update([
'is_reachable' => false, 'is_reachable' => false,
]); ]);
$this->server->update(['unreachable_email_sent' => true]);
return; return;
} }
$result = $this->server->validateConnection(); $result = $this->server->validateConnection();
if ($result) { if ($result) {
break; $this->server->settings()->update([
} 'is_reachable' => true,
]);
$this->server->update([
'unreachable_count' => 0,
]);
} else {
$serverUptimeCheckNumber++; $serverUptimeCheckNumber++;
sleep(5); $this->server->settings()->update([
'is_reachable' => false,
]);
$this->server->update([
'unreachable_count' => $serverUptimeCheckNumber,
]);
return;
} }
if (data_get($this->server, 'unreachable_email_sent') === true) { if (data_get($this->server, 'unreachable_email_sent') === true) {
ray('Server is reachable again, sending notification...'); ray('Server is reachable again, sending notification...');
$this->server->team->notify(new Revived($this->server)); // $this->server->team->notify(new Revived($this->server));
$this->server->update(['unreachable_email_sent' => false]); $this->server->update(['unreachable_email_sent' => false]);
} }
if ( if (
@ -83,7 +94,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
'is_usable' => true 'is_usable' => true
]); ]);
} }
$this->server->validateDockerEngine(true); // $this->server->validateDockerEngine(true);
$containers = instant_remote_process(["docker container ls -q"], $this->server); $containers = instant_remote_process(["docker container ls -q"], $this->server);
if (!$containers) { if (!$containers) {
return; return;

View File

@ -33,11 +33,13 @@ class Application extends BaseModel
}); });
static::deleting(function ($application) { static::deleting(function ($application) {
// Stop Container // Stop Container
if ($application->destination->server->isFunctional()) {
instant_remote_process( instant_remote_process(
["docker rm -f {$application->uuid}"], ["docker rm -f {$application->uuid}"],
$application->destination->server, $application->destination->server,
false false
); );
}
$application->settings()->delete(); $application->settings()->delete();
$storages = $application->persistentStorages()->get(); $storages = $application->persistentStorages()->get();
foreach ($storages as $storage) { foreach ($storages as $storage) {

View File

@ -6,8 +6,12 @@ use App\Notifications\Channels\SendsEmail;
use App\Notifications\TransactionalEmails\ResetPassword as TransactionalEmailsResetPassword; use App\Notifications\TransactionalEmails\ResetPassword as TransactionalEmailsResetPassword;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\URL;
use Laravel\Fortify\TwoFactorAuthenticatable; use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Sanctum\HasApiTokens; use Laravel\Sanctum\HasApiTokens;
@ -54,6 +58,23 @@ class User extends Authenticatable implements SendsEmail
return $this->email; return $this->email;
} }
public function sendVerificationEmail()
{
$mail = new MailMessage();
$url = Url::temporarySignedRoute(
'verify.verify',
Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
[
'id' => $this->getKey(),
'hash' => sha1($this->getEmailForVerification()),
]
);
$mail->view('emails.email-verification', [
'url' => $url,
]);
$mail->subject('Coolify Cloud: Verify your email.');
send_user_an_email($mail, $this->email);
}
public function sendPasswordResetNotification($token): void public function sendPasswordResetNotification($token): void
{ {
$this->notify(new TransactionalEmailsResetPassword($token)); $this->notify(new TransactionalEmailsResetPassword($token));
@ -61,7 +82,7 @@ class User extends Authenticatable implements SendsEmail
public function isAdmin() public function isAdmin()
{ {
return data_get($this->pivot,'role') === 'admin' || data_get($this->pivot,'role') === 'owner'; return data_get($this->pivot, 'role') === 'admin' || data_get($this->pivot, 'role') === 'owner';
} }
public function isAdminFromSession() public function isAdminFromSession()
@ -79,7 +100,7 @@ class User extends Authenticatable implements SendsEmail
return true; return true;
} }
$team = $teams->where('id', session('currentTeam')->id)->first(); $team = $teams->where('id', session('currentTeam')->id)->first();
$role = data_get($team,'pivot.role'); $role = data_get($team, 'pivot.role');
return $role === 'admin' || $role === 'owner'; return $role === 'admin' || $role === 'owner';
} }
@ -96,7 +117,7 @@ class User extends Authenticatable implements SendsEmail
public function currentTeam() public function currentTeam()
{ {
return Cache::remember('team:' . auth()->user()->id, 3600, function() { return Cache::remember('team:' . auth()->user()->id, 3600, function () {
return Team::find(session('currentTeam')->id); return Team::find(session('currentTeam')->id);
}); });
} }

View File

@ -180,55 +180,55 @@ function refresh_server_connection(PrivateKey $private_key)
} }
} }
function validateServer(Server $server, bool $throwError = false) // function validateServer(Server $server, bool $throwError = false)
{ // {
try { // try {
$uptime = instant_remote_process(['uptime'], $server, $throwError); // $uptime = instant_remote_process(['uptime'], $server, $throwError);
if (!$uptime) { // if (!$uptime) {
$server->settings->is_reachable = false; // $server->settings->is_reachable = false;
$server->team->notify(new Unreachable($server)); // $server->team->notify(new Unreachable($server));
$server->unreachable_email_sent = true; // $server->unreachable_email_sent = true;
$server->save(); // $server->save();
return [ // return [
"uptime" => null, // "uptime" => null,
"dockerVersion" => null, // "dockerVersion" => null,
]; // ];
} // }
$server->settings->is_reachable = true; // $server->settings->is_reachable = true;
instant_remote_process(["docker ps"], $server, $throwError); // instant_remote_process(["docker ps"], $server, $throwError);
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $server, $throwError); // $dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $server, $throwError);
if (!$dockerVersion) { // if (!$dockerVersion) {
$dockerVersion = null; // $dockerVersion = null;
return [ // return [
"uptime" => $uptime, // "uptime" => $uptime,
"dockerVersion" => null, // "dockerVersion" => null,
]; // ];
} // }
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion); // $dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
if (is_null($dockerVersion)) { // if (is_null($dockerVersion)) {
$server->settings->is_usable = false; // $server->settings->is_usable = false;
} else { // } else {
$server->settings->is_usable = true; // $server->settings->is_usable = true;
if (data_get($server, 'unreachable_email_sent') === true) { // if (data_get($server, 'unreachable_email_sent') === true) {
$server->team->notify(new Revived($server)); // $server->team->notify(new Revived($server));
$server->unreachable_email_sent = false; // $server->unreachable_email_sent = false;
$server->save(); // $server->save();
} // }
} // }
return [ // return [
"uptime" => $uptime, // "uptime" => $uptime,
"dockerVersion" => $dockerVersion, // "dockerVersion" => $dockerVersion,
]; // ];
} catch (\Throwable $e) { // } catch (\Throwable $e) {
$server->settings->is_reachable = false; // $server->settings->is_reachable = false;
$server->settings->is_usable = false; // $server->settings->is_usable = false;
throw $e; // throw $e;
} finally { // } finally {
if (data_get($server, 'settings')) { // if (data_get($server, 'settings')) {
$server->settings->save(); // $server->settings->save();
} // }
} // }
} // }
function checkRequiredCommands(Server $server) function checkRequiredCommands(Server $server)
{ {

View File

@ -122,14 +122,14 @@ function allowedPathsForUnsubscribedAccounts()
return [ return [
'subscription', 'subscription',
'login', 'login',
'register', 'logout',
'waitlist', 'waitlist',
'force-password-reset', 'force-password-reset',
'logout',
'livewire/message/force-password-reset', 'livewire/message/force-password-reset',
'livewire/message/check-license', 'livewire/message/check-license',
'livewire/message/switch-team', 'livewire/message/switch-team',
'livewire/message/subscription.pricing-plans' 'livewire/message/subscription.pricing-plans',
'livewire/message/help'
]; ];
} }
function allowedPathsForBoardingAccounts() function allowedPathsForBoardingAccounts()
@ -141,3 +141,11 @@ function allowedPathsForBoardingAccounts()
'livewire/message/activity-monitor' 'livewire/message/activity-monitor'
]; ];
} }
function allowedPathsForInvalidAccounts() {
return [
'logout',
'verify',
'livewire/message/verify-email',
'livewire/message/help'
];
}

136
composer.lock generated
View File

@ -62,16 +62,16 @@
}, },
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
"version": "3.283.0", "version": "3.283.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/aws/aws-sdk-php.git", "url": "https://github.com/aws/aws-sdk-php.git",
"reference": "5084c03431ecda0003e35d7fc7a12eeca4242685" "reference": "6616677d76e39af28138512740199d38a461859f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5084c03431ecda0003e35d7fc7a12eeca4242685", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/6616677d76e39af28138512740199d38a461859f",
"reference": "5084c03431ecda0003e35d7fc7a12eeca4242685", "reference": "6616677d76e39af28138512740199d38a461859f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -151,9 +151,9 @@
"support": { "support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues", "issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.283.0" "source": "https://github.com/aws/aws-sdk-php/tree/3.283.2"
}, },
"time": "2023-10-04T18:08:32+00:00" "time": "2023-10-06T18:09:54+00:00"
}, },
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@ -1083,16 +1083,16 @@
}, },
{ {
"name": "egulias/email-validator", "name": "egulias/email-validator",
"version": "4.0.1", "version": "4.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/egulias/EmailValidator.git", "url": "https://github.com/egulias/EmailValidator.git",
"reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff" "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/3a85486b709bc384dae8eb78fb2eec649bdb64ff", "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e",
"reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff", "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1101,8 +1101,8 @@
"symfony/polyfill-intl-idn": "^1.26" "symfony/polyfill-intl-idn": "^1.26"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^9.5.27", "phpunit/phpunit": "^10.2",
"vimeo/psalm": "^4.30" "vimeo/psalm": "^5.12"
}, },
"suggest": { "suggest": {
"ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
@ -1138,7 +1138,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/egulias/EmailValidator/issues", "issues": "https://github.com/egulias/EmailValidator/issues",
"source": "https://github.com/egulias/EmailValidator/tree/4.0.1" "source": "https://github.com/egulias/EmailValidator/tree/4.0.2"
}, },
"funding": [ "funding": [
{ {
@ -1146,7 +1146,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-01-14T14:17:03+00:00" "time": "2023-10-06T06:47:41+00:00"
}, },
{ {
"name": "fruitcake/php-cors", "name": "fruitcake/php-cors",
@ -2724,16 +2724,16 @@
}, },
{ {
"name": "league/flysystem", "name": "league/flysystem",
"version": "3.16.0", "version": "3.17.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/flysystem.git", "url": "https://github.com/thephpleague/flysystem.git",
"reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729" "reference": "bd4c9b26849d82364119c68429541f1631fba94b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4fdf372ca6b63c6e281b1c01a624349ccb757729", "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/bd4c9b26849d82364119c68429541f1631fba94b",
"reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729", "reference": "bd4c9b26849d82364119c68429541f1631fba94b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2751,8 +2751,8 @@
"symfony/http-client": "<5.2" "symfony/http-client": "<5.2"
}, },
"require-dev": { "require-dev": {
"async-aws/s3": "^1.5", "async-aws/s3": "^1.5 || ^2.0",
"async-aws/simple-s3": "^1.1", "async-aws/simple-s3": "^1.1 || ^2.0",
"aws/aws-sdk-php": "^3.220.0", "aws/aws-sdk-php": "^3.220.0",
"composer/semver": "^3.0", "composer/semver": "^3.0",
"ext-fileinfo": "*", "ext-fileinfo": "*",
@ -2798,7 +2798,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/thephpleague/flysystem/issues", "issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.16.0" "source": "https://github.com/thephpleague/flysystem/tree/3.17.0"
}, },
"funding": [ "funding": [
{ {
@ -2810,7 +2810,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-09-07T19:22:17+00:00" "time": "2023-10-05T20:15:05+00:00"
}, },
{ {
"name": "league/flysystem-aws-s3-v3", "name": "league/flysystem-aws-s3-v3",
@ -3557,16 +3557,16 @@
}, },
{ {
"name": "nette/schema", "name": "nette/schema",
"version": "v1.2.4", "version": "v1.2.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nette/schema.git", "url": "https://github.com/nette/schema.git",
"reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab" "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/c9ff517a53903b3d4e29ec547fb20feecb05b8ab", "url": "https://api.github.com/repos/nette/schema/zipball/0462f0166e823aad657c9224d0f849ecac1ba10a",
"reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab", "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3613,9 +3613,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/nette/schema/issues", "issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.2.4" "source": "https://github.com/nette/schema/tree/v1.2.5"
}, },
"time": "2023-08-05T18:56:25+00:00" "time": "2023-10-05T20:37:59+00:00"
}, },
{ {
"name": "nette/utils", "name": "nette/utils",
@ -6757,16 +6757,16 @@
}, },
{ {
"name": "stripe/stripe-php", "name": "stripe/stripe-php",
"version": "v12.5.0", "version": "v12.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/stripe/stripe-php.git", "url": "https://github.com/stripe/stripe-php.git",
"reference": "a4249b4a90437844f6c35e8701f8c68acd206f56" "reference": "e0c15e4cbf252e708b937482bb1a50fa7e01bc9d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/a4249b4a90437844f6c35e8701f8c68acd206f56", "url": "https://api.github.com/repos/stripe/stripe-php/zipball/e0c15e4cbf252e708b937482bb1a50fa7e01bc9d",
"reference": "a4249b4a90437844f6c35e8701f8c68acd206f56", "reference": "e0c15e4cbf252e708b937482bb1a50fa7e01bc9d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6811,9 +6811,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/stripe/stripe-php/issues", "issues": "https://github.com/stripe/stripe-php/issues",
"source": "https://github.com/stripe/stripe-php/tree/v12.5.0" "source": "https://github.com/stripe/stripe-php/tree/v12.6.0"
}, },
"time": "2023-09-28T23:06:27+00:00" "time": "2023-10-05T18:01:43+00:00"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
@ -10258,16 +10258,16 @@
"packages-dev": [ "packages-dev": [
{ {
"name": "brianium/paratest", "name": "brianium/paratest",
"version": "v7.2.8", "version": "v7.2.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/paratestphp/paratest.git", "url": "https://github.com/paratestphp/paratest.git",
"reference": "882b02d197328138686bb06ce7d8cbb98fc0a16c" "reference": "1f9e41c0779be4540654d92a9314016713f5e62c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/882b02d197328138686bb06ce7d8cbb98fc0a16c", "url": "https://api.github.com/repos/paratestphp/paratest/zipball/1f9e41c0779be4540654d92a9314016713f5e62c",
"reference": "882b02d197328138686bb06ce7d8cbb98fc0a16c", "reference": "1f9e41c0779be4540654d92a9314016713f5e62c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -10275,13 +10275,13 @@
"ext-pcre": "*", "ext-pcre": "*",
"ext-reflection": "*", "ext-reflection": "*",
"ext-simplexml": "*", "ext-simplexml": "*",
"fidry/cpu-core-counter": "^0.4.1 || ^0.5.1", "fidry/cpu-core-counter": "^0.5.1",
"jean85/pretty-package-versions": "^2.0.5", "jean85/pretty-package-versions": "^2.0.5",
"php": "~8.1.0 || ~8.2.0 || ~8.3.0", "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
"phpunit/php-code-coverage": "^10.1.3", "phpunit/php-code-coverage": "^10.1.7",
"phpunit/php-file-iterator": "^4.0.2", "phpunit/php-file-iterator": "^4.1.0",
"phpunit/php-timer": "^6.0", "phpunit/php-timer": "^6.0",
"phpunit/phpunit": "^10.3.2", "phpunit/phpunit": "^10.4.0",
"sebastian/environment": "^6.0.1", "sebastian/environment": "^6.0.1",
"symfony/console": "^6.3.4", "symfony/console": "^6.3.4",
"symfony/process": "^6.3.4" "symfony/process": "^6.3.4"
@ -10290,8 +10290,8 @@
"doctrine/coding-standard": "^12.0.0", "doctrine/coding-standard": "^12.0.0",
"ext-pcov": "*", "ext-pcov": "*",
"ext-posix": "*", "ext-posix": "*",
"infection/infection": "^0.27.0", "infection/infection": "^0.27.3",
"phpstan/phpstan": "^1.10.32", "phpstan/phpstan": "^1.10.37",
"phpstan/phpstan-deprecation-rules": "^1.1.4", "phpstan/phpstan-deprecation-rules": "^1.1.4",
"phpstan/phpstan-phpunit": "^1.3.14", "phpstan/phpstan-phpunit": "^1.3.14",
"phpstan/phpstan-strict-rules": "^1.5.1", "phpstan/phpstan-strict-rules": "^1.5.1",
@ -10337,7 +10337,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/paratestphp/paratest/issues", "issues": "https://github.com/paratestphp/paratest/issues",
"source": "https://github.com/paratestphp/paratest/tree/v7.2.8" "source": "https://github.com/paratestphp/paratest/tree/v7.2.9"
}, },
"funding": [ "funding": [
{ {
@ -10349,7 +10349,7 @@
"type": "paypal" "type": "paypal"
} }
], ],
"time": "2023-10-04T13:38:04+00:00" "time": "2023-10-06T07:53:04+00:00"
}, },
{ {
"name": "fakerphp/faker", "name": "fakerphp/faker",
@ -10983,35 +10983,35 @@
}, },
{ {
"name": "pestphp/pest", "name": "pestphp/pest",
"version": "v2.20.0", "version": "v2.21.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pestphp/pest.git", "url": "https://github.com/pestphp/pest.git",
"reference": "a8b785f69e44ae3f902cbf08fe6b79359ba46945" "reference": "2ffafd445d42c8b7b7e1874bde1c29945767a49d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pestphp/pest/zipball/a8b785f69e44ae3f902cbf08fe6b79359ba46945", "url": "https://api.github.com/repos/pestphp/pest/zipball/2ffafd445d42c8b7b7e1874bde1c29945767a49d",
"reference": "a8b785f69e44ae3f902cbf08fe6b79359ba46945", "reference": "2ffafd445d42c8b7b7e1874bde1c29945767a49d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"brianium/paratest": "^7.2.7", "brianium/paratest": "^7.2.9",
"nunomaduro/collision": "^7.9.0", "nunomaduro/collision": "^7.9.0",
"nunomaduro/termwind": "^1.15.1", "nunomaduro/termwind": "^1.15.1",
"pestphp/pest-plugin": "^2.1.1", "pestphp/pest-plugin": "^2.1.1",
"pestphp/pest-plugin-arch": "^2.3.3", "pestphp/pest-plugin-arch": "^2.3.3",
"php": "^8.1.0", "php": "^8.1.0",
"phpunit/phpunit": "^10.3.5" "phpunit/phpunit": "^10.4.0"
}, },
"conflict": { "conflict": {
"phpunit/phpunit": ">10.3.5", "phpunit/phpunit": ">10.4.0",
"sebastian/exporter": "<5.1.0", "sebastian/exporter": "<5.1.0",
"webmozart/assert": "<1.11.0" "webmozart/assert": "<1.11.0"
}, },
"require-dev": { "require-dev": {
"pestphp/pest-dev-tools": "^2.16.0", "pestphp/pest-dev-tools": "^2.16.0",
"pestphp/pest-plugin-type-coverage": "^2.2.0", "pestphp/pest-plugin-type-coverage": "^2.4.0",
"symfony/process": "^6.3.4" "symfony/process": "^6.3.4"
}, },
"bin": [ "bin": [
@ -11070,7 +11070,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/pestphp/pest/issues", "issues": "https://github.com/pestphp/pest/issues",
"source": "https://github.com/pestphp/pest/tree/v2.20.0" "source": "https://github.com/pestphp/pest/tree/v2.21.0"
}, },
"funding": [ "funding": [
{ {
@ -11082,7 +11082,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-09-29T18:05:52+00:00" "time": "2023-10-06T12:33:39+00:00"
}, },
{ {
"name": "pestphp/pest-plugin", "name": "pestphp/pest-plugin",
@ -11454,16 +11454,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.37", "version": "1.10.38",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "058ba07e92f744d4dcf6061ae75283d0c6456f2e" "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/058ba07e92f744d4dcf6061ae75283d0c6456f2e", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5302bb402c57f00fb3c2c015bac86e0827e4b691",
"reference": "058ba07e92f744d4dcf6061ae75283d0c6456f2e", "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -11512,7 +11512,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-10-02T16:18:37+00:00" "time": "2023-10-06T14:19:14+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
@ -11837,16 +11837,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "10.3.5", "version": "10.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503" "reference": "9784e877e3700de37475545bdbdce8383ff53d25"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/747c3b2038f1139e3dcd9886a3f5a948648b7503", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9784e877e3700de37475545bdbdce8383ff53d25",
"reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503", "reference": "9784e877e3700de37475545bdbdce8383ff53d25",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -11886,7 +11886,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "10.3-dev" "dev-main": "10.4-dev"
} }
}, },
"autoload": { "autoload": {
@ -11918,7 +11918,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.5" "source": "https://github.com/sebastianbergmann/phpunit/tree/10.4.0"
}, },
"funding": [ "funding": [
{ {
@ -11934,7 +11934,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-09-19T05:42:37+00:00" "time": "2023-10-06T03:41:22+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",

View File

@ -1,6 +1,7 @@
<?php <?php
return [ return [
'docs' => 'https://coolify.io/contact',
'self_hosted' => env('SELF_HOSTED', true), 'self_hosted' => env('SELF_HOSTED', true),
'waitlist' => env('WAITLIST', false), 'waitlist' => env('WAITLIST', false),
'license_url' => 'https://licenses.coollabs.io', 'license_url' => 'https://licenses.coollabs.io',

View File

@ -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.70', 'release' => '4.0.0-beta.71',
// 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'),

View File

@ -1,3 +1,3 @@
<?php <?php
return '4.0.0-beta.70'; return '4.0.0-beta.71';

View File

@ -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('servers', function (Blueprint $table) {
$table->integer('unreachable_count')->default(0);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('servers', function (Blueprint $table) {
$table->dropColumn('unreachable_count');
});
}
};

58
package-lock.json generated
View File

@ -6,18 +6,18 @@
"": { "": {
"dependencies": { "dependencies": {
"@tailwindcss/typography": "0.5.10", "@tailwindcss/typography": "0.5.10",
"alpinejs": "3.13.0", "alpinejs": "3.13.1",
"daisyui": "3.7.7", "daisyui": "3.9.2",
"tailwindcss-scrollbar": "0.1.0" "tailwindcss-scrollbar": "0.1.0"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "4.3.4", "@vitejs/plugin-vue": "4.4.0",
"autoprefixer": "10.4.16", "autoprefixer": "10.4.16",
"axios": "1.5.0", "axios": "1.5.1",
"laravel-vite-plugin": "0.8.0", "laravel-vite-plugin": "0.8.1",
"postcss": "8.4.30", "postcss": "8.4.31",
"tailwindcss": "3.3.3", "tailwindcss": "3.3.3",
"vite": "4.4.9", "vite": "4.4.11",
"vue": "3.3.4" "vue": "3.3.4"
} }
}, },
@ -503,9 +503,9 @@
} }
}, },
"node_modules/@vitejs/plugin-vue": { "node_modules/@vitejs/plugin-vue": {
"version": "4.3.4", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.3.4.tgz", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.4.0.tgz",
"integrity": "sha512-ciXNIHKPriERBisHFBvnTbfKa6r9SAesOYXeGDzgegcvy9Q4xdScSHAmKbNT0M3O0S9LKhIf5/G+UYG4NnnzYw==", "integrity": "sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^14.18.0 || >=16.0.0" "node": "^14.18.0 || >=16.0.0"
@ -683,9 +683,9 @@
"integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==" "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA=="
}, },
"node_modules/alpinejs": { "node_modules/alpinejs": {
"version": "3.13.0", "version": "3.13.1",
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.0.tgz", "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.1.tgz",
"integrity": "sha512-7FYR1Yz3evIjlJD1mZ3SYWSw+jlOmQGeQ1QiSufSQ6J84XMQFkzxm6OobiZ928SfqhGdoIp2SsABNsS4rXMMJw==", "integrity": "sha512-/LZ7mumW02V7AV5xTTftJFHS0I3KOXLl7tHm4xpxXAV+HJ/zjTT0n8MU7RZ6UoGPhmO/i+KEhQojaH/0RsH5tg==",
"dependencies": { "dependencies": {
"@vue/reactivity": "~3.1.1" "@vue/reactivity": "~3.1.1"
} }
@ -756,9 +756,9 @@
} }
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.5.0", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz",
"integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"follow-redirects": "^1.15.0", "follow-redirects": "^1.15.0",
@ -953,15 +953,15 @@
"dev": true "dev": true
}, },
"node_modules/daisyui": { "node_modules/daisyui": {
"version": "3.7.7", "version": "3.9.2",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.7.7.tgz", "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.9.2.tgz",
"integrity": "sha512-2/nFdW/6R9MMnR8tTm07jPVyPaZwpUSkVsFAADb7Oq8N2Ynbls57laDdNqxTCUmn0QvcZi01TKl8zQbAwRfw1w==", "integrity": "sha512-yJZ1QjHUaL+r9BkquTdzNHb7KIgAJVFh0zbOXql2Wu0r7zx5qZNLxclhjN0WLoIpY+o2h/8lqXg7ijj8oTigOw==",
"dependencies": { "dependencies": {
"colord": "^2.9", "colord": "^2.9",
"css-selector-tokenizer": "^0.8", "css-selector-tokenizer": "^0.8",
"postcss": "^8", "postcss": "^8",
"postcss-js": "^4", "postcss-js": "^4",
"tailwindcss": "^3" "tailwindcss": "^3.1"
}, },
"engines": { "engines": {
"node": ">=16.9.0" "node": ">=16.9.0"
@ -1289,9 +1289,9 @@
} }
}, },
"node_modules/laravel-vite-plugin": { "node_modules/laravel-vite-plugin": {
"version": "0.8.0", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.8.0.tgz", "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.8.1.tgz",
"integrity": "sha512-6VjLI+azBpeK6rWBiKcb/En5GnTdYpL0U4zS8gXYvb2/VSq4mlau5H3NWpSktUDBMM1b97LLgICx5zevi8IY0w==", "integrity": "sha512-fxzUDjOA37kOsYq8dP+3oPIlw8/kJVXwu0hOXLun82R1LpV02shGeWGYKx2lbpKffL5I0sfPPjfqbYxuqBluAA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
@ -1516,9 +1516,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.30", "version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==", "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -1920,9 +1920,9 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "4.4.9", "version": "4.4.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz",
"integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"esbuild": "^0.18.10", "esbuild": "^0.18.10",

View File

@ -6,19 +6,19 @@
"build": "vite build" "build": "vite build"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "4.3.4", "@vitejs/plugin-vue": "4.4.0",
"autoprefixer": "10.4.16", "autoprefixer": "10.4.16",
"axios": "1.5.0", "axios": "1.5.1",
"laravel-vite-plugin": "0.8.0", "laravel-vite-plugin": "0.8.1",
"postcss": "8.4.30", "postcss": "8.4.31",
"tailwindcss": "3.3.3", "tailwindcss": "3.3.3",
"vite": "4.4.9", "vite": "4.4.11",
"vue": "3.3.4" "vue": "3.3.4"
}, },
"dependencies": { "dependencies": {
"@tailwindcss/typography": "0.5.10", "@tailwindcss/typography": "0.5.10",
"alpinejs": "3.13.0", "alpinejs": "3.13.1",
"daisyui": "3.7.7", "daisyui": "3.9.2",
"tailwindcss-scrollbar": "0.1.0" "tailwindcss-scrollbar": "0.1.0"
} }
} }

View File

@ -9,12 +9,12 @@
@if ($is_registration_enabled) @if ($is_registration_enabled)
@if (config('coolify.waitlist')) @if (config('coolify.waitlist'))
<a href="/waitlist" <a href="/waitlist"
class="text-xs normal-case hover:no-underline btn btn-sm bg-coollabs-gradient"> class="text-xs text-center text-white normal-case bg-transparent border-none rounded no-animation hover:no-underline btn btn-sm bg-coollabs-gradient">
Join the waitlist Join the waitlist
</a> </a>
@else @else
<a href="/register" <a href="/register"
class="text-xs normal-case hover:no-underline btn btn-sm bg-coollabs-gradient"> class="text-xs text-center text-white normal-case bg-transparent border-none rounded no-animation hover:no-underline btn btn-sm bg-coollabs-gradient">
{{ __('auth.register_now') }} {{ __('auth.register_now') }}
</a> </a>
@endif @endif

View File

@ -0,0 +1,12 @@
<x-layout-subscription>
<div class="min-h-screen hero">
<div class="min-w-fit">
<h1> Verification Email Sent </h1>
<div class="flex justify-center gap-2 text-center">
<br>To activate your account, please open the email and follow the
instructions.
</div>
<livewire:verify-email />
</div>
</div>
</x-layout-subscription>

View File

@ -256,7 +256,7 @@
your self-hosted instance? your self-hosted instance?
<x-forms.button> <x-forms.button>
<a class="font-bold text-white hover:no-underline" <a class="font-bold text-white hover:no-underline"
href="https://docs.coollabs.io/contact">Contact Us</a> href="{{ config('coolify.docs') }}">Contact Us</a>
</x-forms.button> </x-forms.button>
</div> </div>
</div> </div>

View File

@ -0,0 +1,3 @@
<x-emails.layout>
Verify your email [here]({{ $url }}).
</x-emails.layout>

View File

@ -10,7 +10,7 @@
<a href="/"> <a href="/">
<x-forms.button>Go back home</x-forms.button> <x-forms.button>Go back home</x-forms.button>
</a> </a>
<a target="_blank" class="text-xs" href="https://docs.coollabs.io/contact.html">Contact <a target="_blank" class="text-xs" href="{{ config('coolify.docs') }}">Contact
support support
<x-external-link /> <x-external-link />
</a> </a>

View File

@ -10,7 +10,7 @@
<a href="/"> <a href="/">
<x-forms.button>Go back home</x-forms.button> <x-forms.button>Go back home</x-forms.button>
</a> </a>
<a target="_blank" class="text-xs" href="https://docs.coollabs.io/contact.html">Contact <a target="_blank" class="text-xs" href="{{ config('coolify.docs') }}">Contact
support support
<x-external-link /> <x-external-link />
</a> </a>

View File

@ -11,7 +11,7 @@
<a href="/"> <a href="/">
<x-forms.button>Go back home</x-forms.button> <x-forms.button>Go back home</x-forms.button>
</a> </a>
<a target="_blank" class="text-xs" href="https://docs.coollabs.io/contact.html">Contact <a target="_blank" class="text-xs" href="{{ config('coolify.docs') }}">Contact
support support
<x-external-link /> <x-external-link />
</a> </a>

View File

@ -11,7 +11,7 @@
<a href="/"> <a href="/">
<x-forms.button>Go back home</x-forms.button> <x-forms.button>Go back home</x-forms.button>
</a> </a>
<a href="https://docs.coollabs.io/contact.html" class="font-semibold text-white ">Contact <a href="{{ config('coolify.docs') }}" class="font-semibold text-white ">Contact
support support
<span aria-hidden="true">&rarr;</span></a> <span aria-hidden="true">&rarr;</span></a>
</div> </div>

View File

@ -10,7 +10,7 @@
<a href="/"> <a href="/">
<x-forms.button>Go back home</x-forms.button> <x-forms.button>Go back home</x-forms.button>
</a> </a>
<a href="https://docs.coollabs.io/contact.html" class="font-semibold text-white ">Contact <a href="{{ config('coolify.docs') }}" class="font-semibold text-white ">Contact
support support
<span aria-hidden="true">&rarr;</span></a> <span aria-hidden="true">&rarr;</span></a>
</div> </div>

View File

@ -14,7 +14,7 @@
<a href="/"> <a href="/">
<x-forms.button>Go back home</x-forms.button> <x-forms.button>Go back home</x-forms.button>
</a> </a>
<a href="https://docs.coollabs.io/contact.html" class="font-semibold text-white">Contact <a href="{{ config('coolify.docs') }}" class="font-semibold text-white">Contact
support support
<span aria-hidden="true">&rarr;</span></a> <span aria-hidden="true">&rarr;</span></a>
</div> </div>

View File

@ -8,7 +8,7 @@
patience. patience.
</p> </p>
<div class="flex items-center justify-center mt-10 gap-x-6"> <div class="flex items-center justify-center mt-10 gap-x-6">
<a href="https://docs.coollabs.io/contact.html" class="font-semibold text-white ">Contact <a href="{{ config('coolify.docs') }}" class="font-semibold text-white ">Contact
support support
<span aria-hidden="true">&rarr;</span></a> <span aria-hidden="true">&rarr;</span></a>
</div> </div>

View File

@ -16,7 +16,7 @@
again</x-forms.button></a> again</x-forms.button></a>
@endif @endif
<div>To update your subscription (upgrade / downgrade), please <a class="text-white underline" <div>To update your subscription (upgrade / downgrade), please <a class="text-white underline"
href="https://docs.coollabs.io/contact" target="_blank">contact us.</a></div> href="{{ config('coolify.docs') }}" target="_blank">contact us.</a></div>
</div> </div>
@endif @endif
@if (subscriptionProvider() === 'lemon') @if (subscriptionProvider() === 'lemon')
@ -25,7 +25,7 @@
@if (currentTeam()->subscription->lemon_status === 'cancelled') @if (currentTeam()->subscription->lemon_status === 'cancelled')
<div class="pb-4">Subscriptions ends at: {{ getRenewDate() }}</div> <div class="pb-4">Subscriptions ends at: {{ getRenewDate() }}</div>
<div class="py-4">If you would like to change the subscription to a lower/higher plan, <a <div class="py-4">If you would like to change the subscription to a lower/higher plan, <a
class="text-white underline" href="https://docs.coollabs.io/contact" target="_blank">please class="text-white underline" href="{{ config('coolify.docs') }}" target="_blank">please
contact contact
us.</a></div> us.</a></div>
@else @else

View File

@ -23,12 +23,12 @@
</x-slot:pro> </x-slot:pro>
<x-slot:ultimate> <x-slot:ultimate>
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-ultimate" <x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-ultimate"
class="w-full h-10 buyme"><a class="text-white hover:no-underline" href="https://docs.coollabs.io/contact" target="_blank"> class="w-full h-10 buyme"><a class="text-white hover:no-underline" href="{{ config('coolify.docs') }}" target="_blank">
Contact Us</a> Contact Us</a>
</x-forms.button> </x-forms.button>
<x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-ultimate" <x-forms.button x-show="selected === 'yearly'" x-cloak aria-describedby="tier-ultimate"
class="w-full h-10 buyme"><a class="text-white hover:no-underline" href="https://docs.coollabs.io/contact" target="_blank"> class="w-full h-10 buyme"><a class="text-white hover:no-underline" href="{{ config('coolify.docs') }}" target="_blank">
Contact Us</a> Contact Us</a>
</x-forms.button> </x-forms.button>
</x-slot:ultimate> </x-slot:ultimate>

View File

@ -0,0 +1,3 @@
<div class="pt-4">
<x-forms.button wire:click="again">Send Verification Email Again</x-forms.button>
</div>

View File

@ -26,6 +26,7 @@ use App\Models\PrivateKey;
use App\Models\Server; use App\Models\Server;
use App\Models\StandaloneDocker; use App\Models\StandaloneDocker;
use App\Models\SwarmDocker; use App\Models\SwarmDocker;
use Illuminate\Foundation\Auth\EmailVerificationRequest;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password; use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
@ -61,7 +62,19 @@ Route::post('/forgot-password', function (Request $request) {
} }
return response()->json(['message' => 'Transactional emails are not active'], 400); return response()->json(['message' => 'Transactional emails are not active'], 400);
})->name('password.forgot'); })->name('password.forgot');
Route::get('/waitlist', WaitlistIndex::class)->name('waitlist.index'); Route::get('/waitlist', WaitlistIndex::class)->name('waitlist.index');
Route::get('/verify', function () {
return view('auth.verify-email');
})->middleware('auth')->name('verify.email');
Route::get('/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) {
$request->fulfill();
return redirect('/');
})->middleware(['auth'])->name('verify.verify');
Route::middleware(['throttle:login'])->group(function () { Route::middleware(['throttle:login'])->group(function () {
Route::get('/auth/link', [Controller::class, 'link'])->name('auth.link'); Route::get('/auth/link', [Controller::class, 'link'])->name('auth.link');
}); });
@ -74,7 +87,7 @@ Route::prefix('magic')->middleware(['auth'])->group(function () {
Route::get('/environment/new', [MagicController::class, 'newEnvironment']); Route::get('/environment/new', [MagicController::class, 'newEnvironment']);
}); });
Route::middleware(['auth'])->group(function () { Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/projects', [ProjectController::class, 'all'])->name('projects'); Route::get('/projects', [ProjectController::class, 'all'])->name('projects');
Route::get('/project/{project_uuid}/edit', [ProjectController::class, 'edit'])->name('project.edit'); Route::get('/project/{project_uuid}/edit', [ProjectController::class, 'edit'])->name('project.edit');
Route::get('/project/{project_uuid}', [ProjectController::class, 'show'])->name('project.show'); Route::get('/project/{project_uuid}', [ProjectController::class, 'show'])->name('project.show');
@ -114,7 +127,7 @@ Route::middleware(['auth'])->group(function () {
}); });
Route::middleware(['auth'])->group(function () { Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/', Dashboard::class)->name('dashboard'); Route::get('/', Dashboard::class)->name('dashboard');
Route::get('/boarding', BoardingIndex::class)->name('boarding'); Route::get('/boarding', BoardingIndex::class)->name('boarding');
Route::middleware(['throttle:force-password-reset'])->group(function () { Route::middleware(['throttle:force-password-reset'])->group(function () {