add features

* feat: autojoin toggle
* feat: auto add devices
* feat: proxy feature
* feat: support puppeteer in docker
* feat: toggle to activate cloud proxy
* feat: relay device information
* feat: relay logs to cloud
* feat: migrate on start
* feat: calculate battery state, wifi signal
* feat: eye candy for configure view
* feat: update via api
This commit is contained in:
Benjamin Nussbaum 2025-02-26 09:33:54 +01:00
parent d4eb832186
commit 715e6a2562
53 changed files with 1459 additions and 460 deletions

View file

@ -1,21 +1,39 @@
<?php
use App\Jobs\GenerateScreenJob;
use App\Models\Device;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;
Route::get('/display', function (Request $request) {
$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' => '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');

View file

@ -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');

View file

@ -1,8 +1,9 @@
<?php
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use App\Jobs\FetchProxyCloudResponses;
//Artisan::command('inspire', function () {
// Artisan::command('inspire', function () {
// $this->comment(Inspiring::quote());
//})->purpose('Display an inspiring quote')->hourly();
// })->purpose('Display an inspiring quote')->hourly();
Schedule::job(new FetchProxyCloudResponses)->everyFifteenMinutes();

View file

@ -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';