@php
$current_image_uuid =$device->current_screen_image;
- $current_image_path = 'images/generated/' . $current_image_uuid . '.png';
+ file_exists('storage/images/generated/' . $current_image_uuid . '.png') ? $file_extension = 'png' : $file_extension = 'bmp';
+ $current_image_path = 'storage/images/generated/' . $current_image_uuid . '.' . $file_extension;
@endphp
{{ $device->name }}
diff --git a/resources/views/livewire/device-manager.blade.php b/resources/views/livewire/device-manager.blade.php
deleted file mode 100644
index 3668c94..0000000
--- a/resources/views/livewire/device-manager.blade.php
+++ /dev/null
@@ -1,124 +0,0 @@
-
- {{--@dump($devices)--}}
-
-
-
Devices
-
- Add Device
-
-
- @if (session()->has('message'))
-
- {{ session('message') }}
-
- @endif
-
-
-
-
-
-
-
-
- |
- Name
- |
-
- Friendly ID
- |
-
- Mac Address
- |
-
- Refresh
- |
-
- Actions
- |
-
-
-
-
- @foreach ($devices as $device)
-
- |
- {{ $device->name }}
- |
-
- {{ $device->friendly_id }}
- |
-
-
- {{ $device->mac_address }}
-
- |
-
- {{ $device->default_refresh_interval }}
- |
-
-
-
- |
-
- @endforeach
-
-
-
-
-
-
diff --git a/resources/views/livewire/devices/configure.blade.php b/resources/views/livewire/devices/configure.blade.php
new file mode 100644
index 0000000..583b725
--- /dev/null
+++ b/resources/views/livewire/devices/configure.blade.php
@@ -0,0 +1,120 @@
+user()->devices->contains($device), 403);
+
+ $current_image_uuid = $device->current_screen_image;
+ $current_image_path = 'images/generated/' . $current_image_uuid . '.png';
+
+ return view('livewire.devices.configure', compact('device'), [
+ 'image' => ($current_image_uuid) ? url($current_image_path) : null,
+ ]);
+ }
+
+ public function deleteDevice(\App\Models\Device $device)
+ {
+ abort_unless(auth()->user()->devices->contains($device), 403);
+ $device->delete();
+
+ redirect()->route('devices');
+ }
+}
+?>
+
+
+
+
+
+ @php
+ $current_image_uuid =$device->current_screen_image;
+ file_exists('storage/images/generated/' . $current_image_uuid . '.png') ? $file_extension = 'png' : $file_extension = 'bmp';
+ $current_image_path = 'storage/images/generated/' . $current_image_uuid . '.' . $file_extension;
+ @endphp
+
+
+
+ {{ $device->name }}
+
+
+
+
+
+
+
+
+
+
+
+ {{$device->updated_at->diffForHumans()}}
+
+
+
+ {{$device->mac_address}}
+
+
+
+ {{$device->last_firmware_version}}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{-- Edit TRMNL--}}
+ {{-- --}}
+
+
+ {{--
--}}
+
+
+
+
+
+
+
+ {{-- Save changes--}}
+
+
+
+
+
+
+ Delete {{$device->name}}?
+
+
+
+
+
+
+ Cancel
+
+ Delete device
+
+
+
+
+ @if($current_image_uuid)
+
+
 }})
