commit
aba86dffd7
@ -1,15 +1,15 @@
|
||||
name: Coolify Builder (v4)
|
||||
name: Coolify Helper Image (v4)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main", "v4"]
|
||||
branches: [ "main", "next" ]
|
||||
paths:
|
||||
- .github/workflows/coolify-builder.yml
|
||||
- docker/coolify-builder/Dockerfile
|
||||
- .github/workflows/coolify-helper.yml
|
||||
- docker/coolify-helper/Dockerfile
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: "coollabsio/coolify-builder"
|
||||
IMAGE_NAME: "coollabsio/coolify-helper"
|
||||
|
||||
jobs:
|
||||
amd64:
|
||||
@ -30,12 +30,12 @@ jobs:
|
||||
with:
|
||||
no-cache: true
|
||||
context: .
|
||||
file: docker/coolify-builder/Dockerfile
|
||||
file: docker/coolify-helper/Dockerfile
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
aarch64:
|
||||
runs-on: [self-hosted, arm64]
|
||||
runs-on: [ self-hosted, arm64 ]
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
@ -52,7 +52,7 @@ jobs:
|
||||
with:
|
||||
no-cache: true
|
||||
context: .
|
||||
file: docker/coolify-builder/Dockerfile
|
||||
file: docker/coolify-helper/Dockerfile
|
||||
platforms: linux/aarch64
|
||||
push: true
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:aarch64
|
||||
@ -61,7 +61,7 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
needs: [amd64, aarch64]
|
||||
needs: [ amd64, aarch64 ]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
@ -15,6 +15,7 @@ class PrepareCoolifyTask
|
||||
{
|
||||
protected Activity $activity;
|
||||
protected CoolifyTaskArgs $remoteProcessArgs;
|
||||
|
||||
public function __construct(CoolifyTaskArgs $remoteProcessArgs)
|
||||
{
|
||||
$this->remoteProcessArgs = $remoteProcessArgs;
|
||||
|
@ -49,6 +49,28 @@ public function __construct(Activity $activity, bool $hide_from_output = false,
|
||||
$this->ignore_errors = $ignore_errors;
|
||||
}
|
||||
|
||||
public static function decodeOutput(?Activity $activity = null): string
|
||||
{
|
||||
if (is_null($activity)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
$decoded = json_decode(
|
||||
data_get($activity, 'description'),
|
||||
associative: true,
|
||||
flags: JSON_THROW_ON_ERROR
|
||||
);
|
||||
} catch (\JsonException $exception) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return collect($decoded)
|
||||
->sortBy(fn ($i) => $i['order'])
|
||||
->map(fn ($i) => $i['output'])
|
||||
->implode("");
|
||||
}
|
||||
|
||||
public function __invoke(): ProcessResult
|
||||
{
|
||||
$this->time_start = hrtime(true);
|
||||
@ -83,15 +105,6 @@ public function __invoke(): ProcessResult
|
||||
return $processResult;
|
||||
}
|
||||
|
||||
protected function getLatestCounter(): int
|
||||
{
|
||||
$description = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR);
|
||||
if ($description === null || count($description) === 0) {
|
||||
return 1;
|
||||
}
|
||||
return end($description)['order'] + 1;
|
||||
}
|
||||
|
||||
protected function getCommand(): string
|
||||
{
|
||||
$user = $this->activity->getExtraProperty('user');
|
||||
@ -120,6 +133,13 @@ protected function handleOutput(string $type, string $output)
|
||||
}
|
||||
}
|
||||
|
||||
protected function elapsedTime(): int
|
||||
{
|
||||
$timeMs = (hrtime(true) - $this->time_start) / 1_000_000;
|
||||
|
||||
return intval($timeMs);
|
||||
}
|
||||
|
||||
public function encodeOutput($type, $output)
|
||||
{
|
||||
$outputStack = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR);
|
||||
@ -135,26 +155,13 @@ public function encodeOutput($type, $output)
|
||||
return json_encode($outputStack, flags: JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
public static function decodeOutput(?Activity $activity = null): string
|
||||
protected function getLatestCounter(): int
|
||||
{
|
||||
if (is_null($activity)) {
|
||||
return '';
|
||||
$description = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR);
|
||||
if ($description === null || count($description) === 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
$decoded = json_decode(
|
||||
data_get($activity, 'description'),
|
||||
associative: true,
|
||||
flags: JSON_THROW_ON_ERROR
|
||||
);
|
||||
} catch (\JsonException $exception) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return collect($decoded)
|
||||
->sortBy(fn ($i) => $i['order'])
|
||||
->map(fn ($i) => $i['output'])
|
||||
->implode("");
|
||||
return end($description)['order'] + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,11 +178,4 @@ protected function isAfterLastThrottle()
|
||||
|
||||
return ($this->current_time - $this->throttle_interval_ms) > $this->last_write_at;
|
||||
}
|
||||
|
||||
protected function elapsedTime(): int
|
||||
{
|
||||
$timeMs = (hrtime(true) - $this->time_start) / 1_000_000;
|
||||
|
||||
return intval($timeMs);
|
||||
}
|
||||
}
|
||||
|
164
app/Actions/Database/StartPostgresql.php
Normal file
164
app/Actions/Database/StartPostgresql.php
Normal file
@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Database;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\StandalonePostgresql;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class StartPostgresql
|
||||
{
|
||||
public StandalonePostgresql $database;
|
||||
public array $commands = [];
|
||||
public array $init_scripts = [];
|
||||
public string $configuration_dir;
|
||||
|
||||
public function __invoke(Server $server, StandalonePostgresql $database)
|
||||
{
|
||||
$this->database = $database;
|
||||
$container_name = generate_container_name($this->database->uuid);
|
||||
$this->configuration_dir = database_configuration_dir() . '/' . $container_name;
|
||||
|
||||
$this->commands = [
|
||||
"mkdir -p $this->configuration_dir",
|
||||
"mkdir -p $this->configuration_dir/docker-entrypoint-initdb.d/"
|
||||
];
|
||||
|
||||
$persistent_storages = $this->generate_local_persistent_volumes();
|
||||
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
|
||||
$environment_variables = $this->generate_environment_variables();
|
||||
$this->generate_init_scripts();
|
||||
$docker_compose = [
|
||||
'version' => '3.8',
|
||||
'services' => [
|
||||
$container_name => [
|
||||
'image' => $this->database->image,
|
||||
'container_name' => $container_name,
|
||||
'environment' => $environment_variables,
|
||||
'restart' => 'always',
|
||||
'networks' => [
|
||||
$this->database->destination->network,
|
||||
],
|
||||
'healthcheck' => [
|
||||
'test' => [
|
||||
'CMD-SHELL',
|
||||
'pg_isready',
|
||||
'-d',
|
||||
$this->database->postgres_db,
|
||||
'-U',
|
||||
$this->database->postgres_user,
|
||||
],
|
||||
'interval' => '5s',
|
||||
'timeout' => '5s',
|
||||
'retries' => 10,
|
||||
'start_period' => '5s'
|
||||
],
|
||||
'mem_limit' => $this->database->limits_memory,
|
||||
'memswap_limit' => $this->database->limits_memory_swap,
|
||||
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
||||
'mem_reservation' => $this->database->limits_memory_reservation,
|
||||
'cpus' => $this->database->limits_cpus,
|
||||
'cpuset' => $this->database->limits_cpuset,
|
||||
'cpu_shares' => $this->database->limits_cpu_shares,
|
||||
]
|
||||
],
|
||||
'networks' => [
|
||||
$this->database->destination->network => [
|
||||
'external' => false,
|
||||
'name' => $this->database->destination->network,
|
||||
'attachable' => true,
|
||||
]
|
||||
]
|
||||
];
|
||||
if (count($this->database->ports_mappings_array) > 0) {
|
||||
$docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
|
||||
}
|
||||
if (count($persistent_storages) > 0) {
|
||||
$docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
|
||||
}
|
||||
if (count($volume_names) > 0) {
|
||||
$docker_compose['volumes'] = $volume_names;
|
||||
}
|
||||
if (count($this->init_scripts) > 0) {
|
||||
foreach ($this->init_scripts as $init_script) {
|
||||
$docker_compose['services'][$container_name]['volumes'][] = [
|
||||
'type' => 'bind',
|
||||
'source' => $init_script,
|
||||
'target' => '/docker-entrypoint-initdb.d/' . basename($init_script),
|
||||
'read_only' => true,
|
||||
];
|
||||
}
|
||||
}
|
||||
$docker_compose = Yaml::dump($docker_compose, 10);
|
||||
$docker_compose_base64 = base64_encode($docker_compose);
|
||||
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d > $this->configuration_dir/docker-compose.yml";
|
||||
$readme = generate_readme_file($this->database->name, now());
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
return remote_process($this->commands, $server);
|
||||
}
|
||||
|
||||
private function generate_local_persistent_volumes()
|
||||
{
|
||||
$local_persistent_volumes = [];
|
||||
foreach ($this->database->persistentStorages as $persistentStorage) {
|
||||
$volume_name = $persistentStorage->host_path ?? $persistentStorage->name;
|
||||
$local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
|
||||
}
|
||||
return $local_persistent_volumes;
|
||||
}
|
||||
|
||||
private function generate_local_persistent_volumes_only_volume_names()
|
||||
{
|
||||
$local_persistent_volumes_names = [];
|
||||
foreach ($this->database->persistentStorages as $persistentStorage) {
|
||||
if ($persistentStorage->host_path) {
|
||||
continue;
|
||||
}
|
||||
$name = $persistentStorage->name;
|
||||
$local_persistent_volumes_names[$name] = [
|
||||
'name' => $name,
|
||||
'external' => false,
|
||||
];
|
||||
}
|
||||
return $local_persistent_volumes_names;
|
||||
}
|
||||
|
||||
private function generate_environment_variables()
|
||||
{
|
||||
$environment_variables = collect();
|
||||
ray('Generate Environment Variables')->green();
|
||||
ray($this->database->runtime_environment_variables)->green();
|
||||
foreach ($this->database->runtime_environment_variables as $env) {
|
||||
$environment_variables->push("$env->key=$env->value");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_USER'))->isEmpty()) {
|
||||
$environment_variables->push("POSTGRES_USER={$this->database->postgres_user}");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_PASSWORD'))->isEmpty()) {
|
||||
$environment_variables->push("POSTGRES_PASSWORD={$this->database->postgres_password}");
|
||||
}
|
||||
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_DB'))->isEmpty()) {
|
||||
$environment_variables->push("POSTGRES_DB={$this->database->postgres_db}");
|
||||
}
|
||||
return $environment_variables->all();
|
||||
}
|
||||
|
||||
private function generate_init_scripts()
|
||||
{
|
||||
if (is_null($this->database->init_scripts) || count($this->database->init_scripts) === 0) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->database->init_scripts as $init_script) {
|
||||
$filename = data_get($init_script, 'filename');
|
||||
$content = data_get($init_script, 'content');
|
||||
$content_base64 = base64_encode($content);
|
||||
$this->commands[] = "echo '{$content_base64}' | base64 -d > $this->configuration_dir/docker-entrypoint-initdb.d/{$filename}";
|
||||
$this->init_scripts[] = "$this->configuration_dir/docker-entrypoint-initdb.d/{$filename}";
|
||||
}
|
||||
}
|
||||
}
|
@ -3,11 +3,8 @@
|
||||
namespace App\Actions\Fortify;
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Laravel\Fortify\Contracts\CreatesNewUsers;
|
||||
@ -19,13 +16,12 @@ class CreateNewUser implements CreatesNewUsers
|
||||
/**
|
||||
* Validate and create a newly registered user.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
* @param array<string, string> $input
|
||||
*/
|
||||
public function create(array $input): User
|
||||
{
|
||||
$settings = InstanceSettings::get();
|
||||
if (!$settings->is_registration_enabled) {
|
||||
Log::info('Registration is disabled');
|
||||
abort(403);
|
||||
}
|
||||
Validator::make($input, [
|
||||
|
@ -14,7 +14,7 @@ class ResetUserPassword implements ResetsUserPasswords
|
||||
/**
|
||||
* Validate and reset the user's forgotten password.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
* @param array<string, string> $input
|
||||
*/
|
||||
public function reset(User $user, array $input): void
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ class UpdateUserPassword implements UpdatesUserPasswords
|
||||
/**
|
||||
* Validate and update the user's password.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
* @param array<string, string> $input
|
||||
*/
|
||||
public function update(User $user, array $input): void
|
||||
{
|
||||
|
@ -13,7 +13,7 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
|
||||
/**
|
||||
* Validate and update the given user's profile information.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
* @param array<string, string> $input
|
||||
*/
|
||||
public function update(User $user, array $input): void
|
||||
{
|
||||
@ -29,8 +29,10 @@ public function update(User $user, array $input): void
|
||||
],
|
||||
])->validateWithBag('updateProfileInformation');
|
||||
|
||||
if ($input['email'] !== $user->email &&
|
||||
$user instanceof MustVerifyEmail) {
|
||||
if (
|
||||
$input['email'] !== $user->email &&
|
||||
$user instanceof MustVerifyEmail
|
||||
) {
|
||||
$this->updateVerifiedUser($user, $input);
|
||||
} else {
|
||||
$user->forceFill([
|
||||
@ -43,7 +45,7 @@ public function update(User $user, array $input): void
|
||||
/**
|
||||
* Update the given verified user's profile information.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
* @param array<string, string> $input
|
||||
*/
|
||||
protected function updateVerifiedUser(User $user, array $input): void
|
||||
{
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class CheckResaleLicense
|
||||
{
|
||||
@ -12,41 +11,52 @@ public function __invoke()
|
||||
{
|
||||
try {
|
||||
$settings = InstanceSettings::get();
|
||||
$instance_id = config('app.id');
|
||||
$settings->update([
|
||||
'is_resale_license_active' => false,
|
||||
]);
|
||||
if (is_dev()) {
|
||||
return;
|
||||
}
|
||||
if (!$settings->resale_license) {
|
||||
return;
|
||||
}
|
||||
ray('Checking license key');
|
||||
$base_url = config('coolify.license_url');
|
||||
if (is_dev()) {
|
||||
$base_url = 'http://host.docker.internal:8787';
|
||||
}
|
||||
$instance_id = config('app.id');
|
||||
|
||||
ray("Checking license key against $base_url/lemon/validate");
|
||||
$data = Http::withHeaders([
|
||||
'Accept' => 'application/json',
|
||||
])->post('https://api.lemonsqueezy.com/v1/licenses/validate', [
|
||||
])->get("$base_url/lemon/validate", [
|
||||
'license_key' => $settings->resale_license,
|
||||
'instance_name' => $instance_id,
|
||||
])->throw()->json();
|
||||
$product_id = (int)data_get($data, 'meta.product_id');
|
||||
$valid_product_id = (int)config('coolify.lemon_squeezy_product_id');
|
||||
if ($product_id !== $valid_product_id) {
|
||||
throw new \Exception('Invalid product id');
|
||||
}
|
||||
ray('Valid Product Id');
|
||||
|
||||
['valid' => $valid, 'license_key' => $license_key] = $data;
|
||||
|
||||
if ($valid) {
|
||||
if (data_get($license_key, 'status') === 'inactive') {
|
||||
Http::withHeaders([
|
||||
'Accept' => 'application/json',
|
||||
])->post('https://api.lemonsqueezy.com/v1/licenses/activate', [
|
||||
'license_key' => $settings->resale_license,
|
||||
'instance_name' => $instance_id,
|
||||
])->throw()->json();
|
||||
}
|
||||
'instance_id' => $instance_id,
|
||||
])->json();
|
||||
if (data_get($data, 'valid') === true && data_get($data, 'license_key.status') === 'active') {
|
||||
ray('Valid & active license key');
|
||||
$settings->update([
|
||||
'is_resale_license_active' => true,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
throw new \Exception('Invalid license key');
|
||||
$data = Http::withHeaders([
|
||||
'Accept' => 'application/json',
|
||||
])->get("$base_url/lemon/activate", [
|
||||
'license_key' => $settings->resale_license,
|
||||
'instance_id' => $instance_id,
|
||||
])->json();
|
||||
if (data_get($data, 'activated') === true) {
|
||||
ray('Activated license key');
|
||||
$settings->update([
|
||||
'is_resale_license_active' => true,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
if (data_get($data, 'license_key.status') === 'active') {
|
||||
throw new \Exception('Invalid license key.');
|
||||
}
|
||||
throw new \Exception('Cannot activate license key.');
|
||||
} catch (\Throwable $th) {
|
||||
ray($th);
|
||||
$settings->update([
|
||||
|
25
app/Actions/Proxy/CheckConfigurationSync.php
Normal file
25
app/Actions/Proxy/CheckConfigurationSync.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Proxy;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class CheckConfigurationSync
|
||||
{
|
||||
public function __invoke(Server $server, bool $reset = false)
|
||||
{
|
||||
$proxy_path = get_proxy_path();
|
||||
$proxy_configuration = instant_remote_process([
|
||||
"cat $proxy_path/docker-compose.yml",
|
||||
], $server, false);
|
||||
|
||||
if ($reset || is_null($proxy_configuration)) {
|
||||
$proxy_configuration = Str::of(generate_default_proxy_configuration($server))->trim()->value;
|
||||
resolve(SaveConfigurationSync::class)($server, $proxy_configuration);
|
||||
return $proxy_configuration;
|
||||
}
|
||||
|
||||
return $proxy_configuration;
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Proxy;
|
||||
|
||||
use App\Enums\ProxyTypes;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class CheckProxySettingsInSync
|
||||
{
|
||||
public function __invoke(Server $server, bool $reset = false)
|
||||
{
|
||||
$proxy_path = config('coolify.proxy_config_path');
|
||||
$output = instant_remote_process([
|
||||
"cat $proxy_path/docker-compose.yml",
|
||||
], $server, false);
|
||||
if (is_null($output) || $reset) {
|
||||
$final_output = Str::of(getProxyConfiguration($server))->trim()->value;
|
||||
} else {
|
||||
$final_output = Str::of($output)->trim()->value;
|
||||
}
|
||||
$docker_compose_yml_base64 = base64_encode($final_output);
|
||||
$server->proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
||||
$server->save();
|
||||
if (is_null($output) || $reset) {
|
||||
instant_remote_process([
|
||||
"mkdir -p $proxy_path",
|
||||
"echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
|
||||
], $server);
|
||||
}
|
||||
return $final_output;
|
||||
}
|
||||
}
|
23
app/Actions/Proxy/SaveConfigurationSync.php
Normal file
23
app/Actions/Proxy/SaveConfigurationSync.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Proxy;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SaveConfigurationSync
|
||||
{
|
||||
public function __invoke(Server $server, string $configuration)
|
||||
{
|
||||
$proxy_path = get_proxy_path();
|
||||
$docker_compose_yml_base64 = base64_encode($configuration);
|
||||
|
||||
$server->proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
||||
$server->save();
|
||||
|
||||
instant_remote_process([
|
||||
"mkdir -p $proxy_path",
|
||||
"echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
|
||||
], $server);
|
||||
}
|
||||
}
|
@ -5,8 +5,8 @@
|
||||
use App\Enums\ProxyStatus;
|
||||
use App\Enums\ProxyTypes;
|
||||
use App\Models\Server;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
|
||||
class StartProxy
|
||||
{
|
||||
@ -18,8 +18,7 @@ public function __invoke(Server $server): Activity
|
||||
$server->proxy->status = ProxyStatus::EXITED->value;
|
||||
$server->save();
|
||||
}
|
||||
$proxy_path = config('coolify.proxy_config_path');
|
||||
|
||||
$proxy_path = get_proxy_path();
|
||||
$networks = collect($server->standaloneDockers)->map(function ($docker) {
|
||||
return $docker['network'];
|
||||
})->unique();
|
||||
@ -30,29 +29,24 @@ public function __invoke(Server $server): Activity
|
||||
return "docker network ls --format '{{.Name}}' | grep '^$network$' >/dev/null 2>&1 || docker network create --attachable $network > /dev/null 2>&1";
|
||||
});
|
||||
|
||||
$configuration = instant_remote_process([
|
||||
"cat $proxy_path/docker-compose.yml",
|
||||
], $server, false);
|
||||
if (is_null($configuration)) {
|
||||
$configuration = Str::of(getProxyConfiguration($server))->trim()->value;
|
||||
} else {
|
||||
$configuration = Str::of($configuration)->trim()->value;
|
||||
}
|
||||
$configuration = resolve(CheckConfigurationSync::class)($server);
|
||||
|
||||
$docker_compose_yml_base64 = base64_encode($configuration);
|
||||
$server->proxy->last_applied_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
||||
$server->save();
|
||||
|
||||
$activity = remote_process([
|
||||
"echo 'Creating required Docker networks...'",
|
||||
...$create_networks_command,
|
||||
"mkdir -p $proxy_path",
|
||||
"cd $proxy_path",
|
||||
"echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
|
||||
"echo 'Creating Docker Compose file...'",
|
||||
"echo 'Pulling docker image...'",
|
||||
'docker compose pull -q',
|
||||
"echo 'Stopping old proxy...'",
|
||||
"echo 'Stopping existing proxy...'",
|
||||
'docker compose down -v --remove-orphans',
|
||||
"echo 'Starting new proxy...'",
|
||||
"lsof -nt -i:80 | xargs -r kill -9",
|
||||
"lsof -nt -i:443 | xargs -r kill -9",
|
||||
"echo 'Starting proxy...'",
|
||||
'docker compose up -d --remove-orphans',
|
||||
"echo 'Proxy installed successfully...'"
|
||||
], $server);
|
||||
|
@ -17,13 +17,13 @@ public function __invoke(bool $force)
|
||||
$settings = InstanceSettings::get();
|
||||
ray('Running InstanceAutoUpdateJob');
|
||||
$localhost_name = 'localhost';
|
||||
if (isDev()) {
|
||||
if (is_dev()) {
|
||||
$localhost_name = 'testing-local-docker-container';
|
||||
}
|
||||
$this->server = Server::where('name', $localhost_name)->firstOrFail();
|
||||
$this->latest_version = get_latest_version_of_coolify();
|
||||
$this->current_version = config('version');
|
||||
ray('latest version:' . $this->latest_version . " current version: " . $this->current_version . ' force: ' . $force);
|
||||
ray('latest version:' . $this->latest_version . " current version: " . $this->current_version . ' force: ' . $force);
|
||||
if ($settings->next_channel) {
|
||||
ray('next channel enabled');
|
||||
$this->latest_version = 'next';
|
||||
@ -49,9 +49,10 @@ public function __invoke(bool $force)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private function update()
|
||||
{
|
||||
if (isDev()) {
|
||||
if (is_dev()) {
|
||||
ray("Running update on local docker container. Updating to $this->latest_version");
|
||||
remote_process([
|
||||
"sleep 10"
|
||||
|
@ -10,10 +10,12 @@ class Init extends Command
|
||||
{
|
||||
protected $signature = 'app:init';
|
||||
protected $description = 'Cleanup instance related stuffs';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->cleanup_in_progress_application_deployments();
|
||||
}
|
||||
|
||||
private function cleanup_in_progress_application_deployments()
|
||||
{
|
||||
// Cleanup any failed deployments
|
||||
|
@ -43,15 +43,16 @@ private function showHelp()
|
||||
style('coolify')->color('#9333EA');
|
||||
style('title-box')->apply('mt-1 px-2 py-1 bg-coolify');
|
||||
|
||||
render(<<<'HTML'
|
||||
render(
|
||||
<<<'HTML'
|
||||
<div>
|
||||
<div class="title-box">
|
||||
Coolify
|
||||
</div>
|
||||
<p class="ml-1 mt-1 ">
|
||||
<p class="mt-1 ml-1 ">
|
||||
Demo Notify <strong class="text-coolify">=></strong> Send a demo notification to a given channel.
|
||||
</p>
|
||||
<p class="ml-1 mt-1 bg-coolify px-1">
|
||||
<p class="px-1 mt-1 ml-1 bg-coolify">
|
||||
php artisan app:demo-notify {channel}
|
||||
</p>
|
||||
<div class="my-1">
|
||||
@ -64,7 +65,8 @@ private function showHelp()
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
HTML);
|
||||
HTML
|
||||
);
|
||||
|
||||
ask(<<<'HTML'
|
||||
<div class="mr-1">
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Http\Client\PendingRequest;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Http\Client\Pool;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class SyncBunny extends Command
|
||||
{
|
||||
|
@ -3,10 +3,14 @@
|
||||
namespace App\Console;
|
||||
|
||||
use App\Jobs\CheckResaleLicenseJob;
|
||||
use App\Jobs\CheckResaleLicenseKeys;
|
||||
use App\Jobs\CleanupInstanceStuffsJob;
|
||||
use App\Jobs\DatabaseBackupJob;
|
||||
use App\Jobs\DockerCleanupJob;
|
||||
use App\Jobs\InstanceApplicationsStatusJob;
|
||||
use App\Jobs\InstanceAutoUpdateJob;
|
||||
use App\Jobs\ProxyCheckJob;
|
||||
use App\Jobs\DockerCleanupJob;
|
||||
use App\Jobs\CheckResaleLicenseKeys;
|
||||
use App\Models\ScheduledDatabaseBackup;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
@ -14,20 +18,47 @@ class Kernel extends ConsoleKernel
|
||||
{
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
if (isDev()) {
|
||||
// $schedule->call(fn() => $this->check_scheduled_backups($schedule))->everyTenSeconds();
|
||||
if (is_dev()) {
|
||||
$schedule->command('horizon:snapshot')->everyMinute();
|
||||
$schedule->job(new InstanceApplicationsStatusJob)->everyMinute();
|
||||
$schedule->job(new ProxyCheckJob)->everyFiveMinutes();
|
||||
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute();
|
||||
|
||||
// $schedule->job(new CheckResaleLicenseJob)->hourly();
|
||||
// $schedule->job(new DockerCleanupJob)->everyOddHour();
|
||||
// $schedule->job(new InstanceAutoUpdateJob(true))->everyMinute();
|
||||
} else {
|
||||
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
||||
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute();
|
||||
$schedule->job(new InstanceApplicationsStatusJob)->everyMinute();
|
||||
$schedule->job(new CheckResaleLicenseJob)->hourly();
|
||||
$schedule->job(new ProxyCheckJob)->everyFiveMinutes();
|
||||
$schedule->job(new DockerCleanupJob)->everyTenMinutes();
|
||||
$schedule->job(new InstanceAutoUpdateJob)->everyTenMinutes();
|
||||
}
|
||||
$this->check_scheduled_backups($schedule);
|
||||
}
|
||||
|
||||
private function check_scheduled_backups($schedule)
|
||||
{
|
||||
ray('check_scheduled_backups');
|
||||
$scheduled_backups = ScheduledDatabaseBackup::all();
|
||||
if ($scheduled_backups->isEmpty()) {
|
||||
ray('no scheduled backups');
|
||||
return;
|
||||
}
|
||||
foreach ($scheduled_backups as $scheduled_backup) {
|
||||
if (!$scheduled_backup->enabled) continue;
|
||||
if (isset(VALID_CRON_STRINGS[$scheduled_backup->frequency])) {
|
||||
$scheduled_backup->frequency = VALID_CRON_STRINGS[$scheduled_backup->frequency];
|
||||
}
|
||||
$schedule->job(new DatabaseBackupJob(
|
||||
backup: $scheduled_backup
|
||||
))->cron($scheduled_backup->frequency);
|
||||
}
|
||||
}
|
||||
|
||||
protected function commands(): void
|
||||
{
|
||||
$this->load(__DIR__ . '/Commands');
|
||||
|
@ -9,7 +9,7 @@
|
||||
class ServerMetadata extends Data
|
||||
{
|
||||
public function __construct(
|
||||
public ?ProxyTypes $type,
|
||||
public ?ProxyTypes $type,
|
||||
public ?ProxyStatus $status
|
||||
) {
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ enum ProxyTypes: string
|
||||
case NGINX = 'NGINX';
|
||||
case CADDY = 'CADDY';
|
||||
}
|
||||
|
||||
enum ProxyStatus: string
|
||||
{
|
||||
case EXITED = 'exited';
|
||||
|
@ -4,13 +4,12 @@
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Throwable;
|
||||
use Sentry\Laravel\Integration;
|
||||
use Throwable;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
|
||||
private InstanceSettings $settings;
|
||||
/**
|
||||
* A list of exception types with their corresponding custom log levels.
|
||||
*
|
||||
@ -19,7 +18,6 @@ class Handler extends ExceptionHandler
|
||||
protected $levels = [
|
||||
//
|
||||
];
|
||||
|
||||
/**
|
||||
* A list of the exception types that are not reported.
|
||||
*
|
||||
@ -28,7 +26,6 @@ class Handler extends ExceptionHandler
|
||||
protected $dontReport = [
|
||||
//
|
||||
];
|
||||
|
||||
/**
|
||||
* A list of the inputs that are never flashed to the session on validation exceptions.
|
||||
*
|
||||
@ -39,6 +36,7 @@ class Handler extends ExceptionHandler
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
private InstanceSettings $settings;
|
||||
|
||||
/**
|
||||
* Register the exception handling callbacks for the application.
|
||||
@ -47,7 +45,7 @@ public function register(): void
|
||||
{
|
||||
$this->reportable(function (Throwable $e) {
|
||||
$this->settings = InstanceSettings::get();
|
||||
if ($this->settings->do_not_track || isDev()) {
|
||||
if ($this->settings->do_not_track || is_dev()) {
|
||||
return;
|
||||
}
|
||||
Integration::captureUnhandledException($e);
|
||||
|
@ -5,15 +5,14 @@
|
||||
use App\Models\ApplicationDeploymentQueue;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Http\Request;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
|
||||
class ApplicationController extends Controller
|
||||
{
|
||||
use AuthorizesRequests, ValidatesRequests;
|
||||
|
||||
public function configuration()
|
||||
{
|
||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
@ -27,9 +26,10 @@ public function configuration()
|
||||
}
|
||||
return view('project.application.configuration', ['application' => $application]);
|
||||
}
|
||||
|
||||
public function deployments()
|
||||
{
|
||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
@ -49,7 +49,7 @@ public function deployment()
|
||||
{
|
||||
$deploymentUuid = request()->route('deployment_uuid');
|
||||
|
||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
|
@ -2,77 +2,89 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Livewire\Team\Invitations;
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Project;
|
||||
use App\Models\S3Storage;
|
||||
use App\Models\Server;
|
||||
use App\Models\StandalonePostgresql;
|
||||
use App\Models\TeamInvitation;
|
||||
use App\Models\User;
|
||||
use App\Models\Waitlist;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Throwable;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, ValidatesRequests;
|
||||
|
||||
public function waitlist() {
|
||||
$waiting_in_line = Waitlist::whereVerified(true)->count();
|
||||
return view('auth.waitlist', [
|
||||
'waiting_in_line' => $waiting_in_line,
|
||||
]);
|
||||
}
|
||||
public function subscription()
|
||||
{
|
||||
if (!isCloud()) {
|
||||
if (!is_cloud()) {
|
||||
abort(404);
|
||||
}
|
||||
return view('subscription', [
|
||||
'settings' => InstanceSettings::get()
|
||||
'settings' => InstanceSettings::get(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function license()
|
||||
{
|
||||
if (!isCloud()) {
|
||||
if (!is_cloud()) {
|
||||
abort(404);
|
||||
}
|
||||
return view('settings.license', [
|
||||
'settings' => InstanceSettings::get()
|
||||
'settings' => InstanceSettings::get(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function force_passoword_reset() {
|
||||
return view('auth.force-password-reset');
|
||||
}
|
||||
public function dashboard()
|
||||
{
|
||||
$projects = Project::ownedByCurrentTeam()->get();
|
||||
$servers = Server::ownedByCurrentTeam()->get();
|
||||
|
||||
$s3s = S3Storage::ownedByCurrentTeam()->get();
|
||||
$resources = 0;
|
||||
foreach ($projects as $project) {
|
||||
$resources += $project->applications->count();
|
||||
$resources += $project->postgresqls->count();
|
||||
}
|
||||
|
||||
return view('dashboard', [
|
||||
'servers' => $servers->count(),
|
||||
'projects' => $projects->count(),
|
||||
'resources' => $resources,
|
||||
's3s' => $s3s,
|
||||
]);
|
||||
}
|
||||
|
||||
public function settings()
|
||||
{
|
||||
if (auth()->user()->isInstanceAdmin()) {
|
||||
if (is_instance_admin()) {
|
||||
$settings = InstanceSettings::get();
|
||||
$database = StandalonePostgresql::whereName('coolify-db')->first();
|
||||
if ($database) {
|
||||
$s3s = S3Storage::whereTeamId(0)->get();
|
||||
}
|
||||
return view('settings.configuration', [
|
||||
'settings' => $settings
|
||||
]);
|
||||
} else {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
}
|
||||
public function emails()
|
||||
{
|
||||
if (auth()->user()->isInstanceAdmin()) {
|
||||
$settings = InstanceSettings::get();
|
||||
return view('settings.emails', [
|
||||
'settings' => $settings
|
||||
'settings' => $settings,
|
||||
'database' => $database,
|
||||
's3s' => $s3s ?? [],
|
||||
]);
|
||||
} else {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
}
|
||||
|
||||
public function team()
|
||||
{
|
||||
$invitations = [];
|
||||
@ -83,6 +95,23 @@ public function team()
|
||||
'invitations' => $invitations,
|
||||
]);
|
||||
}
|
||||
|
||||
public function storages()
|
||||
{
|
||||
$s3 = S3Storage::ownedByCurrentTeam()->get();
|
||||
return view('team.storages.all', [
|
||||
's3' => $s3,
|
||||
]);
|
||||
}
|
||||
|
||||
public function storages_show()
|
||||
{
|
||||
$storage = S3Storage::ownedByCurrentTeam()->whereUuid(request()->storage_uuid)->firstOrFail();
|
||||
return view('team.storages.show', [
|
||||
'storage' => $storage,
|
||||
]);
|
||||
}
|
||||
|
||||
public function members()
|
||||
{
|
||||
$invitations = [];
|
||||
@ -93,6 +122,7 @@ public function members()
|
||||
'invitations' => $invitations,
|
||||
]);
|
||||
}
|
||||
|
||||
public function acceptInvitation()
|
||||
{
|
||||
try {
|
||||
@ -115,10 +145,11 @@ public function acceptInvitation()
|
||||
$invitation->delete();
|
||||
abort(401);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
} catch (Throwable $th) {
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
public function revokeInvitation()
|
||||
{
|
||||
try {
|
||||
@ -132,7 +163,7 @@ public function revokeInvitation()
|
||||
}
|
||||
$invitation->delete();
|
||||
return redirect()->route('team.show');
|
||||
} catch (\Throwable $th) {
|
||||
} catch (Throwable $th) {
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
76
app/Http/Controllers/DatabaseController.php
Normal file
76
app/Http/Controllers/DatabaseController.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
|
||||
class DatabaseController extends Controller
|
||||
{
|
||||
use AuthorizesRequests, ValidatesRequests;
|
||||
|
||||
public function configuration()
|
||||
{
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']);
|
||||
if (!$environment) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
$database = $environment->databases->where('uuid', request()->route('database_uuid'))->first();
|
||||
if (!$database) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
return view('project.database.configuration', ['database' => $database]);
|
||||
}
|
||||
|
||||
public function executions()
|
||||
{
|
||||
$backup_uuid = request()->route('backup_uuid');
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']);
|
||||
if (!$environment) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
$database = $environment->databases->where('uuid', request()->route('database_uuid'))->first();
|
||||
if (!$database) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
$backup = $database->scheduledBackups->where('uuid', $backup_uuid)->first();
|
||||
if (!$backup) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
$executions = collect($backup->executions)->sortByDesc('created_at');
|
||||
return view('project.database.backups.executions', [
|
||||
'database' => $database,
|
||||
'backup' => $backup,
|
||||
'executions' => $executions,
|
||||
's3s' => auth()->user()->currentTeam()->s3s,
|
||||
]);
|
||||
}
|
||||
|
||||
public function backups()
|
||||
{
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']);
|
||||
if (!$environment) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
$database = $environment->databases->where('uuid', request()->route('database_uuid'))->first();
|
||||
if (!$database) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
return view('project.database.backups.all', [
|
||||
'database' => $database,
|
||||
's3s' => auth()->user()->currentTeam()->s3s,
|
||||
]);
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Livewire\Server\PrivateKey;
|
||||
use App\Models\Environment;
|
||||
use App\Models\Project;
|
||||
use App\Models\Server;
|
||||
@ -16,34 +15,39 @@ public function servers()
|
||||
'servers' => Server::isUsable()->get()
|
||||
]);
|
||||
}
|
||||
|
||||
public function destinations()
|
||||
{
|
||||
return response()->json([
|
||||
'destinations' => Server::destinationsByServer(request()->query('server_id'))->sortBy('name')
|
||||
]);
|
||||
}
|
||||
|
||||
public function projects()
|
||||
{
|
||||
return response()->json([
|
||||
'projects' => Project::ownedByCurrentTeam()->get()
|
||||
]);
|
||||
}
|
||||
|
||||
public function environments()
|
||||
{
|
||||
return response()->json([
|
||||
'environments' => Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->first()->environments
|
||||
]);
|
||||
}
|
||||
|
||||
public function newProject()
|
||||
{
|
||||
$project = Project::firstOrCreate(
|
||||
['name' => request()->query('name') ?? generate_random_name()],
|
||||
['team_id' => session('currentTeam')->id]
|
||||
['team_id' => auth()->user()->currentTeam()->id]
|
||||
);
|
||||
return response()->json([
|
||||
'project_uuid' => $project->uuid
|
||||
]);
|
||||
}
|
||||
|
||||
public function newEnvironment()
|
||||
{
|
||||
$environment = Environment::firstOrCreate(
|
||||
@ -54,6 +58,7 @@ public function newEnvironment()
|
||||
'environment_name' => $environment->name,
|
||||
]);
|
||||
}
|
||||
|
||||
public function newTeam()
|
||||
{
|
||||
$team = Team::create(
|
||||
|
@ -3,46 +3,48 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Project;
|
||||
use App\Models\Server;
|
||||
|
||||
class ProjectController extends Controller
|
||||
{
|
||||
public function all()
|
||||
{
|
||||
$teamId = session('currentTeam')->id;
|
||||
|
||||
$projects = Project::where('team_id', $teamId)->get();
|
||||
return view('projects', ['projects' => $projects]);
|
||||
return view('projects', [
|
||||
'projects' => Project::ownedByCurrentTeam()->get(),
|
||||
'servers' => Server::ownedByCurrentTeam()->count(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit()
|
||||
{
|
||||
$projectUuid = request()->route('project_uuid');
|
||||
$teamId = session('currentTeam')->id;
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
$project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
return view('project.edit', ['project' => $project]);
|
||||
}
|
||||
|
||||
public function show()
|
||||
{
|
||||
$projectUuid = request()->route('project_uuid');
|
||||
$teamId = session('currentTeam')->id;
|
||||
$teamId = auth()->user()->currentTeam()->id;
|
||||
|
||||
$project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
$project->load(['environments']);
|
||||
if (count($project->environments) == 1) {
|
||||
return redirect()->route('project.resources', ['project_uuid' => $project->uuid, 'environment_name' => $project->environments->first()->name]);
|
||||
}
|
||||
return view('project.show', ['project' => $project]);
|
||||
}
|
||||
|
||||
public function new()
|
||||
{
|
||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$type = request()->query('type');
|
||||
$destination_uuid = request()->query('destination');
|
||||
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
@ -50,16 +52,22 @@ public function new()
|
||||
if (!$environment) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
|
||||
$type = request()->query('type');
|
||||
|
||||
if (in_array($type, DATABASE_TYPES)) {
|
||||
$standalone_postgresql = create_standalone_postgresql($environment->id, $destination_uuid);
|
||||
return redirect()->route('project.database.configuration', [
|
||||
'project_uuid' => $project->uuid,
|
||||
'environment_name' => $environment->name,
|
||||
'database_uuid' => $standalone_postgresql->uuid,
|
||||
]);
|
||||
}
|
||||
return view('project.new', [
|
||||
'type' => $type
|
||||
]);
|
||||
}
|
||||
|
||||
public function resources()
|
||||
{
|
||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
$project = auth()->user()->currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
}
|
||||
|
31
app/Http/Controllers/ServerController.php
Normal file
31
app/Http/Controllers/ServerController.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\PrivateKey;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
|
||||
class ServerController extends Controller
|
||||
{
|
||||
use AuthorizesRequests, ValidatesRequests;
|
||||
|
||||
public function new_server()
|
||||
{
|
||||
if (!is_cloud() || is_instance_admin()) {
|
||||
return view('server.create', [
|
||||
'limit_reached' => false,
|
||||
'private_keys' => PrivateKey::ownedByCurrentTeam()->get(),
|
||||
]);
|
||||
}
|
||||
$servers = auth()->user()->currentTeam()->servers->count();
|
||||
$subscription = auth()->user()->currentTeam()?->subscription->type();
|
||||
$limits = config('constants.limits.server')[strtolower($subscription)];
|
||||
$limit_reached = true ?? $servers >= $limits[$subscription];
|
||||
|
||||
return view('server.create', [
|
||||
'limit_reached' => $limit_reached,
|
||||
'private_keys' => PrivateKey::ownedByCurrentTeam()->get(),
|
||||
]);
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ class Kernel extends HttpKernel
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\CheckForcePasswordReset::class,
|
||||
\App\Http\Middleware\SubscriptionValid::class,
|
||||
|
||||
],
|
||||
|
@ -8,19 +8,13 @@
|
||||
|
||||
class ActivityMonitor extends Component
|
||||
{
|
||||
public bool $header = false;
|
||||
public string|null $header = null;
|
||||
public $activityId;
|
||||
public $isPollingActive = false;
|
||||
|
||||
protected $activity;
|
||||
protected $listeners = ['newMonitorActivity'];
|
||||
|
||||
public function hydrateActivity()
|
||||
{
|
||||
$this->activity = Activity::query()
|
||||
->find($this->activityId);
|
||||
}
|
||||
|
||||
public function newMonitorActivity($activityId)
|
||||
{
|
||||
$this->activityId = $activityId;
|
||||
@ -30,6 +24,12 @@ public function newMonitorActivity($activityId)
|
||||
$this->isPollingActive = true;
|
||||
}
|
||||
|
||||
public function hydrateActivity()
|
||||
{
|
||||
$this->activity = Activity::query()
|
||||
->find($this->activityId);
|
||||
}
|
||||
|
||||
public function polling()
|
||||
{
|
||||
$this->hydrateActivity();
|
||||
@ -42,8 +42,10 @@ public function polling()
|
||||
$this->setStatus(ProcessStatus::ERROR);
|
||||
}
|
||||
$this->isPollingActive = false;
|
||||
$this->emit('activityFinished');
|
||||
}
|
||||
}
|
||||
|
||||
protected function setStatus($status)
|
||||
{
|
||||
$this->activity->properties = $this->activity->properties->merge([
|
||||
|
@ -19,11 +19,13 @@ class CheckLicense extends Component
|
||||
'instance_id' => 'Instance Id (Do not change this)',
|
||||
'settings.is_resale_license_active' => 'Is License Active',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->instance_id = config('app.id');
|
||||
$this->settings = InstanceSettings::get();
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
|
@ -18,11 +18,13 @@ class Form extends Component
|
||||
'destination.network' => 'network',
|
||||
'destination.server.ip' => 'IP Address',
|
||||
];
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
$this->destination->save();
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
try {
|
||||
|
@ -5,6 +5,7 @@
|
||||
use App\Models\Server;
|
||||
use App\Models\StandaloneDocker as ModelsStandaloneDocker;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
@ -27,6 +28,7 @@ class StandaloneDocker extends Component
|
||||
'network' => 'network',
|
||||
'server_id' => 'server'
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (request()->query('server_id')) {
|
||||
@ -41,16 +43,17 @@ public function mount()
|
||||
} else {
|
||||
$this->network = new Cuid2(7);
|
||||
}
|
||||
$this->name = generate_random_name();
|
||||
$this->name = Str::kebab("{$this->servers->first()->name}-{$this->network}");
|
||||
}
|
||||
private function createNetworkAndAttachToProxy()
|
||||
|
||||
public function generate_name()
|
||||
{
|
||||
instant_remote_process(['docker network create --attachable ' . $this->network], $this->server, throwError: false);
|
||||
instant_remote_process(["docker network connect $this->network coolify-proxy"], $this->server, throwError: false);
|
||||
$this->server = Server::find($this->server_id);
|
||||
$this->name = Str::kebab("{$this->server->name}-{$this->network}");
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
|
||||
$this->validate();
|
||||
try {
|
||||
$this->server = Server::find($this->server_id);
|
||||
@ -64,7 +67,7 @@ public function submit()
|
||||
'name' => $this->name,
|
||||
'network' => $this->network,
|
||||
'server_id' => $this->server_id,
|
||||
'team_id' => session('currentTeam')->id
|
||||
'team_id' => auth()->user()->currentTeam()->id
|
||||
]);
|
||||
}
|
||||
$this->createNetworkAndAttachToProxy();
|
||||
@ -73,4 +76,10 @@ public function submit()
|
||||
return general_error_handler(err: $e);
|
||||
}
|
||||
}
|
||||
|
||||
private function createNetworkAndAttachToProxy()
|
||||
{
|
||||
instant_remote_process(['docker network create --attachable ' . $this->network], $this->server, throwError: false);
|
||||
instant_remote_process(["docker network connect $this->network coolify-proxy"], $this->server, throwError: false);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ class Show extends Component
|
||||
{
|
||||
public Server $server;
|
||||
public Collection|array $networks = [];
|
||||
|
||||
public function scan()
|
||||
{
|
||||
$alreadyAddedNetworks = $this->server->standaloneDockers;
|
||||
|
41
app/Http/Livewire/Dev/S3Test.php
Normal file
41
app/Http/Livewire/Dev/S3Test.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Dev;
|
||||
|
||||
use App\Models\S3Storage;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithFileUploads;
|
||||
|
||||
class S3Test extends Component
|
||||
{
|
||||
use WithFileUploads;
|
||||
|
||||
public $s3;
|
||||
public $file;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->s3 = S3Storage::first();
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
try {
|
||||
$this->validate([
|
||||
'file' => 'required|max:150', // 1MB Max
|
||||
]);
|
||||
set_s3_target($this->s3);
|
||||
$this->file->storeAs('files', $this->file->getClientOriginalName(), 'custom-s3');
|
||||
$this->emit('success', 'File uploaded successfully.');
|
||||
} catch (\Throwable $th) {
|
||||
return general_error_handler($th, $this, false);
|
||||
}
|
||||
}
|
||||
|
||||
public function get_files()
|
||||
{
|
||||
set_s3_target($this->s3);
|
||||
dd(Storage::disk('custom-s3')->files('files'));
|
||||
}
|
||||
}
|
39
app/Http/Livewire/ForcePasswordReset.php
Normal file
39
app/Http/Livewire/ForcePasswordReset.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
|
||||
use Livewire\Component;
|
||||
|
||||
class ForcePasswordReset extends Component
|
||||
{
|
||||
use WithRateLimiting;
|
||||
public string $email;
|
||||
public string $password;
|
||||
public string $password_confirmation;
|
||||
|
||||
protected $rules = [
|
||||
'email' => 'required|email',
|
||||
'password' => 'required|min:8',
|
||||
'password_confirmation' => 'required|same:password',
|
||||
];
|
||||
public function mount() {
|
||||
$this->email = auth()->user()->email;
|
||||
}
|
||||
public function submit() {
|
||||
try {
|
||||
$this->rateLimit(10);
|
||||
$this->validate();
|
||||
auth()->user()->forceFill([
|
||||
'password' => Hash::make($this->password),
|
||||
'force_password_reset' => false,
|
||||
])->save();
|
||||
auth()->logout();
|
||||
return redirect()->route('login')->with('status', 'Your initial password has been set.');
|
||||
} catch(\Exception $e) {
|
||||
return general_error_handler(err:$e, that:$this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Livewire\Component;
|
||||
|
||||
class License extends Component
|
||||
{
|
||||
public string $license;
|
||||
public function submit()
|
||||
{
|
||||
ray('checking license');
|
||||
$this->validate([
|
||||
'license' => 'required'
|
||||
]);
|
||||
// Pretend we're checking the license
|
||||
// if ($this->license === '123') {
|
||||
// ray('license is valid');
|
||||
// Cache::put('license_key', '123');
|
||||
// return redirect()->to('/');
|
||||
// } else {
|
||||
// ray('license is invalid');
|
||||
// }
|
||||
}
|
||||
}
|
@ -3,48 +3,55 @@
|
||||
namespace App\Http\Livewire\Notifications;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Notifications\Notifications\TestNotification;
|
||||
use App\Notifications\Test;
|
||||
use Livewire\Component;
|
||||
|
||||
class DiscordSettings extends Component
|
||||
{
|
||||
public Team $model;
|
||||
protected $rules = [
|
||||
'model.discord.enabled' => 'nullable|boolean',
|
||||
'model.discord.webhook_url' => 'required|url',
|
||||
'model.discord_notifications.test' => 'nullable|boolean',
|
||||
'model.discord_notifications.deployments' => 'nullable|boolean',
|
||||
|
||||
'model.discord_enabled' => 'nullable|boolean',
|
||||
'model.discord_webhook_url' => 'required|url',
|
||||
'model.discord_notifications_test' => 'nullable|boolean',
|
||||
'model.discord_notifications_deployments' => 'nullable|boolean',
|
||||
'model.discord_notifications_status_changes' => 'nullable|boolean',
|
||||
'model.discord_notifications_database_backups' => 'nullable|boolean',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'model.discord.webhook_url' => 'Discord Webhook',
|
||||
'model.discord_webhook_url' => 'Discord Webhook',
|
||||
];
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
try {
|
||||
$this->submit();
|
||||
} catch (\Exception $e) {
|
||||
$this->model->discord->enabled = false;
|
||||
ray($e->getMessage());
|
||||
$this->model->discord_enabled = false;
|
||||
$this->validate();
|
||||
}
|
||||
}
|
||||
public function saveModel()
|
||||
{
|
||||
$this->model->save();
|
||||
if (is_a($this->model, Team::class)) {
|
||||
session(['currentTeam' => $this->model]);
|
||||
}
|
||||
$this->emit('success', 'Settings saved.');
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->resetErrorBag();
|
||||
$this->validate();
|
||||
$this->saveModel();
|
||||
}
|
||||
|
||||
public function saveModel()
|
||||
{
|
||||
ray($this->model);
|
||||
$this->model->save();
|
||||
if (is_a($this->model, Team::class)) {
|
||||
session(['currentTeam' => $this->model]);
|
||||
}
|
||||
$this->emit('success', 'Settings saved.');
|
||||
}
|
||||
|
||||
public function sendTestNotification()
|
||||
{
|
||||
$this->model->notify(new TestNotification('discord'));
|
||||
$this->model->notify(new Test);
|
||||
$this->emit('success', 'Test notification sent.');
|
||||
}
|
||||
}
|
||||
|
@ -4,89 +4,116 @@
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\Notifications\TestNotification;
|
||||
use App\Notifications\Test;
|
||||
use Livewire\Component;
|
||||
|
||||
class EmailSettings extends Component
|
||||
{
|
||||
public Team $model;
|
||||
public string $emails;
|
||||
|
||||
protected $rules = [
|
||||
'model.smtp.enabled' => 'nullable|boolean',
|
||||
'model.smtp.from_address' => 'required|email',
|
||||
'model.smtp.from_name' => 'required',
|
||||
'model.smtp.recipients' => 'nullable',
|
||||
'model.smtp.host' => 'required',
|
||||
'model.smtp.port' => 'required',
|
||||
'model.smtp.encryption' => 'nullable',
|
||||
'model.smtp.username' => 'nullable',
|
||||
'model.smtp.password' => 'nullable',
|
||||
'model.smtp.timeout' => 'nullable',
|
||||
'model.smtp.test_recipients' => 'nullable',
|
||||
'model.smtp_notifications.test' => 'nullable|boolean',
|
||||
'model.smtp_notifications.deployments' => 'nullable|boolean',
|
||||
'model.discord_notifications.test' => 'nullable|boolean',
|
||||
'model.discord_notifications.deployments' => 'nullable|boolean',
|
||||
'model.smtp_enabled' => 'nullable|boolean',
|
||||
'model.smtp_from_address' => 'required|email',
|
||||
'model.smtp_from_name' => 'required',
|
||||
'model.smtp_recipients' => 'nullable',
|
||||
'model.smtp_host' => 'required',
|
||||
'model.smtp_port' => 'required',
|
||||
'model.smtp_encryption' => 'nullable',
|
||||
'model.smtp_username' => 'nullable',
|
||||
'model.smtp_password' => 'nullable',
|
||||
'model.smtp_timeout' => 'nullable',
|
||||
'model.smtp_notifications_test' => 'nullable|boolean',
|
||||
'model.smtp_notifications_deployments' => 'nullable|boolean',
|
||||
'model.smtp_notifications_status_changes' => 'nullable|boolean',
|
||||
'model.smtp_notifications_database_backups' => 'nullable|boolean',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'model.smtp.from_address' => 'From Address',
|
||||
'model.smtp.from_name' => 'From Name',
|
||||
'model.smtp.recipients' => 'Recipients',
|
||||
'model.smtp.host' => 'Host',
|
||||
'model.smtp.port' => 'Port',
|
||||
'model.smtp.encryption' => 'Encryption',
|
||||
'model.smtp.username' => 'Username',
|
||||
'model.smtp.password' => 'Password',
|
||||
'model.smtp.test_recipients' => 'Test Recipients',
|
||||
'model.smtp_from_address' => 'From Address',
|
||||
'model.smtp_from_name' => 'From Name',
|
||||
'model.smtp_recipients' => 'Recipients',
|
||||
'model.smtp_host' => 'Host',
|
||||
'model.smtp_port' => 'Port',
|
||||
'model.smtp_encryption' => 'Encryption',
|
||||
'model.smtp_username' => 'Username',
|
||||
'model.smtp_password' => 'Password',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->decrypt();
|
||||
$this->emails = auth()->user()->email;
|
||||
}
|
||||
|
||||
private function decrypt()
|
||||
{
|
||||
if (data_get($this->model, 'smtp.password')) {
|
||||
if (data_get($this->model, 'smtp_password')) {
|
||||
try {
|
||||
$this->model->smtp->password = decrypt($this->model->smtp->password);
|
||||
$this->model->smtp_password = decrypt($this->model->smtp_password);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
public function mount()
|
||||
{
|
||||
$this->decrypt();
|
||||
}
|
||||
|
||||
public function copyFromInstanceSettings()
|
||||
{
|
||||
$settings = InstanceSettings::get();
|
||||
if ($settings->smtp->enabled) {
|
||||
$this->model->smtp->enabled = true;
|
||||
$this->model->smtp->from_address = $settings->smtp->from_address;
|
||||
$this->model->smtp->from_name = $settings->smtp->from_name;
|
||||
$this->model->smtp->recipients = $settings->smtp->recipients;
|
||||
$this->model->smtp->host = $settings->smtp->host;
|
||||
$this->model->smtp->port = $settings->smtp->port;
|
||||
$this->model->smtp->encryption = $settings->smtp->encryption;
|
||||
$this->model->smtp->username = $settings->smtp->username;
|
||||
$this->model->smtp->password = $settings->smtp->password;
|
||||
$this->model->smtp->timeout = $settings->smtp->timeout;
|
||||
$this->model->smtp->test_recipients = $settings->smtp->test_recipients;
|
||||
$this->saveModel();
|
||||
if ($settings->smtp_enabled) {
|
||||
$team = auth()->user()->currentTeam();
|
||||
$team->update([
|
||||
'smtp_enabled' => $settings->smtp_enabled,
|
||||
'smtp_from_address' => $settings->smtp_from_address,
|
||||
'smtp_from_name' => $settings->smtp_from_name,
|
||||
'smtp_recipients' => $settings->smtp_recipients,
|
||||
'smtp_host' => $settings->smtp_host,
|
||||
'smtp_port' => $settings->smtp_port,
|
||||
'smtp_encryption' => $settings->smtp_encryption,
|
||||
'smtp_username' => $settings->smtp_username,
|
||||
'smtp_password' => $settings->smtp_password,
|
||||
'smtp_timeout' => $settings->smtp_timeout,
|
||||
]);
|
||||
$this->decrypt();
|
||||
if (is_a($team, Team::class)) {
|
||||
session(['currentTeam' => $team]);
|
||||
}
|
||||
$this->model = $team;
|
||||
$this->emit('success', 'Settings saved.');
|
||||
} else {
|
||||
$this->emit('error', 'Instance SMTP settings are not enabled.');
|
||||
}
|
||||
}
|
||||
|
||||
public function sendTestNotification()
|
||||
{
|
||||
$this->model->notify(new Test($this->emails));
|
||||
$this->emit('success', 'Test Email sent successfully.');
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
try {
|
||||
$this->submit();
|
||||
} catch (\Exception $e) {
|
||||
$this->model->smtp_enabled = false;
|
||||
$this->validate();
|
||||
}
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->resetErrorBag();
|
||||
$this->validate();
|
||||
|
||||
if ($this->model->smtp->password) {
|
||||
$this->model->smtp->password = encrypt($this->model->smtp->password);
|
||||
if ($this->model->smtp_password) {
|
||||
$this->model->smtp_password = encrypt($this->model->smtp_password);
|
||||
} else {
|
||||
$this->model->smtp->password = null;
|
||||
$this->model->smtp_password = null;
|
||||
}
|
||||
|
||||
$this->model->smtp->recipients = str_replace(' ', '', $this->model->smtp->recipients);
|
||||
$this->model->smtp->test_recipients = str_replace(' ', '', $this->model->smtp->test_recipients);
|
||||
$this->model->smtp_recipients = str_replace(' ', '', $this->model->smtp_recipients);
|
||||
$this->saveModel();
|
||||
}
|
||||
|
||||
public function saveModel()
|
||||
{
|
||||
$this->model->save();
|
||||
@ -96,18 +123,4 @@ public function saveModel()
|
||||
}
|
||||
$this->emit('success', 'Settings saved.');
|
||||
}
|
||||
public function sendTestNotification()
|
||||
{
|
||||
$this->model->notify(new TestNotification('smtp'));
|
||||
$this->emit('success', 'Test notification sent.');
|
||||
}
|
||||
public function instantSave()
|
||||
{
|
||||
try {
|
||||
$this->submit();
|
||||
} catch (\Exception $e) {
|
||||
$this->model->smtp->enabled = false;
|
||||
$this->validate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,12 +20,13 @@ class Change extends Component
|
||||
'private_key.description' => 'description',
|
||||
'private_key.private_key' => 'private key'
|
||||
];
|
||||
|
||||
public function delete()
|
||||
{
|
||||
try {
|
||||
if ($this->private_key->isEmpty()) {
|
||||
$this->private_key->delete();
|
||||
session('currentTeam')->privateKeys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
|
||||
auth()->user()->currentTeam()->privateKeys = PrivateKey::where('team_id', auth()->user()->currentTeam()->id)->get();
|
||||
return redirect()->route('private-key.all');
|
||||
}
|
||||
$this->emit('error', 'This private key is in use and cannot be deleted. Please delete all servers, applications, and GitHub/GitLab apps that use this private key before deleting it.');
|
||||
@ -33,6 +34,7 @@ public function delete()
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function changePrivateKey()
|
||||
{
|
||||
try {
|
||||
@ -41,7 +43,7 @@ public function changePrivateKey()
|
||||
$this->private_key->private_key .= "\n";
|
||||
}
|
||||
$this->private_key->save();
|
||||
session('currentTeam')->privateKeys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
|
||||
refreshPrivateKey($this->private_key);
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
class Create extends Component
|
||||
{
|
||||
protected string|null $from = null;
|
||||
public string|null $from = null;
|
||||
public string $name;
|
||||
public string|null $description = null;
|
||||
public string $value;
|
||||
@ -19,6 +19,7 @@ class Create extends Component
|
||||
'name' => 'name',
|
||||
'value' => 'private Key',
|
||||
];
|
||||
|
||||
public function createPrivateKey()
|
||||
{
|
||||
$this->validate();
|
||||
@ -31,7 +32,7 @@ public function createPrivateKey()
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'private_key' => $this->value,
|
||||
'team_id' => session('currentTeam')->id
|
||||
'team_id' => auth()->user()->currentTeam()->id
|
||||
]);
|
||||
if ($this->from === 'server') {
|
||||
return redirect()->route('server.create');
|
||||
|
@ -17,12 +17,14 @@ class Form extends Component
|
||||
protected $validationAttributes = [
|
||||
'name' => 'name',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->userId = auth()->user()->id;
|
||||
$this->name = auth()->user()->name;
|
||||
$this->email = auth()->user()->email;
|
||||
}
|
||||
|
||||
public function submit()
|
||||
|
||||
{
|
||||
|
37
app/Http/Livewire/Project/AddEmpty.php
Normal file
37
app/Http/Livewire/Project/AddEmpty.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project;
|
||||
|
||||
use App\Models\Project;
|
||||
use Livewire\Component;
|
||||
|
||||
class AddEmpty extends Component
|
||||
{
|
||||
public string $name = '';
|
||||
public string $description = '';
|
||||
protected $rules = [
|
||||
'name' => 'required|string|min:3',
|
||||
'description' => 'nullable|string',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'name' => 'Project Name',
|
||||
'description' => 'Project Description',
|
||||
];
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->validate();
|
||||
$project = Project::create([
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
]);
|
||||
return redirect()->route('project.show', $project->uuid);
|
||||
} catch (\Exception $e) {
|
||||
general_error_handler($e, $this);
|
||||
} finally {
|
||||
$this->name = '';
|
||||
}
|
||||
}
|
||||
}
|
40
app/Http/Livewire/Project/AddEnvironment.php
Normal file
40
app/Http/Livewire/Project/AddEnvironment.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project;
|
||||
|
||||
use App\Models\Environment;
|
||||
use App\Models\Project;
|
||||
use Livewire\Component;
|
||||
|
||||
class AddEnvironment extends Component
|
||||
{
|
||||
public Project $project;
|
||||
public string $name = '';
|
||||
public string $description = '';
|
||||
protected $rules = [
|
||||
'name' => 'required|string|min:3',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'name' => 'Environment Name',
|
||||
];
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->validate();
|
||||
$environment = Environment::create([
|
||||
'name' => $this->name,
|
||||
'project_id' => $this->project->id,
|
||||
]);
|
||||
|
||||
return redirect()->route('project.resources', [
|
||||
'project_uuid' => $this->project->uuid,
|
||||
'environment_name' => $environment->name,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
general_error_handler($e, $this);
|
||||
} finally {
|
||||
$this->name = '';
|
||||
}
|
||||
}
|
||||
}
|
@ -10,10 +10,12 @@ class DeploymentLogs extends Component
|
||||
public ApplicationDeploymentQueue $application_deployment_queue;
|
||||
public $isKeepAliveOn = true;
|
||||
protected $listeners = ['refreshQueue'];
|
||||
|
||||
public function refreshQueue()
|
||||
{
|
||||
$this->application_deployment_queue->refresh();
|
||||
}
|
||||
|
||||
public function polling()
|
||||
{
|
||||
$this->emit('deploymentFinished');
|
||||
|
@ -8,17 +8,16 @@
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Livewire\Component;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
|
||||
class DeploymentNavbar extends Component
|
||||
{
|
||||
protected $listeners = ['deploymentFinished'];
|
||||
|
||||
public ApplicationDeploymentQueue $application_deployment_queue;
|
||||
public Application $application;
|
||||
public Server $server;
|
||||
public bool $is_debug_enabled = false;
|
||||
protected $listeners = ['deploymentFinished'];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
@ -26,10 +25,12 @@ public function mount()
|
||||
$this->server = $this->application->destination->server;
|
||||
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
||||
}
|
||||
|
||||
public function deploymentFinished()
|
||||
{
|
||||
$this->application_deployment_queue->refresh();
|
||||
}
|
||||
|
||||
public function show_debug()
|
||||
{
|
||||
$this->application->settings->is_debug_enabled = !$this->application->settings->is_debug_enabled;
|
||||
@ -37,6 +38,7 @@ public function show_debug()
|
||||
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
||||
$this->emit('refreshQueue');
|
||||
}
|
||||
|
||||
public function cancel()
|
||||
{
|
||||
try {
|
||||
|
@ -20,6 +20,7 @@ public function mount()
|
||||
$this->current_url = url()->current();
|
||||
$this->show_more();
|
||||
}
|
||||
|
||||
private function show_more()
|
||||
{
|
||||
if (count($this->deployments) !== 0) {
|
||||
@ -30,10 +31,12 @@ private function show_more()
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public function reload_deployments()
|
||||
{
|
||||
$this->load_deployments();
|
||||
}
|
||||
|
||||
public function load_deployments(int|null $take = null)
|
||||
{
|
||||
if ($take) {
|
||||
|
@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Application\EnvironmentVariable;
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\EnvironmentVariable;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class All extends Component
|
||||
{
|
||||
public Application $application;
|
||||
public string|null $modalId = null;
|
||||
protected $listeners = ['refreshEnvs', 'submit'];
|
||||
public function mount()
|
||||
{
|
||||
$this->modalId = new Cuid2(7);
|
||||
}
|
||||
public function refreshEnvs()
|
||||
{
|
||||
$this->application->refresh();
|
||||
}
|
||||
public function submit($data)
|
||||
{
|
||||
try {
|
||||
$found = $this->application->environment_variables()->where('key', $data['key'])->first();
|
||||
if ($found) {
|
||||
$this->emit('error', 'Environment variable already exists.');
|
||||
return;
|
||||
}
|
||||
EnvironmentVariable::create([
|
||||
'key' => $data['key'],
|
||||
'value' => $data['value'],
|
||||
'is_build_time' => $data['is_build_time'],
|
||||
'is_preview' => $data['is_preview'],
|
||||
'application_id' => $this->application->id,
|
||||
]);
|
||||
$this->application->refresh();
|
||||
|
||||
$this->emit('success', 'Environment variable added successfully.');
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\InstanceSettings;
|
||||
use Livewire\Component;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
use Spatie\Url\Url;
|
||||
|
||||
class General extends Component
|
||||
@ -33,6 +33,7 @@ class General extends Component
|
||||
|
||||
protected $rules = [
|
||||
'application.name' => 'required',
|
||||
'application.description' => 'nullable',
|
||||
'application.fqdn' => 'nullable',
|
||||
'application.git_repository' => 'required',
|
||||
'application.git_branch' => 'required',
|
||||
@ -46,9 +47,11 @@ class General extends Component
|
||||
'application.publish_directory' => 'nullable',
|
||||
'application.ports_exposes' => 'required',
|
||||
'application.ports_mappings' => 'nullable',
|
||||
'application.dockerfile' => 'nullable',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'application.name' => 'name',
|
||||
'application.description' => 'description',
|
||||
'application.fqdn' => 'FQDN',
|
||||
'application.git_repository' => 'Git repository',
|
||||
'application.git_branch' => 'Git branch',
|
||||
@ -62,7 +65,9 @@ class General extends Component
|
||||
'application.publish_directory' => 'Publish directory',
|
||||
'application.ports_exposes' => 'Ports exposes',
|
||||
'application.ports_mappings' => 'Ports mappings',
|
||||
'application.dockerfile' => 'Dockerfile',
|
||||
];
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
// @TODO: find another way - if possible
|
||||
@ -84,6 +89,7 @@ public function instantSave()
|
||||
$this->emit('success', 'Application settings updated!');
|
||||
$this->checkWildCardDomain();
|
||||
}
|
||||
|
||||
protected function checkWildCardDomain()
|
||||
{
|
||||
$coolify_instance_settings = InstanceSettings::get();
|
||||
@ -91,6 +97,7 @@ protected function checkWildCardDomain()
|
||||
$this->global_wildcard_domain = data_get($coolify_instance_settings, 'wildcard_domain');
|
||||
$this->wildcard_domain = $this->server_wildcard_domain ?? $this->global_wildcard_domain ?? null;
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->is_static = $this->application->settings->is_static;
|
||||
@ -102,6 +109,7 @@ public function mount()
|
||||
$this->is_force_https_enabled = $this->application->settings->is_force_https_enabled;
|
||||
$this->checkWildCardDomain();
|
||||
}
|
||||
|
||||
public function generateGlobalRandomDomain()
|
||||
{
|
||||
// Set wildcard domain based on Global wildcard domain
|
||||
@ -113,6 +121,7 @@ public function generateGlobalRandomDomain()
|
||||
$this->application->save();
|
||||
$this->emit('success', 'Application settings updated!');
|
||||
}
|
||||
|
||||
public function generateServerRandomDomain()
|
||||
{
|
||||
// Set wildcard domain based on Server wildcard domain
|
||||
@ -124,6 +133,7 @@ public function generateServerRandomDomain()
|
||||
$this->application->save();
|
||||
$this->emit('success', 'Application settings updated!');
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
@ -132,6 +142,10 @@ public function submit()
|
||||
$domains = Str::of($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
|
||||
return Str::of($domain)->trim()->lower();
|
||||
});
|
||||
$port = get_port_from_dockerfile($this->application->dockerfile);
|
||||
if ($port) {
|
||||
$this->application->ports_exposes = $port;
|
||||
}
|
||||
if ($this->application->base_directory && $this->application->base_directory !== '/') {
|
||||
$this->application->base_directory = rtrim($this->application->base_directory, '/');
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Application;
|
||||
namespace App\Http\Livewire\Project\Application;
|
||||
|
||||
use App\Jobs\ApplicationContainerStatusJob;
|
||||
use App\Jobs\ContainerStatusJob;
|
||||
use App\Models\Application;
|
||||
use App\Notifications\Application\StatusChanged;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
@ -16,17 +17,23 @@ class Heading extends Component
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function check_status()
|
||||
{
|
||||
dispatch_sync(new ApplicationContainerStatusJob(
|
||||
application: $this->application,
|
||||
dispatch_sync(new ContainerStatusJob(
|
||||
resource: $this->application,
|
||||
container_name: generate_container_name($this->application->uuid),
|
||||
));
|
||||
$this->application->refresh();
|
||||
}
|
||||
|
||||
public function force_deploy_without_cache()
|
||||
{
|
||||
$this->deploy(force_rebuild: true);
|
||||
}
|
||||
|
||||
public function deploy(bool $force_rebuild = false)
|
||||
{
|
||||
$this->setDeploymentUuid();
|
||||
@ -42,10 +49,13 @@ public function deploy(bool $force_rebuild = false)
|
||||
'environment_name' => $this->parameters['environment_name'],
|
||||
]);
|
||||
}
|
||||
public function force_deploy_without_cache()
|
||||
|
||||
protected function setDeploymentUuid()
|
||||
{
|
||||
$this->deploy(force_rebuild: true);
|
||||
$this->deploymentUuid = new Cuid2(7);
|
||||
$this->parameters['deployment_uuid'] = $this->deploymentUuid;
|
||||
}
|
||||
|
||||
public function stop()
|
||||
{
|
||||
remote_process(
|
||||
@ -54,10 +64,6 @@ public function stop()
|
||||
);
|
||||
$this->application->status = 'stopped';
|
||||
$this->application->save();
|
||||
}
|
||||
protected function setDeploymentUuid()
|
||||
{
|
||||
$this->deploymentUuid = new Cuid2(7);
|
||||
$this->parameters['deployment_uuid'] = $this->deploymentUuid;
|
||||
$this->application->environment->project->team->notify(new StatusChanged($this->application));
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ class Form extends Component
|
||||
protected $validationAttributes = [
|
||||
'application.preview_url_template' => 'preview url template',
|
||||
];
|
||||
|
||||
public function resetToDefault()
|
||||
{
|
||||
$this->application->preview_url_template = '{{pr_id}}.{{domain}}';
|
||||
@ -24,6 +25,7 @@ public function resetToDefault()
|
||||
$this->application->save();
|
||||
$this->generate_real_url();
|
||||
}
|
||||
|
||||
public function generate_real_url()
|
||||
{
|
||||
if (data_get($this->application, 'fqdn')) {
|
||||
@ -32,10 +34,12 @@ public function generate_real_url()
|
||||
$this->preview_url_template = Str::of($this->application->preview_url_template)->replace('{{domain}}', $host);
|
||||
}
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->generate_real_url();
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Livewire\Project\Application;
|
||||
|
||||
use App\Jobs\ApplicationContainerStatusJob;
|
||||
use App\Jobs\ContainerStatusJob;
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationPreview;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -20,21 +20,18 @@ class Previews extends Component
|
||||
public function mount()
|
||||
{
|
||||
$this->pull_requests = collect();
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function loadStatus($pull_request_id)
|
||||
{
|
||||
dispatch(new ApplicationContainerStatusJob(
|
||||
application: $this->application,
|
||||
dispatch(new ContainerStatusJob(
|
||||
resource: $this->application,
|
||||
container_name: generate_container_name($this->application->uuid, $pull_request_id),
|
||||
pull_request_id: $pull_request_id
|
||||
));
|
||||
}
|
||||
protected function setDeploymentUuid()
|
||||
{
|
||||
$this->deployment_uuid = new Cuid2(7);
|
||||
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
|
||||
}
|
||||
|
||||
public function load_prs()
|
||||
{
|
||||
try {
|
||||
@ -46,6 +43,7 @@ public function load_prs()
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function deploy(int $pull_request_id, string|null $pull_request_html_url = null)
|
||||
{
|
||||
try {
|
||||
@ -74,6 +72,13 @@ public function deploy(int $pull_request_id, string|null $pull_request_html_url
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
protected function setDeploymentUuid()
|
||||
{
|
||||
$this->deployment_uuid = new Cuid2(7);
|
||||
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
|
||||
}
|
||||
|
||||
public function stop(int $pull_request_id)
|
||||
{
|
||||
try {
|
||||
@ -87,6 +92,7 @@ public function stop(int $pull_request_id)
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function previewRefresh()
|
||||
{
|
||||
$this->application->previews->each(function ($preview) {
|
||||
|
@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Application;
|
||||
|
||||
use App\Models\Application;
|
||||
use Livewire\Component;
|
||||
|
||||
class ResourceLimits extends Component
|
||||
{
|
||||
public Application $application;
|
||||
protected $rules = [
|
||||
'application.limits_memory' => 'required|string',
|
||||
'application.limits_memory_swap' => 'required|string',
|
||||
'application.limits_memory_swappiness' => 'required|integer|min:0|max:100',
|
||||
'application.limits_memory_reservation' => 'required|string',
|
||||
'application.limits_cpus' => 'nullable',
|
||||
'application.limits_cpuset' => 'nullable',
|
||||
'application.limits_cpu_shares' => 'nullable',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'application.limits_memory' => 'memory',
|
||||
'application.limits_memory_swap' => 'swap',
|
||||
'application.limits_memory_swappiness' => 'swappiness',
|
||||
'application.limits_memory_reservation' => 'reservation',
|
||||
'application.limits_cpus' => 'cpus',
|
||||
'application.limits_cpuset' => 'cpuset',
|
||||
'application.limits_cpu_shares' => 'cpu shares',
|
||||
];
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
if (!$this->application->limits_memory) {
|
||||
$this->application->limits_memory = "0";
|
||||
}
|
||||
if (!$this->application->limits_memory_swap) {
|
||||
$this->application->limits_memory_swap = "0";
|
||||
}
|
||||
if (!$this->application->limits_memory_swappiness) {
|
||||
$this->application->limits_memory_swappiness = "60";
|
||||
}
|
||||
if (!$this->application->limits_memory_reservation) {
|
||||
$this->application->limits_memory_reservation = "0";
|
||||
}
|
||||
if (!$this->application->limits_cpus) {
|
||||
$this->application->limits_cpus = "0";
|
||||
}
|
||||
if (!$this->application->limits_cpuset) {
|
||||
$this->application->limits_cpuset = "0";
|
||||
}
|
||||
if (!$this->application->limits_cpu_shares) {
|
||||
$this->application->limits_cpu_shares = 1024;
|
||||
}
|
||||
$this->validate();
|
||||
$this->application->save();
|
||||
$this->emit('success', 'Resource limits updated successfully.');
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,8 +3,8 @@
|
||||
namespace App\Http\Livewire\Project\Application;
|
||||
|
||||
use App\Models\Application;
|
||||
use Livewire\Component;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Rollback extends Component
|
||||
@ -16,8 +16,9 @@ class Rollback extends Component
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function rollbackImage($commit)
|
||||
{
|
||||
$deployment_uuid = new Cuid2(7);
|
||||
@ -36,6 +37,7 @@ public function rollbackImage($commit)
|
||||
'environment_name' => $this->parameters['environment_name'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function loadImages()
|
||||
{
|
||||
try {
|
||||
|
@ -21,16 +21,19 @@ class Source extends Component
|
||||
'application.git_branch' => 'branch',
|
||||
'application.git_commit_sha' => 'commit sha',
|
||||
];
|
||||
private function get_private_keys()
|
||||
{
|
||||
$this->private_keys = PrivateKey::whereTeamId(session('currentTeam')->id)->get()->reject(function ($key) {
|
||||
return $key->id == $this->application->private_key_id;
|
||||
});
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->get_private_keys();
|
||||
}
|
||||
|
||||
private function get_private_keys()
|
||||
{
|
||||
$this->private_keys = PrivateKey::whereTeamId(auth()->user()->currentTeam()->id)->get()->reject(function ($key) {
|
||||
return $key->id == $this->application->private_key_id;
|
||||
});
|
||||
}
|
||||
|
||||
public function setPrivateKey(int $private_key_id)
|
||||
{
|
||||
$this->application->private_key_id = $private_key_id;
|
||||
@ -38,6 +41,7 @@ public function setPrivateKey(int $private_key_id)
|
||||
$this->application->refresh();
|
||||
$this->get_private_keys();
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
|
83
app/Http/Livewire/Project/Database/BackupEdit.php
Normal file
83
app/Http/Livewire/Project/Database/BackupEdit.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Database;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class BackupEdit extends Component
|
||||
{
|
||||
public $backup;
|
||||
public $s3s;
|
||||
public array $parameters;
|
||||
|
||||
protected $rules = [
|
||||
'backup.enabled' => 'required|boolean',
|
||||
'backup.frequency' => 'required|string',
|
||||
'backup.number_of_backups_locally' => 'required|integer|min:1',
|
||||
'backup.save_s3' => 'required|boolean',
|
||||
'backup.s3_storage_id' => 'nullable|integer',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'backup.enabled' => 'Enabled',
|
||||
'backup.frequency' => 'Frequency',
|
||||
'backup.number_of_backups_locally' => 'Number of Backups Locally',
|
||||
'backup.save_s3' => 'Save to S3',
|
||||
'backup.s3_storage_id' => 'S3 Storage',
|
||||
];
|
||||
protected $messages = [
|
||||
'backup.s3_storage_id' => 'Select a S3 Storage',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = get_route_parameters();
|
||||
if (is_null($this->backup->s3_storage_id)) {
|
||||
$this->backup->s3_storage_id = 'default';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function delete()
|
||||
{
|
||||
// TODO: Delete backup from server and add a confirmation modal
|
||||
$this->backup->delete();
|
||||
redirect()->route('project.database.backups.all', $this->parameters);
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
try {
|
||||
$this->custom_validate();
|
||||
$this->backup->save();
|
||||
$this->backup->refresh();
|
||||
$this->emit('success', 'Backup updated successfully');
|
||||
} catch (\Exception $e) {
|
||||
$this->emit('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function custom_validate()
|
||||
{
|
||||
if (!is_numeric($this->backup->s3_storage_id)) {
|
||||
$this->backup->s3_storage_id = null;
|
||||
}
|
||||
$isValid = validate_cron_expression($this->backup->frequency);
|
||||
if (!$isValid) {
|
||||
throw new \Exception('Invalid Cron / Human expression');
|
||||
}
|
||||
$this->validate();
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
ray($this->backup->s3_storage_id);
|
||||
try {
|
||||
$this->custom_validate();
|
||||
$this->backup->save();
|
||||
$this->backup->refresh();
|
||||
$this->emit('success', 'Backup updated successfully');
|
||||
} catch (\Exception $e) {
|
||||
$this->emit('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
23
app/Http/Livewire/Project/Database/BackupExecution.php
Normal file
23
app/Http/Livewire/Project/Database/BackupExecution.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Database;
|
||||
|
||||
use App\Models\ScheduledDatabaseBackupExecution;
|
||||
use Livewire\Component;
|
||||
|
||||
class BackupExecution extends Component
|
||||
{
|
||||
public ScheduledDatabaseBackupExecution $execution;
|
||||
|
||||
public function download()
|
||||
{
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
delete_backup_locally($this->execution->filename, $this->execution->scheduledDatabaseBackup->database->destination->server);
|
||||
$this->execution->delete();
|
||||
$this->emit('success', 'Backup execution deleted successfully.');
|
||||
$this->emit('refreshBackupExecutions');
|
||||
}
|
||||
}
|
17
app/Http/Livewire/Project/Database/BackupExecutions.php
Normal file
17
app/Http/Livewire/Project/Database/BackupExecutions.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Database;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class BackupExecutions extends Component
|
||||
{
|
||||
public $backup;
|
||||
public $executions;
|
||||
protected $listeners = ['refreshBackupExecutions'];
|
||||
|
||||
public function refreshBackupExecutions(): void
|
||||
{
|
||||
$this->executions = $this->backup->executions;
|
||||
}
|
||||
}
|
18
app/Http/Livewire/Project/Database/BackupNow.php
Normal file
18
app/Http/Livewire/Project/Database/BackupNow.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Database;
|
||||
|
||||
use App\Jobs\DatabaseBackupJob;
|
||||
use Livewire\Component;
|
||||
|
||||
class BackupNow extends Component
|
||||
{
|
||||
public $backup;
|
||||
public function backup_now()
|
||||
{
|
||||
dispatch(new DatabaseBackupJob(
|
||||
backup: $this->backup
|
||||
));
|
||||
$this->emit('success', 'Backup queued. It will be available in a few minutes');
|
||||
}
|
||||
}
|
52
app/Http/Livewire/Project/Database/CreateScheduledBackup.php
Normal file
52
app/Http/Livewire/Project/Database/CreateScheduledBackup.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Database;
|
||||
|
||||
use App\Models\ScheduledDatabaseBackup;
|
||||
use Livewire\Component;
|
||||
|
||||
class CreateScheduledBackup extends Component
|
||||
{
|
||||
public $database;
|
||||
public $frequency;
|
||||
public bool $enabled = true;
|
||||
public bool $save_s3 = true;
|
||||
public $s3_storage_id;
|
||||
public $s3s;
|
||||
|
||||
protected $rules = [
|
||||
'frequency' => 'required|string',
|
||||
'save_s3' => 'required|boolean',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'frequency' => 'Backup Frequency',
|
||||
'save_s3' => 'Save to S3',
|
||||
];
|
||||
|
||||
public function submit(): void
|
||||
{
|
||||
try {
|
||||
$this->validate();
|
||||
$isValid = validate_cron_expression($this->frequency);
|
||||
if (!$isValid) {
|
||||
$this->emit('error', 'Invalid Cron / Human expression.');
|
||||
return;
|
||||
}
|
||||
ScheduledDatabaseBackup::create([
|
||||
'enabled' => true,
|
||||
'frequency' => $this->frequency,
|
||||
'save_s3' => $this->save_s3,
|
||||
's3_storage_id' => $this->s3_storage_id,
|
||||
'database_id' => $this->database->id,
|
||||
'database_type' => $this->database->getMorphClass(),
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
]);
|
||||
$this->emit('refreshScheduledBackups');
|
||||
} catch (\Exception $e) {
|
||||
general_error_handler($e, $this);
|
||||
} finally {
|
||||
$this->frequency = '';
|
||||
$this->save_s3 = true;
|
||||
}
|
||||
}
|
||||
}
|
58
app/Http/Livewire/Project/Database/Heading.php
Normal file
58
app/Http/Livewire/Project/Database/Heading.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Database;
|
||||
|
||||
use App\Actions\Database\StartPostgresql;
|
||||
use App\Jobs\ContainerStatusJob;
|
||||
use App\Notifications\Application\StatusChanged;
|
||||
use Livewire\Component;
|
||||
|
||||
class Heading extends Component
|
||||
{
|
||||
public $database;
|
||||
public array $parameters;
|
||||
|
||||
protected $listeners = ['activityFinished'];
|
||||
|
||||
public function activityFinished()
|
||||
{
|
||||
$this->database->update([
|
||||
'started_at' => now(),
|
||||
]);
|
||||
$this->emit('refresh');
|
||||
$this->check_status();
|
||||
}
|
||||
|
||||
public function check_status()
|
||||
{
|
||||
dispatch_sync(new ContainerStatusJob(
|
||||
resource: $this->database,
|
||||
container_name: generate_container_name($this->database->uuid),
|
||||
));
|
||||
$this->database->refresh();
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function stop()
|
||||
{
|
||||
remote_process(
|
||||
["docker rm -f {$this->database->uuid}"],
|
||||
$this->database->destination->server
|
||||
);
|
||||
$this->database->status = 'stopped';
|
||||
$this->database->save();
|
||||
$this->database->environment->project->team->notify(new StatusChanged($this->database));
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
if ($this->database->type() === 'standalone-postgresql') {
|
||||
$activity = resolve(StartPostgresql::class)($this->database->destination->server, $this->database);
|
||||
$this->emit('newMonitorActivity', $activity->id);
|
||||
}
|
||||
}
|
||||
}
|
47
app/Http/Livewire/Project/Database/InitScript.php
Normal file
47
app/Http/Livewire/Project/Database/InitScript.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Database;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class InitScript extends Component
|
||||
{
|
||||
public array $script;
|
||||
public int $index;
|
||||
public string|null $filename;
|
||||
public string|null $content;
|
||||
|
||||
protected $rules = [
|
||||
'filename' => 'required|string',
|
||||
'content' => 'required|string',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'filename' => 'Filename',
|
||||
'content' => 'Content',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->index = data_get($this->script, 'index');
|
||||
$this->filename = data_get($this->script, 'filename');
|
||||
$this->content = data_get($this->script, 'content');
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
try {
|
||||
$this->script['index'] = $this->index;
|
||||
$this->script['content'] = $this->content;
|
||||
$this->script['filename'] = $this->filename;
|
||||
$this->emitUp('save_init_script', $this->script);
|
||||
} catch (Exception $e) {
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$this->emitUp('delete_init_script', $this->script);
|
||||
}
|
||||
}
|
107
app/Http/Livewire/Project/Database/Postgresql/General.php
Normal file
107
app/Http/Livewire/Project/Database/Postgresql/General.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Database\Postgresql;
|
||||
|
||||
use App\Models\StandalonePostgresql;
|
||||
use Exception;
|
||||
use Livewire\Component;
|
||||
use function Aws\filter;
|
||||
|
||||
class General extends Component
|
||||
{
|
||||
public StandalonePostgresql $database;
|
||||
public string $new_filename;
|
||||
public string $new_content;
|
||||
|
||||
protected $listeners = ['refresh', 'save_init_script', 'delete_init_script'];
|
||||
|
||||
protected $rules = [
|
||||
'database.name' => 'required',
|
||||
'database.description' => 'nullable',
|
||||
'database.postgres_user' => 'required',
|
||||
'database.postgres_password' => 'required',
|
||||
'database.postgres_db' => 'required',
|
||||
'database.postgres_initdb_args' => 'nullable',
|
||||
'database.postgres_host_auth_method' => 'nullable',
|
||||
'database.init_scripts' => 'nullable',
|
||||
'database.image' => 'required',
|
||||
'database.ports_mappings' => 'nullable',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'database.name' => 'Name',
|
||||
'database.description' => 'Description',
|
||||
'database.postgres_user' => 'Postgres User',
|
||||
'database.postgres_password' => 'Postgres Password',
|
||||
'database.postgres_db' => 'Postgres DB',
|
||||
'database.postgres_initdb_args' => 'Postgres Initdb Args',
|
||||
'database.postgres_host_auth_method' => 'Postgres Host Auth Method',
|
||||
'database.init_scripts' => 'Init Scripts',
|
||||
'database.image' => 'Image',
|
||||
'database.ports_mappings' => 'Port Mapping',
|
||||
];
|
||||
|
||||
public function save_init_script($script)
|
||||
{
|
||||
$this->database->init_scripts = filter($this->database->init_scripts, fn ($s) => $s['filename'] !== $script['filename']);
|
||||
$this->database->init_scripts = array_merge($this->database->init_scripts, [$script]);
|
||||
$this->database->save();
|
||||
$this->emit('success', 'Init script saved successfully.');
|
||||
}
|
||||
|
||||
public function delete_init_script($script)
|
||||
{
|
||||
$collection = collect($this->database->init_scripts);
|
||||
$found = $collection->firstWhere('filename', $script['filename']);
|
||||
if ($found) {
|
||||
ray($collection->filter(fn ($s) => $s['filename'] !== $script['filename'])->toArray());
|
||||
$this->database->init_scripts = $collection->filter(fn ($s) => $s['filename'] !== $script['filename'])->toArray();
|
||||
$this->database->save();
|
||||
$this->refresh();
|
||||
$this->emit('success', 'Init script deleted successfully.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->database->refresh();
|
||||
}
|
||||
|
||||
public function save_new_init_script()
|
||||
{
|
||||
$this->validate([
|
||||
'new_filename' => 'required|string',
|
||||
'new_content' => 'required|string',
|
||||
]);
|
||||
$found = collect($this->database->init_scripts)->firstWhere('filename', $this->new_filename);
|
||||
if ($found) {
|
||||
$this->emit('error', 'Filename already exists.');
|
||||
return;
|
||||
}
|
||||
if (!isset($this->database->init_scripts)) {
|
||||
$this->database->init_scripts = [];
|
||||
}
|
||||
$this->database->init_scripts = array_merge($this->database->init_scripts, [
|
||||
[
|
||||
'index' => count($this->database->init_scripts),
|
||||
'filename' => $this->new_filename,
|
||||
'content' => $this->new_content,
|
||||
]
|
||||
]);
|
||||
$this->database->save();
|
||||
$this->emit('success', 'Init script added successfully.');
|
||||
$this->new_content = '';
|
||||
$this->new_filename = '';
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->validate();
|
||||
$this->database->save();
|
||||
$this->emit('success', 'Database updated successfully.');
|
||||
} catch (Exception $e) {
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
}
|
30
app/Http/Livewire/Project/Database/ScheduledBackups.php
Normal file
30
app/Http/Livewire/Project/Database/ScheduledBackups.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Database;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class ScheduledBackups extends Component
|
||||
{
|
||||
public $database;
|
||||
public $parameters;
|
||||
protected $listeners = ['refreshScheduledBackups'];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function delete($scheduled_backup_id): void
|
||||
{
|
||||
$this->database->scheduledBackups->find($scheduled_backup_id)->delete();
|
||||
$this->emit('success', 'Scheduled backup deleted successfully.');
|
||||
$this->refreshScheduledBackups();
|
||||
}
|
||||
|
||||
public function refreshScheduledBackups(): void
|
||||
{
|
||||
ray('refreshScheduledBackups');
|
||||
$this->database->refresh();
|
||||
}
|
||||
}
|
@ -12,8 +12,9 @@ class DeleteEnvironment extends Component
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$this->validate([
|
||||
|
@ -12,8 +12,9 @@ class DeleteProject extends Component
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$this->validate([
|
||||
|
@ -11,7 +11,7 @@ public function createEmptyProject()
|
||||
{
|
||||
$project = Project::create([
|
||||
'name' => generate_random_name(),
|
||||
'team_id' => session('currentTeam')->id,
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
]);
|
||||
return redirect()->route('project.show', ['project_uuid' => $project->uuid, 'environment_name' => 'production']);
|
||||
}
|
||||
|
@ -5,16 +5,14 @@
|
||||
use App\Models\Application;
|
||||
use App\Models\GithubApp;
|
||||
use App\Models\Project;
|
||||
use App\Models\Server;
|
||||
use App\Models\StandaloneDocker;
|
||||
use App\Models\SwarmDocker;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Livewire\Component;
|
||||
|
||||
class GithubPrivateRepository extends Component
|
||||
{
|
||||
public $current_step = 'github_apps';
|
||||
public $github_apps;
|
||||
public GithubApp $github_app;
|
||||
public $parameters;
|
||||
@ -29,52 +27,23 @@ class GithubPrivateRepository extends Component
|
||||
public string $selected_branch_name = 'main';
|
||||
|
||||
public string $token;
|
||||
|
||||
protected int $page = 1;
|
||||
|
||||
public $repositories;
|
||||
public int $total_repositories_count = 0;
|
||||
|
||||
public $branches;
|
||||
public int $total_branches_count = 0;
|
||||
|
||||
public int $port = 3000;
|
||||
public bool $is_static = false;
|
||||
public string|null $publish_directory = null;
|
||||
protected int $page = 1;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->query = request()->query();
|
||||
$this->repositories = $this->branches = collect();
|
||||
$this->github_apps = GithubApp::private();
|
||||
}
|
||||
protected function loadRepositoryByPage()
|
||||
{
|
||||
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/installation/repositories?per_page=100&page={$this->page}");
|
||||
$json = $response->json();
|
||||
if ($response->status() !== 200) {
|
||||
return $this->emit('error', $json['message']);
|
||||
}
|
||||
|
||||
if ($json['total_count'] === 0) {
|
||||
return;
|
||||
}
|
||||
$this->total_repositories_count = $json['total_count'];
|
||||
$this->repositories = $this->repositories->concat(collect($json['repositories']));
|
||||
}
|
||||
protected function loadBranchByPage()
|
||||
{
|
||||
Log::info('Loading page ' . $this->page);
|
||||
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/repos/{$this->selected_repository_owner}/{$this->selected_repository_repo}/branches?per_page=100&page={$this->page}");
|
||||
$json = $response->json();
|
||||
if ($response->status() !== 200) {
|
||||
return $this->emit('error', $json['message']);
|
||||
}
|
||||
|
||||
$this->total_branches_count = count($json);
|
||||
$this->branches = $this->branches->concat(collect($json));
|
||||
}
|
||||
public function loadRepositories($github_app_id)
|
||||
{
|
||||
$this->repositories = collect();
|
||||
@ -90,7 +59,24 @@ public function loadRepositories($github_app_id)
|
||||
}
|
||||
}
|
||||
$this->selected_repository_id = $this->repositories[0]['id'];
|
||||
$this->current_step = 'repository';
|
||||
}
|
||||
|
||||
protected function loadRepositoryByPage()
|
||||
{
|
||||
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/installation/repositories?per_page=100&page={$this->page}");
|
||||
$json = $response->json();
|
||||
if ($response->status() !== 200) {
|
||||
return $this->emit('error', $json['message']);
|
||||
}
|
||||
|
||||
if ($json['total_count'] === 0) {
|
||||
return;
|
||||
}
|
||||
$this->total_repositories_count = $json['total_count'];
|
||||
$this->repositories = $this->repositories->concat(collect($json['repositories']));
|
||||
}
|
||||
|
||||
public function loadBranches()
|
||||
{
|
||||
$this->selected_repository_owner = $this->repositories->where('id', $this->selected_repository_id)->first()['owner']['login'];
|
||||
@ -105,6 +91,20 @@ public function loadBranches()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadBranchByPage()
|
||||
{
|
||||
ray('Loading page ' . $this->page);
|
||||
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/repos/{$this->selected_repository_owner}/{$this->selected_repository_repo}/branches?per_page=100&page={$this->page}");
|
||||
$json = $response->json();
|
||||
if ($response->status() !== 200) {
|
||||
return $this->emit('error', $json['message']);
|
||||
}
|
||||
|
||||
$this->total_branches_count = count($json);
|
||||
$this->branches = $this->branches->concat(collect($json));
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
@ -134,7 +134,7 @@ public function submit()
|
||||
'destination_id' => $destination->id,
|
||||
'destination_type' => $destination_class,
|
||||
'source_id' => $this->github_app->id,
|
||||
'source_type' => $this->github_app->getMorphClass()
|
||||
'source_type' => $this->github_app->getMorphClass()
|
||||
]);
|
||||
$application->settings->is_static = $this->is_static;
|
||||
$application->settings->save();
|
||||
@ -148,6 +148,7 @@ public function submit()
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
if ($this->is_static) {
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
class GithubPrivateRepositoryDeployKey extends Component
|
||||
{
|
||||
public $current_step = 'private_keys';
|
||||
public $parameters;
|
||||
public $query;
|
||||
public $private_keys;
|
||||
@ -26,14 +27,7 @@ class GithubPrivateRepositoryDeployKey extends Component
|
||||
public null|string $publish_directory = null;
|
||||
|
||||
public string $repository_url;
|
||||
private object $repository_url_parsed;
|
||||
public string $branch;
|
||||
|
||||
private GithubApp|GitlabApp $git_source;
|
||||
private string $git_host;
|
||||
private string $git_repository;
|
||||
private string $git_branch;
|
||||
|
||||
protected $rules = [
|
||||
'repository_url' => 'required|url',
|
||||
'branch' => 'required|string',
|
||||
@ -48,15 +42,22 @@ class GithubPrivateRepositoryDeployKey extends Component
|
||||
'is_static' => 'Is static',
|
||||
'publish_directory' => 'Publish directory',
|
||||
];
|
||||
private object $repository_url_parsed;
|
||||
private GithubApp|GitlabApp $git_source;
|
||||
private string $git_host;
|
||||
private string $git_repository;
|
||||
private string $git_branch;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (isDev()) {
|
||||
if (is_dev()) {
|
||||
$this->repository_url = 'https://github.com/coollabsio/coolify-examples';
|
||||
}
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->query = request()->query();
|
||||
$this->private_keys = PrivateKey::where('team_id', session('currentTeam')->id)->where('id', '!=', 0)->get();
|
||||
$this->private_keys = PrivateKey::where('team_id', auth()->user()->currentTeam()->id)->where('id', '!=', 0)->get();
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
if ($this->is_static) {
|
||||
@ -67,29 +68,13 @@ public function instantSave()
|
||||
$this->publish_directory = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function setPrivateKey($private_key_id)
|
||||
{
|
||||
$this->private_key_id = $private_key_id;
|
||||
$this->current_step = 'repository';
|
||||
}
|
||||
private function get_git_source()
|
||||
{
|
||||
$this->repository_url_parsed = Url::fromString($this->repository_url);
|
||||
$this->git_host = $this->repository_url_parsed->getHost();
|
||||
$this->git_repository = $this->repository_url_parsed->getSegment(1) . '/' . $this->repository_url_parsed->getSegment(2);
|
||||
if ($this->branch) {
|
||||
$this->git_branch = $this->branch;
|
||||
} else {
|
||||
$this->git_branch = $this->repository_url_parsed->getSegment(4) ?? 'main';
|
||||
}
|
||||
|
||||
if ($this->git_host == 'github.com') {
|
||||
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
|
||||
} elseif ($this->git_host == 'gitlab.com') {
|
||||
$this->git_source = GitlabApp::where('name', 'Public GitLab')->first();
|
||||
} elseif ($this->git_host == 'bitbucket.org') {
|
||||
// Not supported yet
|
||||
}
|
||||
}
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
@ -121,7 +106,7 @@ public function submit()
|
||||
'destination_type' => $destination_class,
|
||||
'private_key_id' => $this->private_key_id,
|
||||
'source_id' => $this->git_source->id,
|
||||
'source_type' => $this->git_source->getMorphClass()
|
||||
'source_type' => $this->git_source->getMorphClass()
|
||||
];
|
||||
$application = Application::create($application_init);
|
||||
$application->settings->is_static = $this->is_static;
|
||||
@ -136,4 +121,24 @@ public function submit()
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
private function get_git_source()
|
||||
{
|
||||
$this->repository_url_parsed = Url::fromString($this->repository_url);
|
||||
$this->git_host = $this->repository_url_parsed->getHost();
|
||||
$this->git_repository = $this->repository_url_parsed->getSegment(1) . '/' . $this->repository_url_parsed->getSegment(2);
|
||||
if ($this->branch) {
|
||||
$this->git_branch = $this->branch;
|
||||
} else {
|
||||
$this->git_branch = $this->repository_url_parsed->getSegment(4) ?? 'main';
|
||||
}
|
||||
|
||||
if ($this->git_host == 'github.com') {
|
||||
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
|
||||
} elseif ($this->git_host == 'gitlab.com') {
|
||||
$this->git_source = GitlabApp::where('name', 'Public GitLab')->first();
|
||||
} elseif ($this->git_host == 'bitbucket.org') {
|
||||
// Not supported yet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,13 +15,10 @@
|
||||
class PublicGitRepository extends Component
|
||||
{
|
||||
public string $repository_url;
|
||||
private object $repository_url_parsed;
|
||||
|
||||
public int $port = 3000;
|
||||
public string $type;
|
||||
public $parameters;
|
||||
public $query;
|
||||
|
||||
public bool $branch_found = false;
|
||||
public string $selected_branch = 'main';
|
||||
public bool $is_static = false;
|
||||
@ -29,11 +26,6 @@ class PublicGitRepository extends Component
|
||||
public string $git_branch = 'main';
|
||||
public int $rate_limit_remaining = 0;
|
||||
public $rate_limit_reset = 0;
|
||||
|
||||
private GithubApp|GitlabApp $git_source;
|
||||
private string $git_host;
|
||||
private string $git_repository;
|
||||
|
||||
protected $rules = [
|
||||
'repository_url' => 'required|url',
|
||||
'port' => 'required|numeric',
|
||||
@ -46,13 +38,18 @@ class PublicGitRepository extends Component
|
||||
'is_static' => 'static',
|
||||
'publish_directory' => 'publish directory',
|
||||
];
|
||||
private object $repository_url_parsed;
|
||||
private GithubApp|GitlabApp $git_source;
|
||||
private string $git_host;
|
||||
private string $git_repository;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (isDev()) {
|
||||
if (is_dev()) {
|
||||
$this->repository_url = 'https://github.com/coollabsio/coolify-examples';
|
||||
$this->port = 3000;
|
||||
}
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->query = request()->query();
|
||||
}
|
||||
|
||||
@ -67,12 +64,7 @@ public function instantSave()
|
||||
}
|
||||
$this->emit('success', 'Application settings updated!');
|
||||
}
|
||||
private function get_branch()
|
||||
{
|
||||
['rate_limit_remaining' => $this->rate_limit_remaining, 'rate_limit_reset' => $this->rate_limit_reset] = git_api(source: $this->git_source, endpoint: "/repos/{$this->git_repository}/branches/{$this->git_branch}");
|
||||
$this->rate_limit_reset = Carbon::parse((int)$this->rate_limit_reset)->format('Y-M-d H:i:s');
|
||||
$this->branch_found = true;
|
||||
}
|
||||
|
||||
public function load_branch()
|
||||
{
|
||||
$this->branch_found = false;
|
||||
@ -82,7 +74,9 @@ public function load_branch()
|
||||
$this->get_git_source();
|
||||
try {
|
||||
$this->get_branch();
|
||||
$this->selected_branch = $this->git_branch;
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
|
||||
if (!$this->branch_found && $this->git_branch == 'main') {
|
||||
@ -94,6 +88,7 @@ public function load_branch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_git_source()
|
||||
{
|
||||
$this->repository_url_parsed = Url::fromString($this->repository_url);
|
||||
@ -109,6 +104,14 @@ private function get_git_source()
|
||||
// Not supported yet
|
||||
}
|
||||
}
|
||||
|
||||
private function get_branch()
|
||||
{
|
||||
['rate_limit_remaining' => $this->rate_limit_remaining, 'rate_limit_reset' => $this->rate_limit_reset] = git_api(source: $this->git_source, endpoint: "/repos/{$this->git_repository}/branches/{$this->git_branch}");
|
||||
$this->rate_limit_reset = Carbon::parse((int)$this->rate_limit_reset)->format('Y-M-d H:i:s');
|
||||
$this->branch_found = true;
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
|
51
app/Http/Livewire/Project/New/Select.php
Normal file
51
app/Http/Livewire/Project/New/Select.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\New;
|
||||
|
||||
use App\Models\Server;
|
||||
use Livewire\Component;
|
||||
|
||||
class Select extends Component
|
||||
{
|
||||
public $current_step = 'type';
|
||||
public string $type;
|
||||
public string $server_id;
|
||||
public string $destination_uuid;
|
||||
public $servers = [];
|
||||
public $destinations = [];
|
||||
public array $parameters;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function set_type(string $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->current_step = 'servers';
|
||||
}
|
||||
|
||||
public function set_server(Server $server)
|
||||
{
|
||||
$this->server_id = $server->id;
|
||||
$this->destinations = $server->destinations();
|
||||
$this->current_step = 'destinations';
|
||||
}
|
||||
|
||||
public function set_destination(string $destination_uuid)
|
||||
{
|
||||
$this->destination_uuid = $destination_uuid;
|
||||
redirect()->route('project.resources.new', [
|
||||
'project_uuid' => $this->parameters['project_uuid'],
|
||||
'environment_name' => $this->parameters['environment_name'],
|
||||
'type' => $this->type,
|
||||
'destination' => $this->destination_uuid,
|
||||
]);
|
||||
}
|
||||
|
||||
public function load_servers()
|
||||
{
|
||||
$this->servers = Server::ownedByCurrentTeam()->get();
|
||||
}
|
||||
}
|
68
app/Http/Livewire/Project/New/SimpleDockerfile.php
Normal file
68
app/Http/Livewire/Project/New/SimpleDockerfile.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\New;
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\GithubApp;
|
||||
use App\Models\Project;
|
||||
use App\Models\StandaloneDocker;
|
||||
use App\Models\SwarmDocker;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class SimpleDockerfile extends Component
|
||||
{
|
||||
public string $dockerfile = '';
|
||||
public array $parameters;
|
||||
public array $query;
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->query = request()->query();
|
||||
if (is_dev()) {
|
||||
$this->dockerfile = 'FROM nginx
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
';
|
||||
}
|
||||
}
|
||||
public function submit()
|
||||
{
|
||||
$this->validate([
|
||||
'dockerfile' => 'required'
|
||||
]);
|
||||
$destination_uuid = $this->query['destination'];
|
||||
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
|
||||
if (!$destination) {
|
||||
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
|
||||
}
|
||||
if (!$destination) {
|
||||
throw new \Exception('Destination not found. What?!');
|
||||
}
|
||||
$destination_class = $destination->getMorphClass();
|
||||
|
||||
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
||||
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
||||
|
||||
$port = get_port_from_dockerfile($this->dockerfile);
|
||||
$application = Application::create([
|
||||
'name' => 'dockerfile-' . new Cuid2(7),
|
||||
'repository_project_id' => 0,
|
||||
'git_repository' => "coollabsio/coolify",
|
||||
'git_branch' => 'main',
|
||||
'build_pack' => 'dockerfile',
|
||||
'dockerfile' => $this->dockerfile,
|
||||
'ports_exposes' => $port,
|
||||
'environment_id' => $environment->id,
|
||||
'destination_id' => $destination->id,
|
||||
'destination_type' => $destination_class,
|
||||
'source_id' => 0,
|
||||
'source_type' => GithubApp::class
|
||||
]);
|
||||
redirect()->route('project.application.configuration', [
|
||||
'application_uuid' => $application->uuid,
|
||||
'environment_name' => $environment->name,
|
||||
'project_uuid' => $project->uuid,
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,28 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Application;
|
||||
namespace App\Http\Livewire\Project\Shared;
|
||||
|
||||
use App\Models\Application;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Danger extends Component
|
||||
{
|
||||
public Application $application;
|
||||
public $resource;
|
||||
public array $parameters;
|
||||
public string|null $modalId = null;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->modalId = new Cuid2(7);
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first();
|
||||
$destination = $this->resource->destination->getMorphClass()::where('id', $this->resource->destination->id)->first();
|
||||
|
||||
instant_remote_process(["docker rm -f {$this->application->uuid}"], $destination->server);
|
||||
$this->application->delete();
|
||||
instant_remote_process(["docker rm -f {$this->resource->uuid}"], $destination->server);
|
||||
$this->resource->delete();
|
||||
return redirect()->route('project.resources', [
|
||||
'project_uuid' => $this->parameters['project_uuid'],
|
||||
'environment_name' => $this->parameters['environment_name']
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Application;
|
||||
namespace App\Http\Livewire\Project\Shared;
|
||||
|
||||
use Livewire\Component;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Application\EnvironmentVariable;
|
||||
namespace App\Http\Livewire\Project\Shared\EnvironmentVariable;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
@ -23,10 +23,12 @@ class Add extends Component
|
||||
'value' => 'value',
|
||||
'is_build_time' => 'build',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
ray('submitting');
|
||||
@ -39,6 +41,7 @@ public function submit()
|
||||
]);
|
||||
$this->clear();
|
||||
}
|
||||
|
||||
public function clear()
|
||||
{
|
||||
$this->key = '';
|
52
app/Http/Livewire/Project/Shared/EnvironmentVariable/All.php
Normal file
52
app/Http/Livewire/Project/Shared/EnvironmentVariable/All.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Shared\EnvironmentVariable;
|
||||
|
||||
use App\Models\EnvironmentVariable;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class All extends Component
|
||||
{
|
||||
public $resource;
|
||||
public string|null $modalId = null;
|
||||
protected $listeners = ['refreshEnvs', 'submit'];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->modalId = new Cuid2(7);
|
||||
}
|
||||
|
||||
public function refreshEnvs()
|
||||
{
|
||||
$this->resource->refresh();
|
||||
}
|
||||
|
||||
public function submit($data)
|
||||
{
|
||||
try {
|
||||
$found = $this->resource->environment_variables()->where('key', $data['key'])->first();
|
||||
if ($found) {
|
||||
$this->emit('error', 'Environment variable already exists.');
|
||||
return;
|
||||
}
|
||||
$environment = new EnvironmentVariable();
|
||||
$environment->key = $data['key'];
|
||||
$environment->value = $data['value'];
|
||||
$environment->is_build_time = $data['is_build_time'];
|
||||
$environment->is_preview = $data['is_preview'];
|
||||
|
||||
if ($this->resource->type() === 'application') {
|
||||
$environment->application_id = $this->resource->id;
|
||||
}
|
||||
if ($this->resource->type() === 'standalone-postgresql') {
|
||||
$environment->standalone_postgresql_id = $this->resource->id;
|
||||
}
|
||||
$environment->save();
|
||||
$this->resource->refresh();
|
||||
$this->emit('success', 'Environment variable added successfully.');
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Application\EnvironmentVariable;
|
||||
namespace App\Http\Livewire\Project\Shared\EnvironmentVariable;
|
||||
|
||||
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
|
||||
use Livewire\Component;
|
||||
@ -21,10 +21,16 @@ class Show extends Component
|
||||
'value' => 'value',
|
||||
'is_build_time' => 'build',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->modalId = new Cuid2(7);
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
$this->submit();
|
||||
}
|
||||
public function submit()
|
||||
{
|
||||
@ -32,6 +38,7 @@ public function submit()
|
||||
$this->env->save();
|
||||
$this->emit('success', 'Environment variable updated successfully.');
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$this->env->delete();
|
60
app/Http/Livewire/Project/Shared/ResourceLimits.php
Normal file
60
app/Http/Livewire/Project/Shared/ResourceLimits.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Shared;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class ResourceLimits extends Component
|
||||
{
|
||||
public $resource;
|
||||
protected $rules = [
|
||||
'resource.limits_memory' => 'required|string',
|
||||
'resource.limits_memory_swap' => 'required|string',
|
||||
'resource.limits_memory_swappiness' => 'required|integer|min:0|max:100',
|
||||
'resource.limits_memory_reservation' => 'required|string',
|
||||
'resource.limits_cpus' => 'nullable',
|
||||
'resource.limits_cpuset' => 'nullable',
|
||||
'resource.limits_cpu_shares' => 'nullable',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'resource.limits_memory' => 'memory',
|
||||
'resource.limits_memory_swap' => 'swap',
|
||||
'resource.limits_memory_swappiness' => 'swappiness',
|
||||
'resource.limits_memory_reservation' => 'reservation',
|
||||
'resource.limits_cpus' => 'cpus',
|
||||
'resource.limits_cpuset' => 'cpuset',
|
||||
'resource.limits_cpu_shares' => 'cpu shares',
|
||||
];
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
if (!$this->resource->limits_memory) {
|
||||
$this->resource->limits_memory = "0";
|
||||
}
|
||||
if (!$this->resource->limits_memory_swap) {
|
||||
$this->resource->limits_memory_swap = "0";
|
||||
}
|
||||
if (!$this->resource->limits_memory_swappiness) {
|
||||
$this->resource->limits_memory_swappiness = "60";
|
||||
}
|
||||
if (!$this->resource->limits_memory_reservation) {
|
||||
$this->resource->limits_memory_reservation = "0";
|
||||
}
|
||||
if (!$this->resource->limits_cpus) {
|
||||
$this->resource->limits_cpus = "0";
|
||||
}
|
||||
if (!$this->resource->limits_cpuset) {
|
||||
$this->resource->limits_cpuset = "0";
|
||||
}
|
||||
if (!$this->resource->limits_cpu_shares) {
|
||||
$this->resource->limits_cpu_shares = 1024;
|
||||
}
|
||||
$this->validate();
|
||||
$this->resource->save();
|
||||
$this->emit('success', 'Resource limits updated successfully.');
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Application\Storages;
|
||||
namespace App\Http\Livewire\Project\Shared\Storages;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
@ -22,10 +22,12 @@ class Add extends Component
|
||||
'mount_path' => 'mount',
|
||||
'host_path' => 'host',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
@ -35,6 +37,7 @@ public function submit()
|
||||
'host_path' => $this->host_path,
|
||||
]);
|
||||
}
|
||||
|
||||
public function clear()
|
||||
{
|
||||
$this->name = '';
|
@ -1,19 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Application\Storages;
|
||||
namespace App\Http\Livewire\Project\Shared\Storages;
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\LocalPersistentVolume;
|
||||
use Livewire\Component;
|
||||
|
||||
class All extends Component
|
||||
{
|
||||
public Application $application;
|
||||
public $resource;
|
||||
protected $listeners = ['refreshStorages', 'submit'];
|
||||
|
||||
public function refreshStorages()
|
||||
{
|
||||
$this->application->refresh();
|
||||
$this->resource->refresh();
|
||||
}
|
||||
|
||||
public function submit($data)
|
||||
{
|
||||
try {
|
||||
@ -21,10 +22,10 @@ public function submit($data)
|
||||
'name' => $data['name'],
|
||||
'mount_path' => $data['mount_path'],
|
||||
'host_path' => $data['host_path'],
|
||||
'resource_id' => $this->application->id,
|
||||
'resource_type' => Application::class,
|
||||
'resource_id' => $this->resource->id,
|
||||
'resource_type' => $this->resource->getMorphClass(),
|
||||
]);
|
||||
$this->application->refresh();
|
||||
$this->resource->refresh();
|
||||
$this->emit('success', 'Storage added successfully');
|
||||
$this->emit('clearAddStorage');
|
||||
} catch (\Exception $e) {
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\Application\Storages;
|
||||
namespace App\Http\Livewire\Project\Shared\Storages;
|
||||
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
@ -19,16 +19,19 @@ class Show extends Component
|
||||
'mount_path' => 'mount',
|
||||
'host_path' => 'host',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->modalId = new Cuid2(7);
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
$this->storage->save();
|
||||
$this->emit('success', 'Storage updated successfully');
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$this->storage->delete();
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Enums\ActivityTypes;
|
||||
use App\Models\Server;
|
||||
use Livewire\Component;
|
||||
|
||||
@ -20,6 +19,7 @@ class RunCommand extends Component
|
||||
'server' => 'server',
|
||||
'command' => 'command',
|
||||
];
|
||||
|
||||
public function mount($servers)
|
||||
{
|
||||
$this->servers = $servers;
|
||||
|
@ -5,7 +5,6 @@
|
||||
use App\Actions\Server\InstallDocker;
|
||||
use App\Models\Server;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Form extends Component
|
||||
{
|
||||
@ -14,7 +13,6 @@ class Form extends Component
|
||||
public $dockerVersion;
|
||||
public string|null $wildcard_domain = null;
|
||||
public int $cleanup_after_percentage;
|
||||
public string|null $modalId = null;
|
||||
|
||||
protected $rules = [
|
||||
'server.name' => 'required|min:6',
|
||||
@ -35,43 +33,35 @@ class Form extends Component
|
||||
'server.settings.is_reachable' => 'is reachable',
|
||||
'server.settings.is_part_of_swarm' => 'is part of swarm'
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->modalId = new Cuid2(7);
|
||||
$this->wildcard_domain = $this->server->settings->wildcard_domain;
|
||||
$this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage;
|
||||
}
|
||||
|
||||
public function installDocker()
|
||||
{
|
||||
$activity = resolve(InstallDocker::class)($this->server, session('currentTeam'));
|
||||
$activity = resolve(InstallDocker::class)($this->server, auth()->user()->currentTeam());
|
||||
$this->emit('newMonitorActivity', $activity->id);
|
||||
}
|
||||
|
||||
public function validateServer()
|
||||
{
|
||||
try {
|
||||
$this->uptime = instant_remote_process(['uptime'], $this->server);
|
||||
if ($this->uptime) {
|
||||
$this->server->settings->is_reachable = true;
|
||||
$this->server->settings->save();
|
||||
} else {
|
||||
$this->uptime = 'Server not reachable.';
|
||||
throw new \Exception('Server not reachable.');
|
||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
|
||||
if ($uptime) {
|
||||
$this->uptime = $uptime;
|
||||
}
|
||||
$this->dockerVersion = instant_remote_process(['docker version|head -2|grep -i version'], $this->server, false);
|
||||
if (!$this->dockerVersion) {
|
||||
$this->dockerVersion = 'Not installed.';
|
||||
} else {
|
||||
$this->server->settings->is_usable = true;
|
||||
$this->server->settings->save();
|
||||
if ($dockerVersion) {
|
||||
$this->dockerVersion = $dockerVersion;
|
||||
$this->emit('proxyStatusUpdated');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->server->settings->is_reachable = false;
|
||||
$this->server->settings->is_usable = false;
|
||||
$this->server->settings->save();
|
||||
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
if (!$this->server->isEmpty()) {
|
||||
@ -81,6 +71,7 @@ public function delete()
|
||||
$this->server->delete();
|
||||
redirect()->route('server.all');
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
namespace App\Http\Livewire\Server\New;
|
||||
|
||||
use App\Models\PrivateKey;
|
||||
use App\Models\Server;
|
||||
use Livewire\Component;
|
||||
|
||||
class ByIp extends Component
|
||||
{
|
||||
public $private_keys;
|
||||
public $limit_reached;
|
||||
public int|null $private_key_id = null;
|
||||
public $new_private_key_name;
|
||||
public $new_private_key_description;
|
||||
@ -35,19 +35,23 @@ class ByIp extends Component
|
||||
'user' => 'user',
|
||||
'port' => 'port',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->name = generate_random_name();
|
||||
$this->private_key_id = $this->private_keys->first()->id;
|
||||
}
|
||||
|
||||
public function setPrivateKey(string $private_key_id)
|
||||
{
|
||||
$this->private_key_id = $private_key_id;
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
$this->emit('success', 'Application settings updated!');
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
@ -61,7 +65,7 @@ public function submit()
|
||||
'ip' => $this->ip,
|
||||
'user' => $this->user,
|
||||
'port' => $this->port,
|
||||
'team_id' => session('currentTeam')->id,
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
'private_key_id' => $this->private_key_id,
|
||||
]);
|
||||
$server->settings->is_part_of_swarm = $this->is_part_of_swarm;
|
||||
|
@ -3,7 +3,6 @@
|
||||
namespace App\Http\Livewire\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Livewire\Component;
|
||||
use Masmerise\Toaster\Toaster;
|
||||
|
||||
@ -13,35 +12,33 @@ class PrivateKey extends Component
|
||||
public $privateKeys;
|
||||
public $parameters;
|
||||
|
||||
public function checkConnection()
|
||||
{
|
||||
try {
|
||||
$uptime = instant_remote_process(['uptime'], $this->server);
|
||||
if ($uptime) {
|
||||
Toaster::success('Server is reachable with this private key.');
|
||||
$this->server->settings->is_reachable = true;
|
||||
$this->server->settings->is_usable = true;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->server->settings->is_reachable = false;
|
||||
$this->server->settings->is_usable = false;
|
||||
$this->server->settings->save();
|
||||
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
||||
}
|
||||
}
|
||||
public function setPrivateKey($private_key_id)
|
||||
{
|
||||
$this->server->update([
|
||||
'private_key_id' => $private_key_id
|
||||
]);
|
||||
|
||||
// Delete the old ssh mux file to force a new one to be created
|
||||
Storage::disk('ssh-mux')->delete($this->server->muxFilename());
|
||||
refreshPrivateKey($this->server->privateKey);
|
||||
$this->server->refresh();
|
||||
$this->checkConnection();
|
||||
}
|
||||
|
||||
public function checkConnection()
|
||||
{
|
||||
try {
|
||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server);
|
||||
if ($uptime) {
|
||||
Toaster::success('Server is reachable with this private key.');
|
||||
}
|
||||
if ($dockerVersion) {
|
||||
Toaster::success('Server is usable for Coolify.');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
namespace App\Http\Livewire\Server;
|
||||
|
||||
use App\Actions\Proxy\CheckProxySettingsInSync;
|
||||
use App\Actions\Proxy\CheckConfigurationSync;
|
||||
use App\Actions\Proxy\SaveConfigurationSync;
|
||||
use App\Enums\ProxyTypes;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\Server;
|
||||
use Livewire\Component;
|
||||
|
||||
@ -16,69 +16,61 @@ class Proxy extends Component
|
||||
public $proxy_settings = null;
|
||||
public string|null $redirect_url = null;
|
||||
|
||||
protected $listeners = ['proxyStatusUpdated', 'saveConfiguration'];
|
||||
protected $listeners = ['proxyStatusUpdated', 'saveConfiguration' => 'submit'];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->redirect_url = $this->server->proxy->redirect_url;
|
||||
}
|
||||
|
||||
public function proxyStatusUpdated()
|
||||
{
|
||||
$this->server->refresh();
|
||||
}
|
||||
public function switchProxy()
|
||||
|
||||
public function change_proxy()
|
||||
{
|
||||
$this->server->proxy = null;
|
||||
$this->server->save();
|
||||
$this->emit('proxyStatusUpdated');
|
||||
}
|
||||
public function setProxy(string $proxy_type)
|
||||
|
||||
public function select_proxy(string $proxy_type)
|
||||
{
|
||||
$this->server->proxy->type = $proxy_type;
|
||||
$this->server->proxy->status = 'exited';
|
||||
$this->server->save();
|
||||
$this->emit('proxyStatusUpdated');
|
||||
}
|
||||
public function stopProxy()
|
||||
{
|
||||
instant_remote_process([
|
||||
"docker rm -f coolify-proxy",
|
||||
], $this->server);
|
||||
$this->server->proxy->status = 'exited';
|
||||
$this->server->save();
|
||||
$this->emit('proxyStatusUpdated');
|
||||
}
|
||||
public function saveConfiguration()
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$proxy_path = config('coolify.proxy_config_path');
|
||||
$this->proxy_settings = Str::of($this->proxy_settings)->trim()->value;
|
||||
$docker_compose_yml_base64 = base64_encode($this->proxy_settings);
|
||||
$this->server->proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
||||
resolve(SaveConfigurationSync::class)($this->server, $this->proxy_settings);
|
||||
|
||||
$this->server->proxy->redirect_url = $this->redirect_url;
|
||||
$this->server->save();
|
||||
|
||||
instant_remote_process([
|
||||
"echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
|
||||
], $this->server);
|
||||
$this->server->refresh();
|
||||
setup_default_redirect_404(redirect_url: $this->server->proxy->redirect_url, server: $this->server);
|
||||
$this->emit('success', 'Proxy configuration saved.');
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e);
|
||||
}
|
||||
}
|
||||
public function resetProxy()
|
||||
|
||||
public function reset_proxy_configuration()
|
||||
{
|
||||
try {
|
||||
$this->proxy_settings = resolve(CheckProxySettingsInSync::class)($this->server, true);
|
||||
$this->proxy_settings = resolve(CheckConfigurationSync::class)($this->server, true);
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e);
|
||||
}
|
||||
}
|
||||
public function checkProxySettingsInSync()
|
||||
|
||||
public function load_proxy_configuration()
|
||||
{
|
||||
try {
|
||||
$this->proxy_settings = resolve(CheckProxySettingsInSync::class)($this->server);
|
||||
$this->proxy_settings = resolve(CheckConfigurationSync::class)($this->server);
|
||||
} catch (\Exception $e) {
|
||||
return general_error_handler(err: $e);
|
||||
}
|
||||
|
@ -5,28 +5,24 @@
|
||||
use App\Actions\Proxy\StartProxy;
|
||||
use App\Models\Server;
|
||||
use Livewire\Component;
|
||||
use Str;
|
||||
|
||||
class Deploy extends Component
|
||||
{
|
||||
public Server $server;
|
||||
public $proxy_settings = null;
|
||||
protected $listeners = ['proxyStatusUpdated'];
|
||||
public function proxyStatusUpdated()
|
||||
{
|
||||
$this->server->refresh();
|
||||
}
|
||||
public function deploy()
|
||||
|
||||
public function start_proxy()
|
||||
{
|
||||
if (
|
||||
$this->server->proxy->last_applied_settings &&
|
||||
$this->server->proxy->last_saved_settings !== $this->server->proxy->last_applied_settings
|
||||
) {
|
||||
$this->saveConfiguration($this->server);
|
||||
$this->emit('saveConfiguration', $server);
|
||||
}
|
||||
$activity = resolve(StartProxy::class)($this->server);
|
||||
$this->emit('newMonitorActivity', $activity->id);
|
||||
}
|
||||
|
||||
public function stop()
|
||||
{
|
||||
instant_remote_process([
|
||||
@ -36,8 +32,4 @@ public function stop()
|
||||
$this->server->save();
|
||||
$this->emit('proxyStatusUpdated');
|
||||
}
|
||||
private function saveConfiguration(Server $server)
|
||||
{
|
||||
$this->emit('saveConfiguration', $server);
|
||||
}
|
||||
}
|
||||
|
@ -9,20 +9,13 @@
|
||||
class Status extends Component
|
||||
{
|
||||
public Server $server;
|
||||
protected $listeners = ['proxyStatusUpdated'];
|
||||
public function proxyStatusUpdated()
|
||||
|
||||
public function get_status()
|
||||
{
|
||||
dispatch_sync(new ProxyContainerStatusJob(
|
||||
server: $this->server
|
||||
));
|
||||
$this->server->refresh();
|
||||
}
|
||||
public function proxyStatus()
|
||||
{
|
||||
try {
|
||||
dispatch_sync(new ProxyContainerStatusJob(
|
||||
server: $this->server
|
||||
));
|
||||
$this->emit('proxyStatusUpdated');
|
||||
} catch (\Exception $e) {
|
||||
ray($e->getMessage());
|
||||
}
|
||||
$this->emit('proxyStatusUpdated');
|
||||
}
|
||||
}
|
||||
|
87
app/Http/Livewire/Settings/Backup.php
Normal file
87
app/Http/Livewire/Settings/Backup.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Settings;
|
||||
|
||||
use App\Jobs\DatabaseBackupJob;
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\S3Storage;
|
||||
use App\Models\ScheduledDatabaseBackup;
|
||||
use App\Models\Server;
|
||||
use App\Models\StandalonePostgresql;
|
||||
use Livewire\Component;
|
||||
|
||||
class Backup extends Component
|
||||
{
|
||||
public InstanceSettings $settings;
|
||||
public $s3s;
|
||||
public StandalonePostgresql|null|array $database = [];
|
||||
public ScheduledDatabaseBackup|null|array $backup = [];
|
||||
public $executions = [];
|
||||
|
||||
protected $rules = [
|
||||
'database.uuid' => 'required',
|
||||
'database.name' => 'required',
|
||||
'database.description' => 'nullable',
|
||||
'database.postgres_user' => 'required',
|
||||
'database.postgres_password' => 'required',
|
||||
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'database.uuid' => 'uuid',
|
||||
'database.name' => 'name',
|
||||
'database.description' => 'description',
|
||||
'database.postgres_user' => 'postgres user',
|
||||
'database.postgres_password' => 'postgres password',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->backup = $this->database?->scheduledBackups->first() ?? [];
|
||||
$this->executions = $this->backup?->executions ?? [];
|
||||
}
|
||||
public function add_coolify_database()
|
||||
{
|
||||
$server = Server::find(0);
|
||||
$out = instant_remote_process(['docker inspect coolify-db'], $server);
|
||||
$envs = format_docker_envs_to_json($out);
|
||||
$postgres_password = $envs['POSTGRES_PASSWORD'];
|
||||
$postgres_user = $envs['POSTGRES_USER'];
|
||||
$postgres_db = $envs['POSTGRES_DB'];
|
||||
$this->database = StandalonePostgresql::create([
|
||||
'id' => 0,
|
||||
'name' => 'coolify-db',
|
||||
'description' => 'Coolify database',
|
||||
'postgres_user' => $postgres_user,
|
||||
'postgres_password' => $postgres_password,
|
||||
'postgres_db' => $postgres_db,
|
||||
'status' => 'running',
|
||||
'destination_type' => 'App\Models\StandaloneDocker',
|
||||
'destination_id' => 0,
|
||||
]);
|
||||
$this->backup = ScheduledDatabaseBackup::create([
|
||||
'id' => 0,
|
||||
'enabled' => true,
|
||||
'save_s3' => false,
|
||||
'frequency' => '0 0 * * *',
|
||||
'database_id' => $this->database->id,
|
||||
'database_type' => 'App\Models\StandalonePostgresql',
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
]);
|
||||
$this->database->refresh();
|
||||
$this->backup->refresh();
|
||||
ray($this->backup);
|
||||
$this->s3s = S3Storage::whereTeamId(0)->get();
|
||||
}
|
||||
|
||||
public function backup_now()
|
||||
{
|
||||
dispatch(new DatabaseBackupJob(
|
||||
backup: $this->backup
|
||||
));
|
||||
$this->emit('success', 'Backup queued. It will be available in a few minutes');
|
||||
}
|
||||
public function submit()
|
||||
{
|
||||
$this->emit('success', 'Backup updated successfully');
|
||||
}
|
||||
}
|
@ -31,6 +31,7 @@ class Configuration extends Component
|
||||
'settings.public_port_min' => 'Public port min',
|
||||
'settings.public_port_max' => 'Public port max',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->do_not_track = $this->settings->do_not_track;
|
||||
@ -38,6 +39,7 @@ public function mount()
|
||||
$this->is_registration_enabled = $this->settings->is_registration_enabled;
|
||||
$this->next_channel = $this->settings->next_channel;
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
$this->settings->do_not_track = $this->do_not_track;
|
||||
@ -47,6 +49,21 @@ public function instantSave()
|
||||
$this->settings->save();
|
||||
$this->emit('success', 'Settings updated!');
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->resetErrorBag();
|
||||
if ($this->settings->public_port_min > $this->settings->public_port_max) {
|
||||
$this->addError('settings.public_port_min', 'The minimum port must be lower than the maximum port.');
|
||||
return;
|
||||
}
|
||||
$this->validate();
|
||||
$this->settings->save();
|
||||
$this->server = Server::findOrFail(0);
|
||||
$this->setup_instance_fqdn();
|
||||
$this->emit('success', 'Instance settings updated successfully!');
|
||||
}
|
||||
|
||||
private function setup_instance_fqdn()
|
||||
{
|
||||
$file = "$this->dynamic_config_path/coolify.yaml";
|
||||
@ -110,6 +127,7 @@ private function setup_instance_fqdn()
|
||||
dispatch(new ProxyStartJob($this->server));
|
||||
}
|
||||
}
|
||||
|
||||
private function save_configuration_to_disk(array $traefik_dynamic_conf, string $file)
|
||||
{
|
||||
$yaml = Yaml::dump($traefik_dynamic_conf, 12, 2);
|
||||
@ -128,17 +146,4 @@ private function save_configuration_to_disk(array $traefik_dynamic_conf, string
|
||||
ray($yaml);
|
||||
}
|
||||
}
|
||||
public function submit()
|
||||
{
|
||||
$this->resetErrorBag();
|
||||
if ($this->settings->public_port_min > $this->settings->public_port_max) {
|
||||
$this->addError('settings.public_port_min', 'The minimum port must be lower than the maximum port.');
|
||||
return;
|
||||
}
|
||||
$this->validate();
|
||||
$this->settings->save();
|
||||
$this->server = Server::findOrFail(0);
|
||||
$this->setup_instance_fqdn();
|
||||
$this->emit('success', 'Instance settings updated successfully!');
|
||||
}
|
||||
}
|
||||
|
@ -3,78 +3,80 @@
|
||||
namespace App\Http\Livewire\Settings;
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Notifications\TransactionalEmails\TestEmail;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use App\Notifications\TransactionalEmails\Test;
|
||||
use Livewire\Component;
|
||||
|
||||
class Email extends Component
|
||||
{
|
||||
public InstanceSettings $settings;
|
||||
|
||||
public string $emails;
|
||||
protected $rules = [
|
||||
'settings.smtp.enabled' => 'nullable|boolean',
|
||||
'settings.smtp.host' => 'required',
|
||||
'settings.smtp.port' => 'required|numeric',
|
||||
'settings.smtp.encryption' => 'nullable',
|
||||
'settings.smtp.username' => 'nullable',
|
||||
'settings.smtp.password' => 'nullable',
|
||||
'settings.smtp.timeout' => 'nullable',
|
||||
'settings.smtp.test_recipients' => 'nullable',
|
||||
'settings.smtp.from_address' => 'required|email',
|
||||
'settings.smtp.from_name' => 'required',
|
||||
'settings.smtp_enabled' => 'nullable|boolean',
|
||||
'settings.smtp_host' => 'required',
|
||||
'settings.smtp_port' => 'required|numeric',
|
||||
'settings.smtp_encryption' => 'nullable',
|
||||
'settings.smtp_username' => 'nullable',
|
||||
'settings.smtp_password' => 'nullable',
|
||||
'settings.smtp_timeout' => 'nullable',
|
||||
'settings.smtp_from_address' => 'required|email',
|
||||
'settings.smtp_from_name' => 'required',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'settings.smtp.from_address' => 'From Address',
|
||||
'settings.smtp.from_name' => 'From Name',
|
||||
'settings.smtp.recipients' => 'Recipients',
|
||||
'settings.smtp.host' => 'Host',
|
||||
'settings.smtp.port' => 'Port',
|
||||
'settings.smtp.encryption' => 'Encryption',
|
||||
'settings.smtp.username' => 'Username',
|
||||
'settings.smtp.password' => 'Password',
|
||||
'settings.smtp.test_recipients' => 'Test Recipients',
|
||||
'settings.smtp_from_address' => 'From Address',
|
||||
'settings.smtp_from_name' => 'From Name',
|
||||
'settings.smtp_recipients' => 'Recipients',
|
||||
'settings.smtp_host' => 'Host',
|
||||
'settings.smtp_port' => 'Port',
|
||||
'settings.smtp_encryption' => 'Encryption',
|
||||
'settings.smtp_username' => 'Username',
|
||||
'settings.smtp_password' => 'Password',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->decrypt();
|
||||
$this->emails = auth()->user()->email;
|
||||
}
|
||||
|
||||
private function decrypt()
|
||||
{
|
||||
if (data_get($this->settings, 'smtp_password')) {
|
||||
try {
|
||||
$this->settings->smtp_password = decrypt($this->settings->smtp_password);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
try {
|
||||
$this->submit();
|
||||
$this->emit('success', 'Settings saved successfully.');
|
||||
} catch (\Exception $e) {
|
||||
$this->settings->smtp->enabled = false;
|
||||
$this->settings->smtp_enabled = false;
|
||||
$this->validate();
|
||||
}
|
||||
}
|
||||
public function testNotification()
|
||||
{
|
||||
$this->settings->notify(new TestEmail);
|
||||
$this->emit('success', 'Test email sent.');
|
||||
}
|
||||
private function decrypt()
|
||||
{
|
||||
if (data_get($this->settings, 'smtp.password')) {
|
||||
try {
|
||||
$this->settings->smtp->password = decrypt($this->settings->smtp->password);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->resetErrorBag();
|
||||
$this->validate();
|
||||
if ($this->settings->smtp->password) {
|
||||
$this->settings->smtp->password = encrypt($this->settings->smtp->password);
|
||||
if ($this->settings->smtp_password) {
|
||||
$this->settings->smtp_password = encrypt($this->settings->smtp_password);
|
||||
} else {
|
||||
$this->settings->smtp->password = null;
|
||||
$this->settings->smtp_password = null;
|
||||
}
|
||||
|
||||
$this->settings->smtp->test_recipients = str_replace(' ', '', $this->settings->smtp->test_recipients);
|
||||
$this->settings->save();
|
||||
$this->emit('success', 'Transaction email settings updated successfully.');
|
||||
$this->decrypt();
|
||||
}
|
||||
|
||||
public function sendTestNotification()
|
||||
{
|
||||
$this->settings->notify(new Test($this->emails));
|
||||
$this->emit('success', 'Test email sent.');
|
||||
}
|
||||
}
|
||||
|
@ -34,12 +34,14 @@ class Change extends Component
|
||||
'github_app.webhook_secret' => 'nullable',
|
||||
'github_app.is_system_wide' => 'required|bool',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->webhook_endpoint = $this->ipv4;
|
||||
$this->parameters = getRouteParameters();
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->is_system_wide = $this->github_app->is_system_wide;
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
@ -49,6 +51,7 @@ public function submit()
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
{
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ public function mount()
|
||||
{
|
||||
$this->name = generate_random_name();
|
||||
}
|
||||
|
||||
public function createGitHubApp()
|
||||
{
|
||||
try {
|
||||
@ -39,7 +40,7 @@ public function createGitHubApp()
|
||||
'custom_user' => $this->custom_user,
|
||||
'custom_port' => $this->custom_port,
|
||||
'is_system_wide' => $this->is_system_wide,
|
||||
'team_id' => session('currentTeam')->id,
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
]);
|
||||
redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
|
||||
} catch (\Exception $e) {
|
||||
|
@ -8,10 +8,12 @@
|
||||
class SwitchTeam extends Component
|
||||
{
|
||||
public string $selectedTeamId = 'default';
|
||||
|
||||
public function updatedSelectedTeamId()
|
||||
{
|
||||
$this->switch_to($this->selectedTeamId);
|
||||
}
|
||||
|
||||
public function switch_to($team_id)
|
||||
{
|
||||
if (!auth()->user()->teams->contains($team_id)) {
|
||||
|
@ -18,6 +18,7 @@ class Create extends Component
|
||||
'name' => 'name',
|
||||
'description' => 'description',
|
||||
];
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
|
@ -9,7 +9,7 @@ class Delete extends Component
|
||||
{
|
||||
public function delete()
|
||||
{
|
||||
$currentTeam = session('currentTeam');
|
||||
$currentTeam = auth()->user()->currentTeam();
|
||||
$currentTeam->delete();
|
||||
|
||||
$team = auth()->user()->teams()->first();
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
use App\Models\Team;
|
||||
use Livewire\Component;
|
||||
use Masmerise\Toaster\Toaster;
|
||||
|
||||
class Form extends Component
|
||||
{
|
||||
@ -17,10 +16,12 @@ class Form extends Component
|
||||
'team.name' => 'name',
|
||||
'team.description' => 'description',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->team = session('currentTeam');
|
||||
$this->team = auth()->user()->currentTeam();
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate();
|
||||
|
@ -9,13 +9,15 @@ class Invitations extends Component
|
||||
{
|
||||
public $invitations;
|
||||
protected $listeners = ['refreshInvitations'];
|
||||
public function refreshInvitations()
|
||||
{
|
||||
$this->invitations = TeamInvitation::whereTeamId(auth()->user()->currentTeam()->id)->get();
|
||||
}
|
||||
|
||||
public function deleteInvitation(int $invitation_id)
|
||||
{
|
||||
TeamInvitation::find($invitation_id)->delete();
|
||||
$this->refreshInvitations();
|
||||
}
|
||||
|
||||
public function refreshInvitations()
|
||||
{
|
||||
$this->invitations = TeamInvitation::whereTeamId(auth()->user()->currentTeam()->id)->get();
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use App\Models\TeamInvitation;
|
||||
use App\Models\User;
|
||||
use App\Notifications\TransactionalEmails\InvitationLinkEmail;
|
||||
use App\Notifications\TransactionalEmails\InvitationLink;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
@ -12,14 +12,17 @@ class InviteLink extends Component
|
||||
{
|
||||
public string $email;
|
||||
public string $role = 'member';
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->email = isDev() ? 'test3@example.com' : '';
|
||||
$this->email = is_dev() ? 'test3@example.com' : '';
|
||||
}
|
||||
|
||||
public function viaEmail()
|
||||
{
|
||||
$this->generate_invite_link(isEmail: true);
|
||||
}
|
||||
|
||||
private function generate_invite_link(bool $isEmail = false)
|
||||
{
|
||||
try {
|
||||
@ -32,9 +35,9 @@ private function generate_invite_link(bool $isEmail = false)
|
||||
return general_error_handler(that: $this, customErrorMessage: "$this->email must be registered first (or activate transactional emails to invite via email).");
|
||||
}
|
||||
|
||||
$member_emails = session('currentTeam')->members()->get()->pluck('email');
|
||||
$member_emails = auth()->user()->currentTeam()->members()->get()->pluck('email');
|
||||
if ($member_emails->contains($this->email)) {
|
||||
return general_error_handler(that: $this, customErrorMessage: "$this->email is already a member of " . session('currentTeam')->name . ".");
|
||||
return general_error_handler(that: $this, customErrorMessage: "$this->email is already a member of " . auth()->user()->currentTeam()->name . ".");
|
||||
}
|
||||
|
||||
$invitation = TeamInvitation::whereEmail($this->email);
|
||||
@ -50,7 +53,7 @@ private function generate_invite_link(bool $isEmail = false)
|
||||
}
|
||||
|
||||
TeamInvitation::firstOrCreate([
|
||||
'team_id' => session('currentTeam')->id,
|
||||
'team_id' => auth()->user()->currentTeam()->id,
|
||||
'uuid' => $uuid,
|
||||
'email' => $this->email,
|
||||
'role' => $this->role,
|
||||
@ -58,7 +61,7 @@ private function generate_invite_link(bool $isEmail = false)
|
||||
'via' => $isEmail ? 'email' : 'link',
|
||||
]);
|
||||
if ($isEmail) {
|
||||
$user->first()->notify(new InvitationLinkEmail());
|
||||
$user->first()->notify(new InvitationLink);
|
||||
$this->emit('success', 'Invitation sent via email successfully.');
|
||||
} else {
|
||||
$this->emit('success', 'Invitation link generated.');
|
||||
@ -72,6 +75,7 @@ private function generate_invite_link(bool $isEmail = false)
|
||||
return general_error_handler(err: $e, that: $this, customErrorMessage: $error_message);
|
||||
}
|
||||
}
|
||||
|
||||
public function viaLink()
|
||||
{
|
||||
$this->generate_invite_link();
|
||||
|
@ -8,19 +8,22 @@
|
||||
class Member extends Component
|
||||
{
|
||||
public User $member;
|
||||
|
||||
public function makeAdmin()
|
||||
{
|
||||
$this->member->teams()->updateExistingPivot(session('currentTeam')->id, ['role' => 'admin']);
|
||||
$this->member->teams()->updateExistingPivot(auth()->user()->currentTeam()->id, ['role' => 'admin']);
|
||||
$this->emit('reloadWindow');
|
||||
}
|
||||
|
||||
public function makeReadonly()
|
||||
{
|
||||
$this->member->teams()->updateExistingPivot(session('currentTeam')->id, ['role' => 'member']);
|
||||
$this->member->teams()->updateExistingPivot(auth()->user()->currentTeam()->id, ['role' => 'member']);
|
||||
$this->emit('reloadWindow');
|
||||
}
|
||||
|
||||
public function remove()
|
||||
{
|
||||
$this->member->teams()->detach(session('currentTeam'));
|
||||
$this->member->teams()->detach(auth()->user()->currentTeam());
|
||||
$this->emit('reloadWindow');
|
||||
}
|
||||
}
|
||||
|
84
app/Http/Livewire/Team/Storage/Create.php
Normal file
84
app/Http/Livewire/Team/Storage/Create.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Team\Storage;
|
||||
|
||||
use App\Models\S3Storage;
|
||||
use Livewire\Component;
|
||||
|
||||
class Create extends Component
|
||||
{
|
||||
public string $name;
|
||||
public string $description;
|
||||
public string $region = 'us-east-1';
|
||||
public string $key;
|
||||
public string $secret;
|
||||
public string $bucket;
|
||||
public string $endpoint;
|
||||
public S3Storage $storage;
|
||||
protected $rules = [
|
||||
'name' => 'nullable|min:3|max:255',
|
||||
'description' => 'nullable|min:3|max:255',
|
||||
'region' => 'required|max:255',
|
||||
'key' => 'required|max:255',
|
||||
'secret' => 'required|max:255',
|
||||
'bucket' => 'required|max:255',
|
||||
'endpoint' => 'nullable|url|max:255',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'name' => 'Name',
|
||||
'description' => 'Description',
|
||||
'region' => 'Region',
|
||||
'key' => 'Key',
|
||||
'secret' => "Secret",
|
||||
'bucket' => 'Bucket',
|
||||
'endpoint' => 'Endpoint',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
if (is_dev()) {
|
||||
$this->name = 'Local MinIO';
|
||||
$this->description = 'Local MinIO';
|
||||
$this->key = 'minioadmin';
|
||||
$this->secret = 'minioadmin';
|
||||
$this->bucket = 'local';
|
||||
$this->endpoint = 'http://coolify-minio:9000';
|
||||
}
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->validate();
|
||||
$this->storage = new S3Storage();
|
||||
$this->storage->name = $this->name;
|
||||
$this->storage->description = $this->description ?? null;
|
||||
$this->storage->region = $this->region;
|
||||
$this->storage->key = $this->key;
|
||||
$this->storage->secret = $this->secret;
|
||||
$this->storage->bucket = $this->bucket;
|
||||
if (empty($this->endpoint)) {
|
||||
$this->storage->endpoint = "https://s3.{$this->region}.amazonaws.com";
|
||||
} else {
|
||||
$this->storage->endpoint = $this->endpoint;
|
||||
}
|
||||
$this->storage->team_id = auth()->user()->currentTeam()->id;
|
||||
$this->storage->testConnection();
|
||||
$this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
|
||||
$this->storage->save();
|
||||
return redirect()->route('team.storages.show', $this->storage->uuid);
|
||||
} catch (\Throwable $th) {
|
||||
return general_error_handler($th, $this);
|
||||
}
|
||||
}
|
||||
|
||||
private function test_s3_connection()
|
||||
{
|
||||
try {
|
||||
$this->storage->testConnection();
|
||||
return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
|
||||
} catch (\Throwable $th) {
|
||||
return general_error_handler($th, $this);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user