Skip to content

Commit 2f3db8a

Browse files
authored
Fix: respect backups_enabled flag in schedule runs and UI (#156)
- Filter out servers with backups_enabled=false when manually running a schedule via runSchedule(), matching RunScheduledBackups command - Filter disabled servers from backup schedule server counts and popover lists on the Configuration page - Use separate total_backups_count (unfiltered) for delete eligibility so schedules attached to disabled servers still block deletion - Show a "Disabled" badge in the backup column on the database servers index when backups are disabled
1 parent e756f1e commit 2f3db8a

File tree

4 files changed

+50
-9
lines changed

4 files changed

+50
-9
lines changed

app/Livewire/Configuration/Index.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use App\Services\Backup\TriggerBackupAction;
1212
use App\Services\FailureNotificationService;
1313
use Illuminate\Contracts\View\View;
14+
use Illuminate\Database\Eloquent\Collection;
1415
use Illuminate\Support\Facades\Log;
1516
use Illuminate\Support\Facades\Process;
1617
use Illuminate\Validation\Rule;
@@ -292,12 +293,17 @@ public function runSchedule(string $scheduleId, TriggerBackupAction $action): vo
292293
{
293294
abort_unless(auth()->user()->isAdmin(), Response::HTTP_FORBIDDEN);
294295

295-
$schedule = BackupSchedule::with('backups.databaseServer.backup.volume')->findOrFail($scheduleId);
296+
$schedule = BackupSchedule::findOrFail($scheduleId);
297+
298+
$backups = $schedule->backups()
299+
->whereRelation('databaseServer', 'backups_enabled', true)
300+
->with('databaseServer.backup.volume')
301+
->get();
296302

297303
$totalSnapshots = 0;
298304
$errors = [];
299305

300-
foreach ($schedule->backups as $backup) {
306+
foreach ($backups as $backup) {
301307
try {
302308
$userId = auth()->id();
303309
$result = $action->execute($backup->databaseServer, is_int($userId) ? $userId : null);
@@ -320,13 +326,20 @@ public function runSchedule(string $scheduleId, TriggerBackupAction $action): vo
320326
}
321327

322328
/**
323-
* @return \Illuminate\Database\Eloquent\Collection<int, BackupSchedule>
329+
* @return Collection<int, BackupSchedule>
324330
*/
325331
#[Computed]
326-
public function backupSchedules(): \Illuminate\Database\Eloquent\Collection
332+
public function backupSchedules(): Collection
327333
{
328-
return BackupSchedule::withCount('backups')
329-
->with('backups.databaseServer:id,name')
334+
return BackupSchedule::withCount([
335+
'backups as backups_count' => function ($query) {
336+
$query->whereRelation('databaseServer', 'backups_enabled', true);
337+
},
338+
'backups as total_backups_count',
339+
])
340+
->with(['backups' => function ($query) {
341+
$query->whereRelation('databaseServer', 'backups_enabled', true);
342+
}, 'backups.databaseServer:id,name'])
330343
->orderBy('name')
331344
->get();
332345
}

resources/views/livewire/configuration/index.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class="btn-ghost btn-sm"
8282
<x-button icon="o-play" class="btn-ghost btn-sm" wire:click="runSchedule('{{ $schedule->id }}')" spinner="runSchedule('{{ $schedule->id }}')" tooltip-left="{{ __('Run now') }}" />
8383
@endif
8484
<x-button icon="o-pencil-square" class="btn-ghost btn-sm" wire:click="openScheduleModal('{{ $schedule->id }}')" tooltip-left="{{ __('Edit') }}" />
85-
@if ($schedule->backups_count > 0)
85+
@if ($schedule->total_backups_count > 0)
8686
<x-popover>
8787
<x-slot:trigger>
8888
<x-button icon="o-trash" class="btn-ghost btn-sm opacity-40" disabled />

resources/views/livewire/database-server/index.blade.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,12 @@ class="btn-ghost btn-sm"
123123
@endscope
124124

125125
@scope('cell_backup', $server)
126-
@if($server->backup)
126+
@if(!$server->backups_enabled)
127+
<span class="badge badge-warning badge-soft badge-xs gap-1">
128+
<x-icon name="o-no-symbol" class="w-3 h-3" />
129+
{{ __('Disabled') }}
130+
</span>
131+
@elseif($server->backup)
127132
<div class="table-cell-primary flex items-center gap-1.5">
128133
<x-volume-type-icon :type="$server->backup->volume->type" class="w-4 h-4 text-base-content/70" />
129134
{{ $server->backup->volume->name }}

tests/Feature/ConfigurationTest.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use App\Livewire\Configuration\Index;
88
use App\Models\BackupSchedule;
99
use App\Models\DatabaseServer;
10+
use App\Models\Snapshot;
1011
use App\Models\User;
1112
use App\Notifications\BackupFailedNotification;
1213
use App\Services\FailureNotificationService;
@@ -216,7 +217,7 @@
216217

217218
$mock = Mockery::mock(FailureNotificationService::class);
218219
$mock->shouldReceive('getNotificationRoutes')->andReturn(['mail' => 'admin@example.com']);
219-
$mock->shouldReceive('notifyBackupFailed')->andThrow(new \RuntimeException('SMTP connection failed'));
220+
$mock->shouldReceive('notifyBackupFailed')->andThrow(new RuntimeException('SMTP connection failed'));
220221
app()->instance(FailureNotificationService::class, $mock);
221222

222223
Livewire::actingAs(User::factory()->create(['role' => 'admin']))
@@ -464,6 +465,28 @@
464465
Queue::assertPushed(ProcessBackupJob::class);
465466
});
466467

468+
test('running a schedule skips servers with backups disabled', function () {
469+
Queue::fake();
470+
471+
$schedule = BackupSchedule::factory()->create();
472+
$enabledServer = DatabaseServer::factory()->create(['database_names' => ['app'], 'backups_enabled' => true]);
473+
$disabledServer = DatabaseServer::factory()->create(['database_names' => ['app'], 'backups_enabled' => false]);
474+
$enabledServer->backup->update(['backup_schedule_id' => $schedule->id]);
475+
$disabledServer->backup->update(['backup_schedule_id' => $schedule->id]);
476+
477+
Livewire::actingAs(User::factory()->create(['role' => 'admin']))
478+
->test(Index::class)
479+
->call('runSchedule', $schedule->id);
480+
481+
Queue::assertPushed(ProcessBackupJob::class, function ($job) use ($enabledServer) {
482+
return Snapshot::find($job->snapshotId)->database_server_id === $enabledServer->id;
483+
});
484+
485+
Queue::assertNotPushed(ProcessBackupJob::class, function ($job) use ($disabledServer) {
486+
return Snapshot::find($job->snapshotId)->database_server_id === $disabledServer->id;
487+
});
488+
});
489+
467490
test('non-admin cannot run a schedule', function () {
468491
Livewire::actingAs(User::factory()->create(['role' => 'member']))
469492
->test(Index::class)

0 commit comments

Comments
 (0)