+ @endif
+
+
+
+
+
diff --git a/resources/views/livewire/devices/manage.blade.php b/resources/views/livewire/devices/manage.blade.php
new file mode 100644
index 0000000..e3935d0
--- /dev/null
+++ b/resources/views/livewire/devices/manage.blade.php
@@ -0,0 +1,205 @@
+ 'required',
+ 'api_key' => 'required',
+ 'default_refresh_interval' => 'required|integer',
+ ];
+
+ public function mount()
+ {
+ $this->devices = auth()->user()->devices;
+ return view('livewire.devices.manage');
+ }
+
+ public function createDevice(): void
+ {
+ $this->validate();
+
+ Device::create([
+ 'name' => $this->name,
+ 'mac_address' => $this->mac_address,
+ 'api_key' => $this->api_key,
+ 'default_refresh_interval' => $this->default_refresh_interval,
+ 'friendly_id' => $this->friendly_id,
+ 'user_id' => auth()->id(),
+ ]);
+
+ $this->reset();
+ \Flux::modal('create-device')->close();
+
+ $this->devices = auth()->user()->devices;
+ session()->flash('message', 'Device created successfully.');
+ }
+
+ public function toggleProxyCloud(Device $device): void
+ {
+ abort_unless(auth()->user()->devices->contains($device), 403);
+ $device->update([
+ 'proxy_cloud' => !$device->proxy_cloud,
+ ]);
+
+ // if ($device->proxy_cloud) {
+ // \App\Jobs\FetchProxyCloudResponses::dispatch();
+ // }
+ }
+}
+
+?>
+
+
+
+ {{--@dump($devices)--}}
+
+
+
Devices
+
+ Add Device
+
+
+ @if (session()->has('message'))
+
+ {{ session('message') }}
+
+ @endif
+
+
+
+
+
+
+
+
+ |
+ Name
+ |
+
+ Friendly ID
+ |
+
+ Mac Address
+ |
+
+ Refresh
+ |
+
+ Actions
+ |
+
+
+
+
+ @foreach ($devices as $device)
+
+ |
+ {{ $device->name }}
+ |
+
+ {{ $device->friendly_id }}
+ |
+
+
+ {{ $device->mac_address }}
+
+ |
+
+ {{ $device->default_refresh_interval }}
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+ @endforeach
+
+
+
+
+
+
+
+
diff --git a/resources/views/livewire/plugins/api.blade.php b/resources/views/livewire/plugins/api.blade.php
new file mode 100644
index 0000000..117e348
--- /dev/null
+++ b/resources/views/livewire/plugins/api.blade.php
@@ -0,0 +1,56 @@
+tokens()?->first();
+ if ($token === null) {
+ $token = Auth::user()->createToken('api-token', ['update-screen']);
+ }
+ $this->token = $token->plainTextToken;
+ }
+
+ public function regenerateToken()
+ {
+ Auth::user()->tokens()?->first()?->delete();
+ $token = Auth::user()->createToken('api-token', ['update-screen']);
+ $this->token = $token->plainTextToken;
+ }
+};
+?>
+
+
+
+
+
API
+
+
+
+
+ POST
+ {{route('display.update')}}
+
+
+
Headers
+
Authorization Bearer {{$token ?? '**********'}}
+
+ Regenerate Token
+
+
+
+
+
+
Body
+
+
+{"markup":"<h1>Hello World</h1>"}
+
+
+
+
+
+
diff --git a/resources/views/livewire/plugins/index.blade.php b/resources/views/livewire/plugins/index.blade.php
new file mode 100644
index 0000000..562ef30
--- /dev/null
+++ b/resources/views/livewire/plugins/index.blade.php
@@ -0,0 +1,36 @@
+
+ ['name' => 'Markup', 'icon' => 'code-backet', 'route' => 'plugins.markup'],
+ 'api' =>
+ ['name' => 'API', 'icon' => 'code-backet', 'route' => 'plugins.api'],
+ ];
+
+};
+?>
+
+
+
+
+
Plugins
+
+
+ @foreach($plugins as $plugin)
+
+ @endforeach
+
+
+
diff --git a/resources/views/livewire/plugins/markup.blade.php b/resources/views/livewire/plugins/markup.blade.php
new file mode 100644
index 0000000..7b6d300
--- /dev/null
+++ b/resources/views/livewire/plugins/markup.blade.php
@@ -0,0 +1,171 @@
+isLoading = true;
+
+ $this->validate([
+ 'blade_code' => 'required|string'
+ ]);
+
+ try {
+ $rendered = Blade::render($this->blade_code);
+
+// if (config('app.puppeteer_docker')) {
+// GenerateScreenJob::dispatch(auth()->user()->devices()->first()->id, $rendered);
+// } else {
+ GenerateScreenJob::dispatchSync(auth()->user()->devices()->first()->id, $rendered);
+// }
+
+ } catch (\Exception $e) {
+ $this->addError('error', $e->getMessage());
+ }
+
+ $this->isLoading = false;
+ }
+
+ public function renderExample(string $example)
+ {
+ switch ($example) {
+ case 'quote':
+ $markup = $this->renderQuote();
+ break;
+ case 'trainMonitor':
+ $markup = $this->renderTrainMonitor();
+ break;
+ case 'homeAssistant':
+ $markup = $this->renderHomeAssistant();
+ break;
+ default:
+ $markup = '
Hello World!
';
+ break;
+ }
+ $this->blade_code = $markup;
+ }
+
+ public function renderQuote(): string
+ {
+ return <<
+
+
+ Motivational Quote
+ “I love inside jokes. I hope to be a part of one someday.”
+ Michael Scott
+
+
+
+
+HTML;
+ }
+
+ public function renderTrainMonitor()
+ {
+ return <<
+
+
+
+
+ | Abfahrt |
+ Aktuell |
+ Zug |
+ Ziel |
+ Steig |
+
+
+
+
+ | 08:51 |
+ 08:52 |
+ REX 1 |
+ Vienna Main Station |
+ 3 |
+
+
+
+
+
+
+HTML;
+
+ }
+
+ public function renderHomeAssistant()
+ {
+ return <<
+
+
+
+
+
+
+ 23.3°
+
+
+ 47.52 %
+
+ Sensor 1
+
+
+
+
+
+
+
+HTML;
+
+ }
+
+
+};
+?>
+
+
diff --git a/routes/api.php b/routes/api.php
index b44e491..d89d483 100644
--- a/routes/api.php
+++ b/routes/api.php
@@ -1,21 +1,39 @@
header('id');
$access_token = $request->header('access-token');
-
$device = Device::where('mac_address', $mac_address)
->where('api_key', $access_token)
->first();
+
if (! $device) {
- return response()->json([
- 'message' => 'MAC Address not registered or invalid access token',
- ], 404);
+ // Check if there's a user with assign_new_devices enabled
+ $auto_assign_user = User::where('assign_new_devices', true)->first();
+
+ if ($auto_assign_user) {
+ // Create a new device and assign it to this user
+ $device = Device::create([
+ 'mac_address' => $mac_address,
+ 'api_key' => $access_token,
+ 'user_id' => $auto_assign_user->id,
+ 'name' => "{$auto_assign_user->name}'s TRMNL",
+ 'friendly_id' => Str::random(6),
+ 'default_refresh_interval' => 900,
+ ]);
+ } else {
+ return response()->json([
+ 'message' => 'MAC Address not registered or invalid access token',
+ ], 404);
+ }
}
$device->update([
@@ -25,9 +43,13 @@ Route::get('/display', function (Request $request) {
]);
$image_uuid = $device->current_screen_image;
-
- $image_path = 'images/generated/'.$image_uuid.'.bmp';
- $filename = basename($image_path);
+ if (! $image_uuid) {
+ $image_path = 'images/setup-logo.bmp';
+ $filename = 'setup-logo.bmp';
+ } else {
+ $image_path = 'images/generated/'.$image_uuid.'.bmp';
+ $filename = basename($image_path);
+ }
return response()->json([
'status' => '0',
@@ -67,8 +89,24 @@ Route::get('/setup', function (Request $request) {
});
Route::post('/log', function (Request $request) {
- $logs = $request->json('log.logs_array', []);
+ $mac_address = $request->header('id');
+ $access_token = $request->header('access-token');
+ $device = Device::where('mac_address', $mac_address)
+ ->where('api_key', $access_token)
+ ->first();
+
+ if (! $device) {
+ return response()->json([
+ 'message' => 'Device not found or invalid access token',
+ ], 404);
+ }
+
+ $device->update([
+ 'last_log_request' => $request->json()->all(),
+ ]);
+
+ $logs = $request->json('log.logs_array', []);
foreach ($logs as $log) {
\Log::info('Device Log', $log);
}
@@ -81,3 +119,23 @@ Route::post('/log', function (Request $request) {
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
+
+Route::post('/display/update', function (Request $request) {
+ $request->validate([
+ 'device_id' => 'required|exists:devices,id',
+ 'markup' => 'required|string',
+ ]);
+
+ $deviceId = $request['device_id'];
+ abort_unless($request->user()->devices->contains($deviceId), 403);
+
+ $view = Blade::render($request['markup']);
+
+ GenerateScreenJob::dispatchSync($deviceId, $view);
+
+ response()->json([
+ 'message' => 'success',
+ ]);
+})
+ ->name('display.update')
+ ->middleware('auth:sanctum', 'ability:update-screen');
diff --git a/routes/auth.php b/routes/auth.php
index 62e6352..5647405 100644
--- a/routes/auth.php
+++ b/routes/auth.php
@@ -8,8 +8,10 @@ Route::middleware('guest')->group(function () {
Volt::route('login', 'auth.login')
->name('login');
- Volt::route('register', 'auth.register')
- ->name('register');
+ if (config('app.registration.enabled')) {
+ Volt::route('register', 'auth.register')
+ ->name('register');
+ }
Volt::route('forgot-password', 'auth.forgot-password')
->name('password.request');
diff --git a/routes/console.php b/routes/console.php
index aaf16f7..b4cff25 100644
--- a/routes/console.php
+++ b/routes/console.php
@@ -1,8 +1,9 @@
comment(Inspiring::quote());
-//})->purpose('Display an inspiring quote')->hourly();
+// })->purpose('Display an inspiring quote')->hourly();
+
+Schedule::job(new FetchProxyCloudResponses)->everyFifteenMinutes();
diff --git a/routes/web.php b/routes/web.php
index e81cf05..355b892 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -7,30 +7,21 @@ Route::get('/', function () {
return view('welcome');
})->name('home');
-Route::view('dashboard', 'dashboard')
- ->middleware(['auth', 'verified'])
- ->name('dashboard');
-
Route::middleware(['auth'])->group(function () {
Route::redirect('settings', 'settings/profile');
-
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');
- Route::get('/devices', function () {
- return view('devices');
- })->name('devices');
+ Volt::route('/dashboard', 'device-dashboard')->name('dashboard');
- Route::get('/devices/{device}/configure', function (App\Models\Device $device) {
- $current_image_uuid = auth()->user()->devices()->find($device->id)->current_screen_image;
- $current_image_path = 'images/generated/' . $current_image_uuid . '.png';
+ Volt::route('/devices', 'devices.manage')->name('devices');
+ Volt::route('/devices/{device}/configure', 'devices.configure')->name('devices.configure');
- return view('devices.configure', compact('device'), [
- 'image' => ($current_image_uuid) ? url($current_image_path) : null,
- ]);
- })->name('devices.configure');
+ Volt::route('plugins', 'plugins.index')->name('plugins.index');
+ Volt::route('plugins/markup', 'plugins.markup')->name('plugins.markup');
+ Volt::route('plugins/api', 'plugins.api')->name('plugins.api');
});
-require __DIR__ . '/auth.php';
+require __DIR__.'/auth.php';
diff --git a/tests/Feature/Auth/AuthenticationTest.php b/tests/Feature/Auth/AuthenticationTest.php
index 10df8e5..61d04f1 100644
--- a/tests/Feature/Auth/AuthenticationTest.php
+++ b/tests/Feature/Auth/AuthenticationTest.php
@@ -44,4 +44,4 @@ test('users can logout', function () {
$this->assertGuest();
$response->assertRedirect('/');
-});
\ No newline at end of file
+});
diff --git a/tests/Feature/Auth/EmailVerificationTest.php b/tests/Feature/Auth/EmailVerificationTest.php
index 2880c6b..37a205f 100644
--- a/tests/Feature/Auth/EmailVerificationTest.php
+++ b/tests/Feature/Auth/EmailVerificationTest.php
@@ -46,4 +46,4 @@ test('email is not verified with invalid hash', function () {
$this->actingAs($user)->get($verificationUrl);
expect($user->fresh()->hasVerifiedEmail())->toBeFalse();
-});
\ No newline at end of file
+});
diff --git a/tests/Feature/Auth/PasswordConfirmationTest.php b/tests/Feature/Auth/PasswordConfirmationTest.php
index ba015f6..3f9b423 100644
--- a/tests/Feature/Auth/PasswordConfirmationTest.php
+++ b/tests/Feature/Auth/PasswordConfirmationTest.php
@@ -37,4 +37,4 @@ test('password is not confirmed with invalid password', function () {
->call('confirmPassword');
$response->assertHasErrors(['password']);
-});
\ No newline at end of file
+});
diff --git a/tests/Feature/Auth/PasswordResetTest.php b/tests/Feature/Auth/PasswordResetTest.php
index 859312d..b678d73 100644
--- a/tests/Feature/Auth/PasswordResetTest.php
+++ b/tests/Feature/Auth/PasswordResetTest.php
@@ -65,4 +65,4 @@ test('password can be reset with valid token', function () {
return true;
});
-});
\ No newline at end of file
+});
diff --git a/tests/Feature/Auth/RegistrationTest.php b/tests/Feature/Auth/RegistrationTest.php
index 399e6a6..1ef6256 100644
--- a/tests/Feature/Auth/RegistrationTest.php
+++ b/tests/Feature/Auth/RegistrationTest.php
@@ -23,4 +23,4 @@ test('new users can register', function () {
->assertRedirect(route('dashboard', absolute: false));
$this->assertAuthenticated();
-});
\ No newline at end of file
+});
diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php
index 26d1d03..e11099a 100644
--- a/tests/Feature/DashboardTest.php
+++ b/tests/Feature/DashboardTest.php
@@ -15,4 +15,4 @@ test('authenticated users can visit the dashboard', function () {
$response = $this->get('/dashboard');
$response->assertStatus(200);
-});
\ No newline at end of file
+});
diff --git a/tests/Feature/Settings/PasswordUpdateTest.php b/tests/Feature/Settings/PasswordUpdateTest.php
index 5cc1209..d0c32c5 100644
--- a/tests/Feature/Settings/PasswordUpdateTest.php
+++ b/tests/Feature/Settings/PasswordUpdateTest.php
@@ -38,4 +38,4 @@ test('correct password must be provided to update password', function () {
->call('updatePassword');
$response->assertHasErrors(['current_password']);
-});
\ No newline at end of file
+});
diff --git a/tests/Feature/Settings/ProfileUpdateTest.php b/tests/Feature/Settings/ProfileUpdateTest.php
index d876e5d..6628ccc 100644
--- a/tests/Feature/Settings/ProfileUpdateTest.php
+++ b/tests/Feature/Settings/ProfileUpdateTest.php
@@ -74,4 +74,4 @@ test('correct password must be provided to delete account', function () {
$response->assertHasErrors(['password']);
expect($user->fresh())->not->toBeNull();
-});
\ No newline at end of file
+});