mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-24 20:49:32 +00:00
Compare commits
15 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
642a6e3203 | ||
|
|
9edbc15828 | ||
|
|
dadc7aaf08 | ||
|
|
b96807d34c | ||
|
|
45b736bb01 | ||
|
|
3d873a79a0 | ||
|
|
6869c582ff | ||
|
|
9b9e5e939c | ||
|
|
f626c15ecc | ||
|
|
8df1fe2e60 | ||
|
|
fd2a533057 | ||
|
|
0a6401f990 | ||
|
|
1326fcb345 | ||
|
|
8b8e534598 | ||
|
|
0b518a3b76 |
@@ -106,7 +106,8 @@ class StartMariadb
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo '{$database->name} started.'";
|
||||
$database_name = addslashes($database->name);
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,8 @@ class StartMongodb
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo '{$database->name} started.'";
|
||||
$database_name = addslashes($database->name);
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,8 @@ class StartMysql
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo '{$database->name} started.'";
|
||||
$database_name = addslashes($database->name);
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
return remote_process($this->commands, $database->destination->server,callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,8 @@ class StartPostgresql
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo '{$database->name} started.'";
|
||||
$database_name = addslashes($database->name);
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,8 @@ class StartRedis
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo '{$database->name} started.'";
|
||||
$database_name = addslashes($database->name);
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
|
||||
@@ -13,11 +13,15 @@ class StartService
|
||||
{
|
||||
ray('Starting service: ' . $service->name);
|
||||
$service->saveComposeConfigs();
|
||||
|
||||
$service_name = addslashes($service->name);
|
||||
$server_name = addslashes($service->server->name);
|
||||
|
||||
$commands[] = "cd " . $service->workdir();
|
||||
$commands[] = "echo 'Saved configuration files to {$service->workdir()}.'";
|
||||
$commands[] = "echo 'Creating Docker network.'";
|
||||
$commands[] = "docker network inspect $service->uuid >/dev/null 2>&1 || docker network create --attachable $service->uuid >/dev/null 2>&1 || true";
|
||||
$commands[] = "echo 'Starting service $service->name on {$service->server->name}.'";
|
||||
$commands[] = "echo Starting service.";
|
||||
$commands[] = "echo 'Pulling images.'";
|
||||
$commands[] = "docker compose pull";
|
||||
$commands[] = "echo 'Starting containers.'";
|
||||
|
||||
@@ -73,8 +73,8 @@ class Deploy extends Controller
|
||||
$message->push("Tag {$tag} not found.");
|
||||
continue;
|
||||
}
|
||||
$applications = $found_tag->applications();
|
||||
$services = $found_tag->services();
|
||||
$applications = $found_tag->applications()->get();
|
||||
$services = $found_tag->services()->get();
|
||||
if ($applications->count() === 0 && $services->count() === 0) {
|
||||
$message->push("No resources found for tag {$tag}.");
|
||||
continue;
|
||||
@@ -97,7 +97,10 @@ class Deploy extends Controller
|
||||
public function deploy_resource($resource, bool $force = false): Collection
|
||||
{
|
||||
$message = collect([]);
|
||||
$type = $resource->getMorphClass();
|
||||
if (gettype($resource) !== 'object') {
|
||||
return $message->push("Resource ($resource) not found.");
|
||||
}
|
||||
$type = $resource?->getMorphClass();
|
||||
if ($type === 'App\Models\Application') {
|
||||
queue_application_deployment(
|
||||
application: $resource,
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -28,9 +30,8 @@ class Help extends Component
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->rateLimit(3, 60);
|
||||
$this->rateLimit(3, 30);
|
||||
$this->validate();
|
||||
$subscriptionType = auth()->user()?->subscription?->type() ?? 'Free';
|
||||
$debug = "Route: {$this->path}";
|
||||
$mail = new MailMessage();
|
||||
$mail->view(
|
||||
@@ -40,9 +41,21 @@ class Help extends Component
|
||||
'debug' => $debug
|
||||
]
|
||||
);
|
||||
$mail->subject("[HELP - {$subscriptionType}]: {$this->subject}");
|
||||
send_user_an_email($mail, auth()->user()?->email, 'hi@coollabs.io');
|
||||
$this->dispatch('success', 'Your message has been sent successfully. <br>We will get in touch with you as soon as possible.');
|
||||
$mail->subject("[HELP]: {$this->subject}");
|
||||
$settings = InstanceSettings::get();
|
||||
$type = set_transanctional_email_settings($settings);
|
||||
if (!$type) {
|
||||
$url = "https://app.coolify.io/api/feedback";
|
||||
if (isDev()) {
|
||||
$url = "http://localhost:80/api/feedback";
|
||||
}
|
||||
Http::post($url, [
|
||||
'content' => "User: `" . auth()->user()?->email . "` with subject: `" . $this->subject . "` has the following problem: `" . $this->description . "`"
|
||||
]);
|
||||
} else {
|
||||
send_user_an_email($mail, auth()->user()?->email, 'hi@coollabs.io');
|
||||
}
|
||||
$this->dispatch('success', 'Feedback sent.', 'We will get in touch with you as soon as possible.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ class Index extends Component
|
||||
}
|
||||
$this->project = $project;
|
||||
$this->environment = $environment;
|
||||
$this->applications = $environment->applications->load(['tags']);
|
||||
|
||||
$this->applications = $this->environment->applications->load(['tags']);
|
||||
$this->applications = $this->applications->map(function ($application) {
|
||||
if (data_get($application, 'environment.project.uuid')) {
|
||||
$application->hrefLink = route('project.application.configuration', [
|
||||
@@ -40,8 +41,7 @@ class Index extends Component
|
||||
}
|
||||
return $application;
|
||||
});
|
||||
ray($this->applications);
|
||||
$this->postgresqls = $environment->postgresqls->load(['tags'])->sortBy('name');
|
||||
$this->postgresqls = $this->environment->postgresqls->load(['tags'])->sortBy('name');
|
||||
$this->postgresqls = $this->postgresqls->map(function ($postgresql) {
|
||||
if (data_get($postgresql, 'environment.project.uuid')) {
|
||||
$postgresql->hrefLink = route('project.database.configuration', [
|
||||
@@ -52,7 +52,7 @@ class Index extends Component
|
||||
}
|
||||
return $postgresql;
|
||||
});
|
||||
$this->redis = $environment->redis->load(['tags'])->sortBy('name');
|
||||
$this->redis = $this->environment->redis->load(['tags'])->sortBy('name');
|
||||
$this->redis = $this->redis->map(function ($redis) {
|
||||
if (data_get($redis, 'environment.project.uuid')) {
|
||||
$redis->hrefLink = route('project.database.configuration', [
|
||||
@@ -63,7 +63,7 @@ class Index extends Component
|
||||
}
|
||||
return $redis;
|
||||
});
|
||||
$this->mongodbs = $environment->mongodbs->load(['tags'])->sortBy('name');
|
||||
$this->mongodbs = $this->environment->mongodbs->load(['tags'])->sortBy('name');
|
||||
$this->mongodbs = $this->mongodbs->map(function ($mongodb) {
|
||||
if (data_get($mongodb, 'environment.project.uuid')) {
|
||||
$mongodb->hrefLink = route('project.database.configuration', [
|
||||
@@ -74,7 +74,7 @@ class Index extends Component
|
||||
}
|
||||
return $mongodb;
|
||||
});
|
||||
$this->mysqls = $environment->mysqls->load(['tags'])->sortBy('name');
|
||||
$this->mysqls = $this->environment->mysqls->load(['tags'])->sortBy('name');
|
||||
$this->mysqls = $this->mysqls->map(function ($mysql) {
|
||||
if (data_get($mysql, 'environment.project.uuid')) {
|
||||
$mysql->hrefLink = route('project.database.configuration', [
|
||||
@@ -85,7 +85,7 @@ class Index extends Component
|
||||
}
|
||||
return $mysql;
|
||||
});
|
||||
$this->mariadbs = $environment->mariadbs->load(['tags'])->sortBy('name');
|
||||
$this->mariadbs = $this->environment->mariadbs->load(['tags'])->sortBy('name');
|
||||
$this->mariadbs = $this->mariadbs->map(function ($mariadb) {
|
||||
if (data_get($mariadb, 'environment.project.uuid')) {
|
||||
$mariadb->hrefLink = route('project.database.configuration', [
|
||||
@@ -96,7 +96,7 @@ class Index extends Component
|
||||
}
|
||||
return $mariadb;
|
||||
});
|
||||
$this->services = $environment->services->load(['tags'])->sortBy('name');
|
||||
$this->services = $this->environment->services->load(['tags'])->sortBy('name');
|
||||
$this->services = $this->services->map(function ($service) {
|
||||
if (data_get($service, 'environment.project.uuid')) {
|
||||
$service->hrefLink = route('project.service.configuration', [
|
||||
|
||||
@@ -50,13 +50,14 @@ class Show extends Component
|
||||
public function redeploy_all()
|
||||
{
|
||||
try {
|
||||
$this->applications->each(function ($resource) {
|
||||
$message = collect([]);
|
||||
$this->applications->each(function ($resource) use ($message) {
|
||||
$deploy = new Deploy();
|
||||
$deploy->deploy_resource($resource);
|
||||
$message->push($deploy->deploy_resource($resource));
|
||||
});
|
||||
$this->services->each(function ($resource) {
|
||||
$this->services->each(function ($resource) use ($message) {
|
||||
$deploy = new Deploy();
|
||||
$deploy->deploy_resource($resource);
|
||||
$message->push($deploy->deploy_resource($resource));
|
||||
});
|
||||
$this->dispatch('success', 'Mass deployment started.');
|
||||
} catch (\Exception $e) {
|
||||
|
||||
@@ -13,6 +13,8 @@ class Environment extends Model
|
||||
return $this->applications()->count() == 0 &&
|
||||
$this->redis()->count() == 0 &&
|
||||
$this->postgresqls()->count() == 0 &&
|
||||
$this->mysqls()->count() == 0 &&
|
||||
$this->mariadbs()->count() == 0 &&
|
||||
$this->mongodbs()->count() == 0 &&
|
||||
$this->services()->count() == 0;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class StandaloneMariadb extends BaseModel
|
||||
{
|
||||
use HasFactory,SoftDeletes;
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $guarded = [];
|
||||
protected $casts = [
|
||||
|
||||
@@ -104,7 +104,7 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n
|
||||
ray($error);
|
||||
if ($error instanceof TooManyRequestsException) {
|
||||
if (isset($livewire)) {
|
||||
return $livewire->dispatch('error', "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.");
|
||||
return $livewire->dispatch('error', "Too many requests.","Please try again in {$error->secondsUntilAvailable} seconds.");
|
||||
}
|
||||
return "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.";
|
||||
}
|
||||
@@ -298,10 +298,8 @@ function validate_cron_expression($expression_to_validate): bool
|
||||
function send_internal_notification(string $message): void
|
||||
{
|
||||
try {
|
||||
$baseUrl = config('app.name');
|
||||
$team = Team::find(0);
|
||||
$team?->notify(new GeneralNotification("👀 {$baseUrl}: " . $message));
|
||||
ray("👀 {$baseUrl}: " . $message);
|
||||
$team?->notify(new GeneralNotification($message));
|
||||
} catch (\Throwable $e) {
|
||||
ray($e->getMessage());
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
return [
|
||||
'docs' => 'https://coolify.io/docs/',
|
||||
'contact' => 'https://coolify.io/docs/contact',
|
||||
'feedback_discord_webhook' => env('FEEDBACK_DISCORD_WEBHOOK'),
|
||||
'self_hosted' => env('SELF_HOSTED', true),
|
||||
'waitlist' => env('WAITLIST', false),
|
||||
'license_url' => 'https://licenses.coollabs.io',
|
||||
|
||||
@@ -7,7 +7,7 @@ return [
|
||||
|
||||
// The release version of your application
|
||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||
'release' => '4.0.0-beta.207',
|
||||
'release' => '4.0.0-beta.211',
|
||||
// When left empty or `null` the Laravel environment will be used
|
||||
'environment' => config('app.env'),
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<?php
|
||||
|
||||
return '4.0.0-beta.207';
|
||||
return '4.0.0-beta.211';
|
||||
|
||||
@@ -46,6 +46,7 @@ services:
|
||||
- PUSHER_APP_SECRET
|
||||
- AUTOUPDATE
|
||||
- SELF_HOSTED
|
||||
- FEEDBACK_DISCORD_WEBHOOK
|
||||
- WAITLIST
|
||||
- SUBSCRIPTION_PROVIDER
|
||||
- STRIPE_API_KEY
|
||||
|
||||
@@ -26,11 +26,10 @@
|
||||
</li>
|
||||
<li title="Send us feedback or get help!" class="fixed top-0 right-0 p-2 px-4 pt-4 mt-auto text-xs">
|
||||
<div class="justify-center" wire:click="help" onclick="help.showModal()">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg class="icon" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="M22 5.5H9c-1.1 0-2 .9-2 2v9a2 2 0 0 0 2 2h13c1.11 0 2-.89 2-2v-9a2 2 0 0 0-2-2m0 11H9V9.17l6.5 3.33L22 9.17v7.33m-6.5-5.69L9 7.5h13l-6.5 3.31M5 16.5c0 .17.03.33.05.5H1c-.552 0-1-.45-1-1s.448-1 1-1h4v1.5M3 7h2.05c-.02.17-.05.33-.05.5V9H3c-.55 0-1-.45-1-1s.45-1 1-1m-2 5c0-.55.45-1 1-1h3v2H2c-.55 0-1-.45-1-1Z" />
|
||||
d="M144 180a16 16 0 1 1-16-16a16 16 0 0 1 16 16m92-52A108 108 0 1 1 128 20a108.12 108.12 0 0 1 108 108m-24 0a84 84 0 1 0-84 84a84.09 84.09 0 0 0 84-84m-84-64c-24.26 0-44 17.94-44 40v4a12 12 0 0 0 24 0v-4c0-8.82 9-16 20-16s20 7.18 20 16s-9 16-20 16a12 12 0 0 0-12 12v8a12 12 0 0 0 23.73 2.56C158.31 137.88 172 122.37 172 104c0-22.06-19.74-40-44-40" />
|
||||
</svg>
|
||||
Feedback
|
||||
</div>
|
||||
</li>
|
||||
<li class="pb-6" title="Logout">
|
||||
|
||||
@@ -142,13 +142,12 @@
|
||||
</li>
|
||||
@endif
|
||||
@if (isSubscriptionActive() || isDev())
|
||||
<li title="Send us feedback or get help!" class="fixed top-0 right-0 p-2 px-4 pt-4 mt-auto text-xs">
|
||||
<li title="Send us feedback or get help!" class="hover:bg-transparent">
|
||||
<div class="justify-center" wire:click="help" onclick="help.showModal()">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg class="icon" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="M22 5.5H9c-1.1 0-2 .9-2 2v9a2 2 0 0 0 2 2h13c1.11 0 2-.89 2-2v-9a2 2 0 0 0-2-2m0 11H9V9.17l6.5 3.33L22 9.17v7.33m-6.5-5.69L9 7.5h13l-6.5 3.31M5 16.5c0 .17.03.33.05.5H1c-.552 0-1-.45-1-1s.448-1 1-1h4v1.5M3 7h2.05c-.02.17-.05.33-.05.5V9H3c-.55 0-1-.45-1-1s.45-1 1-1m-2 5c0-.55.45-1 1-1h3v2H2c-.55 0-1-.45-1-1Z" />
|
||||
d="M144 180a16 16 0 1 1-16-16a16 16 0 0 1 16 16m92-52A108 108 0 1 1 128 20a108.12 108.12 0 0 1 108 108m-24 0a84 84 0 1 0-84 84a84.09 84.09 0 0 0 84-84m-84-64c-24.26 0-44 17.94-44 40v4a12 12 0 0 0 24 0v-4c0-8.82 9-16 20-16s20 7.18 20 16s-9 16-20 16a12 12 0 0 0-12 12v8a12 12 0 0 0 23.73 2.56C158.31 137.88 172 122.37 172 104c0-22.06-19.74-40-44-40" />
|
||||
</svg>
|
||||
Feedback
|
||||
</div>
|
||||
</li>
|
||||
@endif
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
@if (isSubscriptionActive() || isDev())
|
||||
<div title="Send us feedback or get help!" class="fixed top-0 right-0 p-2 px-4 pt-4 mt-auto text-xs">
|
||||
<button class="flex items-center justify-center gap-2" wire:click="help" onclick="help.showModal()">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg class="icon" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor"
|
||||
d="M22 5.5H9c-1.1 0-2 .9-2 2v9a2 2 0 0 0 2 2h13c1.11 0 2-.89 2-2v-9a2 2 0 0 0-2-2m0 11H9V9.17l6.5 3.33L22 9.17v7.33m-6.5-5.69L9 7.5h13l-6.5 3.31M5 16.5c0 .17.03.33.05.5H1c-.552 0-1-.45-1-1s.448-1 1-1h4v1.5M3 7h2.05c-.02.17-.05.33-.05.5V9H3c-.55 0-1-.45-1-1s.45-1 1-1m-2 5c0-.55.45-1 1-1h3v2H2c-.55 0-1-.45-1-1Z" />
|
||||
d="M144 180a16 16 0 1 1-16-16a16 16 0 0 1 16 16m92-52A108 108 0 1 1 128 20a108.12 108.12 0 0 1 108 108m-24 0a84 84 0 1 0-84 84a84.09 84.09 0 0 0 84-84m-84-64c-24.26 0-44 17.94-44 40v4a12 12 0 0 0 24 0v-4c0-8.82 9-16 20-16s20 7.18 20 16s-9 16-20 16a12 12 0 0 0-12 12v8a12 12 0 0 0 23.73 2.56C158.31 137.88 172 122.37 172 104c0-22.06-19.74-40-44-40" />
|
||||
</svg>
|
||||
Feedback
|
||||
</button>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
<x-forms.textarea rows="10" id="description" label="Description"
|
||||
placeholder="Please provide as much information as possible."></x-forms.textarea>
|
||||
<div></div>
|
||||
<x-forms.button class="w-full mt-4" type="submit" onclick="help.close()">Send Email</x-forms.button>
|
||||
<x-forms.button class="w-full mt-4" type="submit" onclick="help.close()">Send</x-forms.button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@ use App\Models\Tag;
|
||||
use App\Models\User;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
@@ -34,6 +35,16 @@ if (isDev()) {
|
||||
Route::get('/health', function () {
|
||||
return 'OK';
|
||||
});
|
||||
Route::post('/feedback', function (Request $request) {
|
||||
$content = $request->input('content');
|
||||
$webhook_url = config('coolify.feedback_discord_webhook');
|
||||
if ($webhook_url) {
|
||||
Http::post($webhook_url, [
|
||||
'content' => $content
|
||||
]);
|
||||
}
|
||||
return response()->json(['message' => 'Feedback sent.'], 200);
|
||||
});
|
||||
// Route::group([
|
||||
// 'middleware' => $middlewares,
|
||||
// 'prefix' => 'v1'
|
||||
@@ -53,6 +64,8 @@ Route::group([
|
||||
'prefix' => 'v1'
|
||||
], function () {
|
||||
Route::get('/deploy', [Deploy::class, 'deploy']);
|
||||
|
||||
|
||||
});
|
||||
|
||||
Route::middleware(['throttle:5'])->group(function () {
|
||||
|
||||
@@ -764,7 +764,6 @@ Route::post('/payments/stripe/events', function () {
|
||||
]);
|
||||
$type = data_get($event, 'type');
|
||||
$data = data_get($event, 'data.object');
|
||||
ray('Event: ' . $type);
|
||||
switch ($type) {
|
||||
case 'checkout.session.completed':
|
||||
$clientReferenceId = data_get($data, 'client_reference_id');
|
||||
@@ -779,7 +778,8 @@ Route::post('/payments/stripe/events', function () {
|
||||
$team = Team::find($teamId);
|
||||
$found = $team->members->where('id', $userId)->first();
|
||||
if (!$found->isAdmin()) {
|
||||
throw new Exception("User {$userId} is not an admin or owner of team {$team->id}.");
|
||||
send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
|
||||
throw new Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
|
||||
}
|
||||
$subscription = Subscription::where('team_id', $teamId)->first();
|
||||
if ($subscription) {
|
||||
@@ -819,25 +819,35 @@ Route::post('/payments/stripe/events', function () {
|
||||
break;
|
||||
case 'invoice.payment_failed':
|
||||
$customerId = data_get($data, 'customer');
|
||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||
if (!$subscription) {
|
||||
send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: ' . $customerId);
|
||||
return response('No subscription found in Coolify.');
|
||||
}
|
||||
$team = data_get($subscription, 'team');
|
||||
if (!$team) {
|
||||
throw new Exception('No team found for subscription: ' . $subscription->id);
|
||||
send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: ' . $customerId);
|
||||
return response('No team found in Coolify.');
|
||||
}
|
||||
if (!$subscription->stripe_invoice_paid) {
|
||||
SubscriptionInvoiceFailedJob::dispatch($team);
|
||||
send_internal_notification('Invoice payment failed: ' . $subscription->team->id);
|
||||
send_internal_notification('Invoice payment failed: ' . $customerId);
|
||||
} else {
|
||||
send_internal_notification('Invoice payment failed but already paid: ' . $subscription->team->id);
|
||||
send_internal_notification('Invoice payment failed but already paid: ' . $customerId);
|
||||
}
|
||||
break;
|
||||
case 'payment_intent.payment_failed':
|
||||
$customerId = data_get($data, 'customer');
|
||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||
$subscription->update([
|
||||
'stripe_invoice_paid' => false,
|
||||
]);
|
||||
send_internal_notification('Subscription payment failed: ' . $subscription->team->id);
|
||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||
if (!$subscription) {
|
||||
send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: ' . $customerId);
|
||||
return response('No subscription found in Coolify.');
|
||||
}
|
||||
if ($subscription->stripe_invoice_paid) {
|
||||
send_internal_notification('payment_intent.payment_failed but invoice is active for customer: ' . $customerId);
|
||||
return;
|
||||
}
|
||||
send_internal_notification('Subscription payment failed for customer: ' . $customerId);
|
||||
break;
|
||||
case 'customer.subscription.updated':
|
||||
$customerId = data_get($data, 'customer');
|
||||
@@ -868,7 +878,7 @@ Route::post('/payments/stripe/events', function () {
|
||||
$subscription->update([
|
||||
'stripe_invoice_paid' => false,
|
||||
]);
|
||||
send_internal_notification('Subscription paused or incomplete for team: ' . $subscription->team->id);
|
||||
send_internal_notification('Subscription paused or incomplete for customer: ' . $customerId);
|
||||
}
|
||||
|
||||
// Trial ended but subscribed, reactive servers
|
||||
@@ -878,7 +888,7 @@ Route::post('/payments/stripe/events', function () {
|
||||
}
|
||||
|
||||
if ($feedback) {
|
||||
$reason = "Cancellation feedback for {$subscription->team->id}: '" . $feedback . "'";
|
||||
$reason = "Cancellation feedback for {$customerId}: '" . $feedback . "'";
|
||||
if ($comment) {
|
||||
$reason .= ' with comment: \'' . $comment . "'";
|
||||
}
|
||||
@@ -888,7 +898,7 @@ Route::post('/payments/stripe/events', function () {
|
||||
if ($cancelAtPeriodEnd) {
|
||||
// send_internal_notification('Subscription cancelled at period end for team: ' . $subscription->team->id);
|
||||
} else {
|
||||
send_internal_notification('Subscription resumed for team: ' . $subscription->team->id);
|
||||
send_internal_notification('customer.subscription.updated for customer: ' . $customerId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -905,9 +915,10 @@ Route::post('/payments/stripe/events', function () {
|
||||
'stripe_invoice_paid' => false,
|
||||
'stripe_trial_already_ended' => true,
|
||||
]);
|
||||
// send_internal_notification('Subscription cancelled: ' . $subscription->team->id);
|
||||
send_internal_notification('customer.subscription.deleted for customer: ' . $customerId);
|
||||
break;
|
||||
case 'customer.subscription.trial_will_end':
|
||||
// Not used for now
|
||||
$customerId = data_get($data, 'customer');
|
||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||
$team = data_get($subscription, 'team');
|
||||
@@ -929,7 +940,7 @@ Route::post('/payments/stripe/events', function () {
|
||||
'stripe_invoice_paid' => false,
|
||||
]);
|
||||
SubscriptionTrialEndedJob::dispatch($team);
|
||||
send_internal_notification('Subscription paused for team: ' . $subscription->team->id);
|
||||
send_internal_notification('Subscription paused for customer: ' . $customerId);
|
||||
break;
|
||||
default:
|
||||
// Unhandled event type
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"version": "3.12.36"
|
||||
},
|
||||
"v4": {
|
||||
"version": "4.0.0-beta.207"
|
||||
"version": "4.0.0-beta.211"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user