2024-04-10 15:00:46 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Livewire\Project\Database\Keydb;
|
|
|
|
|
|
|
|
|
|
use App\Actions\Database\StartDatabaseProxy;
|
|
|
|
|
use App\Actions\Database\StopDatabaseProxy;
|
2024-06-09 21:33:17 +02:00
|
|
|
use App\Models\Server;
|
2024-04-10 15:00:46 +02:00
|
|
|
use App\Models\StandaloneKeydb;
|
2025-08-19 14:15:31 +02:00
|
|
|
use App\Support\ValidationPatterns;
|
2024-04-10 15:00:46 +02:00
|
|
|
use Exception;
|
2025-08-23 18:50:35 +02:00
|
|
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
2024-11-04 14:33:44 +01:00
|
|
|
use Illuminate\Support\Facades\Auth;
|
2024-04-10 15:00:46 +02:00
|
|
|
use Livewire\Component;
|
|
|
|
|
|
|
|
|
|
class General extends Component
|
|
|
|
|
{
|
2025-08-23 18:50:35 +02:00
|
|
|
use AuthorizesRequests;
|
|
|
|
|
|
2025-10-14 17:04:48 +02:00
|
|
|
public ?Server $server = null;
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2024-04-10 15:00:46 +02:00
|
|
|
public StandaloneKeydb $database;
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2024-11-04 14:33:44 +01:00
|
|
|
public string $name;
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2024-11-04 14:33:44 +01:00
|
|
|
public ?string $description = null;
|
|
|
|
|
|
|
|
|
|
public ?string $keydbConf = null;
|
|
|
|
|
|
|
|
|
|
public string $keydbPassword;
|
|
|
|
|
|
|
|
|
|
public string $image;
|
|
|
|
|
|
|
|
|
|
public ?string $portsMappings = null;
|
|
|
|
|
|
|
|
|
|
public ?bool $isPublic = null;
|
|
|
|
|
|
2026-03-29 19:11:28 +05:30
|
|
|
public mixed $publicPort = null;
|
2024-11-04 14:33:44 +01:00
|
|
|
|
2026-03-29 19:11:28 +05:30
|
|
|
public mixed $publicPortTimeout = 3600;
|
2026-02-26 21:07:09 -08:00
|
|
|
|
2024-11-04 14:33:44 +01:00
|
|
|
public ?string $customDockerRunOptions = null;
|
|
|
|
|
|
|
|
|
|
public bool $isLogDrainEnabled = false;
|
|
|
|
|
|
2026-05-28 17:13:18 +02:00
|
|
|
public function getListeners(): array
|
2024-04-10 15:00:46 +02:00
|
|
|
{
|
2026-05-28 17:13:18 +02:00
|
|
|
$user = Auth::user();
|
|
|
|
|
if (! $user) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
$team = $user->currentTeam();
|
|
|
|
|
if (! $team) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
2024-11-04 14:33:44 +01:00
|
|
|
|
|
|
|
|
return [
|
2026-05-28 17:13:18 +02:00
|
|
|
"echo-private:team.{$team->id},DatabaseProxyStopped" => 'databaseProxyStopped',
|
2024-11-04 14:33:44 +01:00
|
|
|
];
|
2024-04-10 15:00:46 +02:00
|
|
|
}
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2024-11-04 14:33:44 +01:00
|
|
|
public function mount()
|
2024-06-10 20:43:34 +00:00
|
|
|
{
|
2024-04-10 15:00:46 +02:00
|
|
|
try {
|
2025-10-14 17:33:42 +02:00
|
|
|
$this->authorize('view', $this->database);
|
2024-11-04 14:33:44 +01:00
|
|
|
$this->syncData();
|
|
|
|
|
$this->server = data_get($this->database, 'destination.server');
|
2025-10-14 17:04:48 +02:00
|
|
|
if (! $this->server) {
|
|
|
|
|
$this->dispatch('error', 'Database destination server is not configured.');
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-01-07 15:31:43 +01:00
|
|
|
} catch (\Throwable $e) {
|
2024-11-04 14:33:44 +01:00
|
|
|
return handleError($e, $this);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2025-08-19 14:15:31 +02:00
|
|
|
protected function rules(): array
|
|
|
|
|
{
|
2026-05-21 08:31:08 +00:00
|
|
|
return [
|
2025-08-19 14:15:31 +02:00
|
|
|
'name' => ValidationPatterns::nameRules(),
|
|
|
|
|
'description' => ValidationPatterns::descriptionRules(),
|
|
|
|
|
'keydbConf' => 'nullable|string',
|
2026-04-20 13:45:57 +02:00
|
|
|
'keydbPassword' => ValidationPatterns::databasePasswordRules(
|
|
|
|
|
enforcePattern: $this->keydbPassword !== $this->database->keydb_password,
|
|
|
|
|
),
|
2025-08-19 14:15:31 +02:00
|
|
|
'image' => 'required|string',
|
2026-03-28 23:23:25 +05:30
|
|
|
'portsMappings' => ValidationPatterns::portMappingRules(),
|
2025-08-19 14:15:31 +02:00
|
|
|
'isPublic' => 'nullable|boolean',
|
2026-03-29 19:11:28 +05:30
|
|
|
'publicPort' => 'nullable|integer|min:1|max:65535',
|
2026-02-27 14:24:04 -08:00
|
|
|
'publicPortTimeout' => 'nullable|integer|min:1',
|
2025-08-19 14:15:31 +02:00
|
|
|
'customDockerRunOptions' => 'nullable|string',
|
|
|
|
|
'isLogDrainEnabled' => 'nullable|boolean',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function messages(): array
|
|
|
|
|
{
|
|
|
|
|
return array_merge(
|
|
|
|
|
ValidationPatterns::combinedMessages(),
|
2026-03-28 23:23:25 +05:30
|
|
|
ValidationPatterns::portMappingMessages(),
|
2025-08-19 14:15:31 +02:00
|
|
|
[
|
2026-04-20 13:58:36 +02:00
|
|
|
...ValidationPatterns::databasePasswordMessages('keydbPassword', 'KeyDB Password'),
|
2025-08-19 14:15:31 +02:00
|
|
|
'image.required' => 'The Docker Image field is required.',
|
|
|
|
|
'image.string' => 'The Docker Image must be a string.',
|
|
|
|
|
'publicPort.integer' => 'The Public Port must be an integer.',
|
2026-03-29 19:11:28 +05:30
|
|
|
'publicPort.min' => 'The Public Port must be at least 1.',
|
|
|
|
|
'publicPort.max' => 'The Public Port must not exceed 65535.',
|
2026-02-26 21:07:09 -08:00
|
|
|
'publicPortTimeout.integer' => 'The Public Port Timeout must be an integer.',
|
2026-02-27 14:24:04 -08:00
|
|
|
'publicPortTimeout.min' => 'The Public Port Timeout must be at least 1.',
|
2025-08-19 14:15:31 +02:00
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-04 14:33:44 +01:00
|
|
|
public function syncData(bool $toModel = false)
|
|
|
|
|
{
|
|
|
|
|
if ($toModel) {
|
|
|
|
|
$this->validate();
|
|
|
|
|
$this->database->name = $this->name;
|
|
|
|
|
$this->database->description = $this->description;
|
|
|
|
|
$this->database->keydb_conf = $this->keydbConf;
|
|
|
|
|
$this->database->keydb_password = $this->keydbPassword;
|
|
|
|
|
$this->database->image = $this->image;
|
|
|
|
|
$this->database->ports_mappings = $this->portsMappings;
|
|
|
|
|
$this->database->is_public = $this->isPublic;
|
2026-03-29 19:11:28 +05:30
|
|
|
$this->database->public_port = $this->publicPort ?: null;
|
|
|
|
|
$this->database->public_port_timeout = $this->publicPortTimeout ?: null;
|
2024-11-04 14:33:44 +01:00
|
|
|
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
|
|
|
|
|
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
|
2024-04-10 15:00:46 +02:00
|
|
|
$this->database->save();
|
2024-11-04 14:33:44 +01:00
|
|
|
} else {
|
|
|
|
|
$this->name = $this->database->name;
|
|
|
|
|
$this->description = $this->database->description;
|
|
|
|
|
$this->keydbConf = $this->database->keydb_conf;
|
|
|
|
|
$this->keydbPassword = $this->database->keydb_password;
|
|
|
|
|
$this->image = $this->database->image;
|
|
|
|
|
$this->portsMappings = $this->database->ports_mappings;
|
|
|
|
|
$this->isPublic = $this->database->is_public;
|
|
|
|
|
$this->publicPort = $this->database->public_port;
|
2026-02-26 21:07:09 -08:00
|
|
|
$this->publicPortTimeout = $this->database->public_port_timeout;
|
2024-11-04 14:33:44 +01:00
|
|
|
$this->customDockerRunOptions = $this->database->custom_docker_run_options;
|
|
|
|
|
$this->isLogDrainEnabled = $this->database->is_log_drain_enabled;
|
2024-04-10 15:00:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2024-11-04 14:33:44 +01:00
|
|
|
public function instantSaveAdvanced()
|
2024-04-10 15:00:46 +02:00
|
|
|
{
|
|
|
|
|
try {
|
2025-08-23 18:50:35 +02:00
|
|
|
$this->authorize('update', $this->database);
|
|
|
|
|
|
2024-11-04 14:33:44 +01:00
|
|
|
if (! $this->server->isLogDrainEnabled()) {
|
|
|
|
|
$this->isLogDrainEnabled = false;
|
|
|
|
|
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
|
|
|
|
|
|
2025-01-07 15:31:43 +01:00
|
|
|
return;
|
2024-04-10 15:00:46 +02:00
|
|
|
}
|
2024-11-04 14:33:44 +01:00
|
|
|
$this->syncData(true);
|
|
|
|
|
|
2024-04-10 15:00:46 +02:00
|
|
|
$this->dispatch('success', 'Database updated.');
|
2024-11-04 14:33:44 +01:00
|
|
|
$this->dispatch('success', 'You need to restart the service for the changes to take effect.');
|
2024-04-10 15:00:46 +02:00
|
|
|
} catch (Exception $e) {
|
|
|
|
|
return handleError($e, $this);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2024-04-10 15:00:46 +02:00
|
|
|
public function instantSave()
|
|
|
|
|
{
|
|
|
|
|
try {
|
2025-08-23 18:50:35 +02:00
|
|
|
$this->authorize('update', $this->database);
|
|
|
|
|
|
2024-11-04 14:33:44 +01:00
|
|
|
if ($this->isPublic && ! $this->publicPort) {
|
2024-04-10 15:00:46 +02:00
|
|
|
$this->dispatch('error', 'Public port is required.');
|
2024-11-04 14:33:44 +01:00
|
|
|
$this->isPublic = false;
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2025-01-07 15:31:43 +01:00
|
|
|
return;
|
2024-04-10 15:00:46 +02:00
|
|
|
}
|
2026-01-06 13:44:46 +01:00
|
|
|
if ($this->isPublic && ! str($this->database->status)->startsWith('running')) {
|
|
|
|
|
$this->dispatch('error', 'Database must be started to be publicly accessible.');
|
|
|
|
|
$this->isPublic = false;
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2026-01-06 13:44:46 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$this->syncData(true);
|
|
|
|
|
if ($this->isPublic) {
|
2024-04-10 15:00:46 +02:00
|
|
|
StartDatabaseProxy::run($this->database);
|
|
|
|
|
$this->dispatch('success', 'Database is now publicly accessible.');
|
|
|
|
|
} else {
|
|
|
|
|
StopDatabaseProxy::run($this->database);
|
|
|
|
|
$this->dispatch('success', 'Database is no longer publicly accessible.');
|
|
|
|
|
}
|
2026-05-21 08:31:08 +00:00
|
|
|
$this->dispatch('databaseUpdated');
|
2025-01-07 15:31:43 +01:00
|
|
|
} catch (\Throwable $e) {
|
2024-11-04 14:33:44 +01:00
|
|
|
$this->isPublic = ! $this->isPublic;
|
|
|
|
|
$this->syncData(true);
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2024-04-10 15:00:46 +02:00
|
|
|
return handleError($e, $this);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-10 20:43:34 +00:00
|
|
|
|
2026-05-21 10:24:49 +00:00
|
|
|
public function databaseProxyStopped(): void
|
2024-04-10 15:00:46 +02:00
|
|
|
{
|
2026-05-21 10:24:49 +00:00
|
|
|
$this->database->refresh();
|
|
|
|
|
$this->isPublic = $this->database->is_public;
|
|
|
|
|
$this->publicPort = $this->database->public_port;
|
|
|
|
|
$this->publicPortTimeout = $this->database->public_port_timeout;
|
2026-05-21 08:31:08 +00:00
|
|
|
$this->dispatch('databaseUpdated');
|
2024-04-10 15:00:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-11-04 14:33:44 +01:00
|
|
|
public function submit()
|
2024-04-10 15:00:46 +02:00
|
|
|
{
|
2024-11-04 14:33:44 +01:00
|
|
|
try {
|
2025-08-23 18:50:35 +02:00
|
|
|
$this->authorize('manageEnvironment', $this->database);
|
|
|
|
|
|
2026-03-28 23:23:25 +05:30
|
|
|
if ($this->portsMappings) {
|
|
|
|
|
$this->portsMappings = str($this->portsMappings)->replace(' ', '')->trim()->toString();
|
|
|
|
|
}
|
2024-11-04 14:33:44 +01:00
|
|
|
if (str($this->publicPort)->isEmpty()) {
|
|
|
|
|
$this->publicPort = null;
|
|
|
|
|
}
|
|
|
|
|
$this->syncData(true);
|
|
|
|
|
$this->dispatch('success', 'Database updated.');
|
2026-05-21 08:31:08 +00:00
|
|
|
$this->dispatch('databaseUpdated');
|
2024-11-04 14:33:44 +01:00
|
|
|
} catch (Exception $e) {
|
|
|
|
|
return handleError($e, $this);
|
|
|
|
|
} finally {
|
|
|
|
|
if (is_null($this->database->config_hash)) {
|
|
|
|
|
$this->database->isConfigurationChanged(true);
|
|
|
|
|
} else {
|
|
|
|
|
$this->dispatch('configurationChanged');
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-04-10 15:00:46 +02:00
|
|
|
}
|
2025-02-10 21:29:45 +01:00
|
|
|
|
2026-03-31 09:29:36 +02:00
|
|
|
public function refresh(): void
|
|
|
|
|
{
|
|
|
|
|
$this->database->refresh();
|
|
|
|
|
$this->syncData();
|
|
|
|
|
}
|
2024-04-10 15:00:46 +02:00
|
|
|
}
|