feat(database): implement two-step confirmation for database deletion

Added a new delete method in the Database component that includes a two-step confirmation process requiring the user to enter their password. If two-step confirmation is disabled, the deletion proceeds without password verification. Additionally, a confirmation modal has been integrated into the database view to prompt users before deletion, enhancing the safety of this critical operation.
This commit is contained in:
Andras Bacsai
2025-03-12 16:33:35 +01:00
parent fa619550c2
commit d894c3d903
3 changed files with 34 additions and 4 deletions

View File

@@ -4,7 +4,10 @@ namespace App\Livewire\Project\Service;
use App\Actions\Database\StartDatabaseProxy;
use App\Actions\Database\StopDatabaseProxy;
use App\Models\InstanceSettings;
use App\Models\ServiceDatabase;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Livewire\Component;
class Database extends Component
@@ -15,6 +18,8 @@ class Database extends Component
public $fileStorages;
public $parameters;
protected $listeners = ['refreshFileStorages'];
protected $rules = [
@@ -34,12 +39,33 @@ class Database extends Component
public function mount()
{
$this->parameters = get_route_parameters();
if ($this->database->is_public) {
$this->db_url_public = $this->database->getServiceDatabaseUrl();
}
$this->refreshFileStorages();
}
public function delete($password)
{
if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
if (! Hash::check($password, Auth::user()->password)) {
$this->addError('password', 'The provided password is incorrect.');
return;
}
}
try {
$this->database->delete();
$this->dispatch('success', 'Database deleted.');
return redirect()->route('project.service.configuration', $this->parameters);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function instantSaveExclude()
{
$this->submit();

View File

@@ -7,6 +7,10 @@
<h2>{{ Str::headline($database->name) }}</h2>
@endif
<x-forms.button type="submit">Save</x-forms.button>
<x-modal-confirmation title="Confirm Service Database Deletion?" buttonTitle="Delete" isErrorButton
submitAction="delete" :actions="['The selected service database container will be stopped and permanently deleted.']" confirmationText="{{ Str::headline($database->name) }}"
confirmationLabel="Please confirm the execution of the actions by entering the Service Database Name below"
shortConfirmationLabel="Service Database Name" step3ButtonText="Permanently Delete" />
</div>
<div class="flex flex-col gap-2">
<div class="flex gap-2">

View File

@@ -3,8 +3,8 @@
<div class="flex flex-col h-full gap-8 pt-6 sm:flex-row">
<div class="flex flex-col items-start gap-2 min-w-fit">
<a class="menu-item"
class="{{ request()->routeIs('project.service.configuration') ? 'menu-item-active' : '' }}"
wire:navigate href="{{ route('project.service.configuration', [...$parameters, 'stack_service_uuid' => null]) }}">
class="{{ request()->routeIs('project.service.configuration') ? 'menu-item-active' : '' }}" wire:navigate
href="{{ route('project.service.configuration', [...$parameters, 'stack_service_uuid' => null]) }}">
<button><- Back</button>
</a>
<a class="menu-item" :class="activeTab === 'general' && 'menu-item-active'"
@@ -12,8 +12,8 @@
wire:navigate href="#">General</a>
@if ($serviceDatabase?->isBackupSolutionAvailable())
<a :class="activeTab === 'backups' && 'menu-item-active'" class="menu-item"
@click.prevent="activeTab = 'backups'; window.location.hash = 'backups'"
wire:navigate href="#backups">Backups</a>
@click.prevent="activeTab = 'backups'; window.location.hash = 'backups'" wire:navigate
href="#backups">Backups</a>
@endif
</div>
<div class="w-full">