mirror of
https://github.com/usetrmnl/byos_laravel.git
synced 2026-01-13 15:07:49 +00:00
feat(#20): preference: assign mirror device id to auto joined devices
This commit is contained in:
parent
b4dfb1673f
commit
8d7a53b888
8 changed files with 138 additions and 2 deletions
|
|
@ -25,6 +25,7 @@ class User extends Authenticatable // implements MustVerifyEmail
|
|||
'email',
|
||||
'password',
|
||||
'assign_new_devices',
|
||||
'assign_new_device_id'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->foreignId('assign_new_device_id')->nullable()->constrained('devices')->nullOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropForeign(['assign_new_device_id']);
|
||||
$table->dropColumn('assign_new_device_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
<flux:menu.separator/>
|
||||
|
||||
<flux:menu.radio.group>
|
||||
<flux:menu.item href="/settings/profile" wire:navigate icon="cog">Settings</flux:menu.item>
|
||||
<flux:menu.item href="/settings/preferences" wire:navigate icon="cog">Settings</flux:menu.item>
|
||||
</flux:menu.radio.group>
|
||||
|
||||
<flux:menu.separator/>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<div class="flex items-start max-md:flex-col">
|
||||
<div class="mr-10 w-full pb-4 md:w-[220px]">
|
||||
<flux:navlist>
|
||||
<flux:navlist.item href="{{ route('settings.preferences') }}" wire:navigate>Preferences</flux:navlist.item>
|
||||
<flux:navlist.item href="{{ route('settings.profile') }}" wire:navigate>Profile</flux:navlist.item>
|
||||
<flux:navlist.item href="{{ route('settings.password') }}" wire:navigate>Password</flux:navlist.item>
|
||||
<flux:navlist.item href="{{ route('settings.appearance') }}" wire:navigate>Appearance</flux:navlist.item>
|
||||
|
|
|
|||
63
resources/views/livewire/settings/preferences.blade.php
Normal file
63
resources/views/livewire/settings/preferences.blade.php
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Device;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Livewire\Volt\Component;
|
||||
|
||||
new class extends Component {
|
||||
public ?int $assign_new_device_id = null;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->assign_new_device_id = Auth::user()->assign_new_device_id;
|
||||
}
|
||||
|
||||
public function updatePreferences(): void
|
||||
{
|
||||
$validated = $this->validate([
|
||||
'assign_new_device_id' => [
|
||||
'nullable',
|
||||
Rule::exists('devices', 'id')->where(function ($query) {
|
||||
$query->where('user_id', Auth::id())
|
||||
->whereNull('mirror_device_id');
|
||||
}),
|
||||
],
|
||||
]);
|
||||
|
||||
Auth::user()->update($validated);
|
||||
|
||||
$this->dispatch('profile-updated');
|
||||
}
|
||||
}; ?>
|
||||
|
||||
<section class="w-full">
|
||||
@include('partials.settings-heading')
|
||||
|
||||
<x-settings.layout heading="Preferences" subheading="Update your preferences">
|
||||
<form wire:submit="updatePreferences" class="my-6 w-full space-y-6">
|
||||
<flux:select wire:model="assign_new_device_id" label="Auto-Joined Devices should mirror">
|
||||
<flux:select.option value="">None</flux:select.option>
|
||||
@foreach(auth()->user()->devices->where('mirror_device_id', null) as $device)
|
||||
<flux:select.option value="{{ $device->id }}">
|
||||
{{ $device->name }} ({{ $device->friendly_id }})
|
||||
</flux:select.option>
|
||||
@endforeach
|
||||
</flux:select>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex items-center justify-end">
|
||||
<flux:button variant="primary" type="submit" class="w-full">{{ __('Save') }}</flux:button>
|
||||
</div>
|
||||
|
||||
<x-action-message class="me-3" on="profile-updated">
|
||||
{{ __('Saved.') }}
|
||||
</x-action-message>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</x-settings.layout>
|
||||
</section>
|
||||
|
|
@ -28,6 +28,7 @@ Route::get('/display', function (Request $request) {
|
|||
'name' => "{$auto_assign_user->name}'s TRMNL",
|
||||
'friendly_id' => Str::random(6),
|
||||
'default_refresh_interval' => 900,
|
||||
'mirror_device_id' => $auto_assign_user->assign_new_device_id,
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
|
|
@ -135,6 +136,7 @@ Route::get('/setup', function (Request $request) {
|
|||
'name' => "{$auto_assign_user->name}'s TRMNL",
|
||||
'friendly_id' => Str::random(6),
|
||||
'default_refresh_interval' => 900,
|
||||
'mirror_device_id' => $auto_assign_user->assign_new_device_id,
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ Route::get('/', function () {
|
|||
})->name('home');
|
||||
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::redirect('settings', 'settings/profile');
|
||||
Route::redirect('settings', 'settings/preferences');
|
||||
Volt::route('settings/preferences', 'settings.preferences')->name('settings.preferences');
|
||||
Volt::route('settings/profile', 'settings.profile')->name('settings.profile');
|
||||
Volt::route('settings/password', 'settings.password')->name('settings.password');
|
||||
Volt::route('settings/appearance', 'settings.appearance')->name('settings.appearance');
|
||||
|
|
|
|||
|
|
@ -105,6 +105,45 @@ test('new device is auto-assigned to user with auto-assign enabled', function ()
|
|||
->api_key->toBe('new-device-key');
|
||||
});
|
||||
|
||||
test('new device is auto-assigned and mirrors specified device', function () {
|
||||
// Create a source device that will be mirrored
|
||||
$sourceDevice = Device::factory()->create([
|
||||
'mac_address' => 'AA:BB:CC:DD:EE:FF',
|
||||
'api_key' => 'source-api-key',
|
||||
'current_screen_image' => 'source-image',
|
||||
]);
|
||||
|
||||
// Create user with auto-assign enabled and mirror device set
|
||||
$user = User::factory()->create([
|
||||
'assign_new_devices' => true,
|
||||
'assign_new_device_id' => $sourceDevice->id,
|
||||
]);
|
||||
|
||||
// Make request from new device
|
||||
$response = $this->withHeaders([
|
||||
'id' => '00:11:22:33:44:55',
|
||||
'access-token' => 'new-device-key',
|
||||
'rssi' => -70,
|
||||
'battery_voltage' => 3.8,
|
||||
'fw-version' => '1.0.0',
|
||||
])->get('/api/display');
|
||||
|
||||
$response->assertOk();
|
||||
|
||||
// Verify the new device was created and mirrors the source device
|
||||
$newDevice = Device::where('mac_address', '00:11:22:33:44:55')->first();
|
||||
expect($newDevice)
|
||||
->not->toBeNull()
|
||||
->user_id->toBe($user->id)
|
||||
->api_key->toBe('new-device-key')
|
||||
->mirror_device_id->toBe($sourceDevice->id);
|
||||
|
||||
// Verify the response contains the source device's image
|
||||
$response->assertJson([
|
||||
'filename' => 'source-image.bmp',
|
||||
]);
|
||||
});
|
||||
|
||||
test('device setup endpoint returns correct data', function () {
|
||||
$device = Device::factory()->create([
|
||||
'mac_address' => '00:11:22:33:44:55',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue