Skip to content

Commit

Permalink
feat: add preferred backup destination option
Browse files Browse the repository at this point in the history
  • Loading branch information
lewislarsen committed Jun 16, 2024
1 parent ec57435 commit 94e7246
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 1 deletion.
7 changes: 6 additions & 1 deletion app/Livewire/BackupTasks/CreateBackupTaskForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,12 @@ public function mount(): void

$this->remoteServers = Auth::user()->remoteServers->where('database_password', null);
$this->remoteServerId = $this->remoteServers->first()?->id ?? '';
$this->backupDestinationId = Auth::user()->backupDestinations->first()?->id ?? '';

if (Auth::user()->preferred_backup_destination_id) {
$this->backupDestinationId = Auth::user()->preferred_backup_destination_id;
} else {
$this->backupDestinationId = Auth::user()->backupDestinations->first()?->id ?? '';
}

// Initialize backup times in half-hour increments
$this->backupTimes = collect(range(0, 47))->map(function ($halfHour) {
Expand Down
1 change: 1 addition & 0 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class User extends Authenticatable
'password',
'timezone',
'github_id',
'preferred_backup_destination_id',
];

protected $hidden = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

use App\Models\BackupDestination;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->foreignIdFor(BackupDestination::class, 'preferred_backup_destination_id')
->nullable()
->constrained('backup_destinations')
->nullOnDelete();
});
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
public string $name = '';
public string $email = '';
public string $timezone = '';
public ?int $preferred_backup_destination_id = null;
public function mount(): void
{
$this->name = Auth::user()->name;
$this->email = Auth::user()->email;
$this->timezone = Auth::user()->timezone;
$this->preferred_backup_destination_id = Auth::user()->preferred_backup_destination_id ?? null;
}
public function updateProfileInformation(): void
Expand All @@ -27,6 +29,7 @@ public function updateProfileInformation(): void
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', Rule::unique(User::class)->ignore($user->id)],
'timezone' => ['required', 'string', 'max:255', Rule::in(timezone_identifiers_list())],
'preferred_backup_destination_id' => ['nullable', 'integer', Rule::exists('backup_destinations', 'id')->where('user_id', $user->id)],
]);
$user->fill($validated);
Expand Down Expand Up @@ -140,6 +143,23 @@ class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 da
<x-input-error class="mt-2" :messages="$errors->get('timezone')"/>
</div>

@if (!Auth::user()->backupDestinations->isEmpty())
<div>
<x-input-label for="preferred_backup_destination_id" :value="__('Default Backup Destination')"/>
<x-select wire:model="preferred_backup_destination_id" id="preferred_backup_destination_id"
name="preferred_backup_destination_id" class="mt-1 block w-full">
<option value="">{{ __('None') }}</option>
@foreach (Auth::user()->backupDestinations as $backupDestination)
<option value="{{ $backupDestination->id }}">{{ $backupDestination->label }} - {{$backupDestination->type() }}</option>
@endforeach
</x-select>
<x-input-explain>
{{ __('The backup destination you select here will be set as the default location for storing new backup tasks.') }}
</x-input-explain>
<x-input-error class="mt-2" :messages="$errors->get('preferred_backup_destination_id')"/>
</div>
@endif

<div class="flex items-center gap-4">
<x-primary-button>
{{ __('Save') }}
Expand Down
71 changes: 71 additions & 0 deletions tests/Feature/Profile/ProfileTest.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use App\Models\BackupDestination;
use App\Models\User;
use Livewire\Volt\Volt;

Expand All @@ -20,13 +21,17 @@
test('profile information can be updated', function () {
Toaster::fake();
$user = User::factory()->create();
$backupDestination = BackupDestination::factory()->create([
'user_id' => $user->id,
]);

$this->actingAs($user);

$component = Volt::test('profile.update-profile-information-form')
->set('name', 'Test User')
->set('email', '[email protected]')
->set('timezone', 'America/New_York')
->set('preferred_backup_destination_id', $backupDestination->id)
->call('updateProfileInformation');

$component
Expand All @@ -38,6 +43,7 @@
$this->assertSame('Test User', $user->name);
$this->assertSame('[email protected]', $user->email);
$this->assertSame('America/New_York', $user->timezone);
$this->assertSame($backupDestination->id, $user->preferred_backup_destination_id);
$this->assertNull($user->email_verified_at);

Toaster::assertDispatched((__('Profile details saved.')));
Expand Down Expand Up @@ -109,3 +115,68 @@
->assertHasErrors('timezone')
->assertNoRedirect();
});

test('the preferred backup destination can be nullable - not set', function () {

$user = User::factory()->create();

$this->actingAs($user);

$component = Volt::test('profile.update-profile-information-form')
->set('name', 'Test User')
->set('email', '[email protected]')
->set('timezone', 'America/New_York')
->call('updateProfileInformation');

$component
->assertHasNoErrors()
->assertNoRedirect();

$user->refresh();

$this->assertNull($user->preferred_backup_destination_id);
});

test('the preferred backup destination must exist', function () {

$user = User::factory()->create();

$this->actingAs($user);

$component = Volt::test('profile.update-profile-information-form')
->set('name', 'Test User')
->set('email', '[email protected]')
->set('timezone', 'America/New_York')
->set('preferred_backup_destination_id', 999)
->call('updateProfileInformation');

$component
->assertHasErrors('preferred_backup_destination_id')
->assertNoRedirect();

$this->assertNull($user->refresh()->preferred_backup_destination_id);
});

test('the preferred backup destination must belong to the user', function () {

$user = User::factory()->create();
$otherUser = User::factory()->create();
$backupDestination = BackupDestination::factory()->create([
'user_id' => $otherUser->id,
]);

$this->actingAs($user);

$component = Volt::test('profile.update-profile-information-form')
->set('name', 'Test User')
->set('email', '[email protected]')
->set('timezone', 'America/New_York')
->set('preferred_backup_destination_id', $backupDestination->id)
->call('updateProfileInformation');

$component
->assertHasErrors('preferred_backup_destination_id')
->assertNoRedirect();

$this->assertNull($user->refresh()->preferred_backup_destination_id);
});

0 comments on commit 94e7246

Please sign in to comment.