feat/005-bulk-operations #5
@ -78,16 +78,6 @@ public static function table(Table $table): Table
|
||||
->requiresConfirmation()
|
||||
->visible(fn (BackupSet $record) => ! $record->trashed())
|
||||
->action(function (BackupSet $record, AuditLogger $auditLogger) {
|
||||
if ($record->restoreRuns()->withTrashed()->exists()) {
|
||||
Notification::make()
|
||||
->title('Cannot archive backup set')
|
||||
->body('Backup sets used by restore runs cannot be archived.')
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$record->delete();
|
||||
|
||||
if ($record->tenant) {
|
||||
@ -159,7 +149,7 @@ public static function table(Table $table): Table
|
||||
|
||||
return $isOnlyTrashed;
|
||||
})
|
||||
->modalDescription('This archives backup sets (soft delete). Backup sets referenced by restore runs will be skipped.')
|
||||
->modalDescription('This archives backup sets (soft delete). Already archived backup sets will be skipped.')
|
||||
->form(function (Collection $records) {
|
||||
if ($records->count() >= 10) {
|
||||
return [
|
||||
|
||||
@ -82,14 +82,6 @@ public function handle(BulkOperationService $service): void
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($backupSet->restoreRuns()->withTrashed()->exists()) {
|
||||
$service->recordSkippedWithReason($run, (string) $backupSet->id, 'Referenced by restore runs');
|
||||
$skipped++;
|
||||
$skipReasons['Referenced by restore runs'] = ($skipReasons['Referenced by restore runs'] ?? 0) + 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$backupSet->delete();
|
||||
$service->recordSuccess($run);
|
||||
$succeeded++;
|
||||
|
||||
@ -32,7 +32,7 @@ public function tenant(): BelongsTo
|
||||
|
||||
public function backupSet(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(BackupSet::class);
|
||||
return $this->belongsTo(BackupSet::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function scopeDeletable($query)
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
use App\Models\BackupItem;
|
||||
use App\Models\BackupSet;
|
||||
use App\Models\BulkOperationRun;
|
||||
use App\Models\RestoreRun;
|
||||
use App\Models\Tenant;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
@ -55,6 +56,35 @@
|
||||
expect($bulkRun->status)->toBe('completed');
|
||||
});
|
||||
|
||||
test('backup sets can be archived even when referenced by restore runs', function () {
|
||||
$tenant = Tenant::factory()->create();
|
||||
$tenant->makeCurrent();
|
||||
$user = User::factory()->create();
|
||||
|
||||
$set = BackupSet::create([
|
||||
'tenant_id' => $tenant->id,
|
||||
'name' => 'Backup',
|
||||
'status' => 'completed',
|
||||
'item_count' => 0,
|
||||
]);
|
||||
|
||||
$restoreRun = RestoreRun::create([
|
||||
'tenant_id' => $tenant->id,
|
||||
'backup_set_id' => $set->id,
|
||||
'status' => 'completed',
|
||||
'is_dry_run' => true,
|
||||
'requested_by' => 'tester@example.com',
|
||||
]);
|
||||
|
||||
Livewire::actingAs($user)
|
||||
->test(BackupSetResource\Pages\ListBackupSets::class)
|
||||
->callTableBulkAction('bulk_delete', collect([$set]))
|
||||
->assertHasNoTableBulkActionErrors();
|
||||
|
||||
expect(BackupSet::withTrashed()->find($set->id)?->trashed())->toBeTrue();
|
||||
expect(RestoreRun::withTrashed()->find($restoreRun->id))->not->toBeNull();
|
||||
});
|
||||
|
||||
test('backup sets table bulk archive requires type-to-confirm for 10+ sets', function () {
|
||||
$tenant = Tenant::factory()->create();
|
||||
$tenant->makeCurrent();
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
]);
|
||||
});
|
||||
|
||||
test('backup set archive is blocked when restore runs exist', function () {
|
||||
test('backup set can be archived when restore runs exist', function () {
|
||||
$tenant = Tenant::create([
|
||||
'tenant_id' => 'tenant-2',
|
||||
'name' => 'Tenant 2',
|
||||
@ -65,7 +65,7 @@
|
||||
'status' => 'completed',
|
||||
]);
|
||||
|
||||
RestoreRun::create([
|
||||
$restoreRun = RestoreRun::create([
|
||||
'tenant_id' => $tenant->id,
|
||||
'backup_set_id' => $backupSet->id,
|
||||
'status' => 'completed',
|
||||
@ -77,12 +77,13 @@
|
||||
Livewire::test(ListBackupSets::class)
|
||||
->callTableAction('archive', $backupSet);
|
||||
|
||||
$this->assertDatabaseMissing('audit_logs', [
|
||||
$this->assertSoftDeleted('backup_sets', ['id' => $backupSet->id]);
|
||||
$this->assertDatabaseHas('audit_logs', [
|
||||
'resource_type' => 'backup_set',
|
||||
'resource_id' => (string) $backupSet->id,
|
||||
'action' => 'backup.deleted',
|
||||
]);
|
||||
$this->assertDatabaseHas('backup_sets', ['id' => $backupSet->id, 'deleted_at' => null]);
|
||||
$this->assertDatabaseHas('restore_runs', ['id' => $restoreRun->id]);
|
||||
});
|
||||
|
||||
test('backup set can be force deleted when trashed and unused', function () {
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
});
|
||||
});
|
||||
|
||||
test('bulk backup set delete job skips sets referenced by restore runs', function () {
|
||||
test('bulk backup set delete job archives sets even when referenced by restore runs', function () {
|
||||
$tenant = Tenant::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
@ -82,10 +82,10 @@
|
||||
$run->refresh();
|
||||
expect($run->status)->toBe('completed')
|
||||
->and($run->processed_items)->toBe(1)
|
||||
->and($run->succeeded)->toBe(0)
|
||||
->and($run->succeeded)->toBe(1)
|
||||
->and($run->failed)->toBe(0)
|
||||
->and($run->skipped)->toBe(1);
|
||||
->and($run->skipped)->toBe(0);
|
||||
|
||||
expect(collect($run->failures)->pluck('reason')->join(' '))->toContain('restore runs');
|
||||
expect(BackupSet::withTrashed()->find($set->id)?->trashed())->toBeFalse();
|
||||
expect(BackupSet::withTrashed()->find($set->id)?->trashed())->toBeTrue();
|
||||
expect(RestoreRun::query()->where('backup_set_id', $set->id)->exists())->toBeTrue();
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user