chore: pint

This commit is contained in:
Benjamin Nussbaum 2025-08-26 11:17:09 +02:00
parent 25f36eaf54
commit 4c66761baa
12 changed files with 142 additions and 121 deletions

View file

@ -2,7 +2,9 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use Exception;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use InvalidArgumentException;
use Laravel\Socialite\Facades\Socialite; use Laravel\Socialite\Facades\Socialite;
class OidcTestCommand extends Command class OidcTestCommand extends Command
@ -31,7 +33,7 @@ class OidcTestCommand extends Command
// Check if OIDC is enabled // Check if OIDC is enabled
$enabled = config('services.oidc.enabled'); $enabled = config('services.oidc.enabled');
$this->line("OIDC Enabled: " . ($enabled ? '✅ Yes' : '❌ No')); $this->line('OIDC Enabled: '.($enabled ? '✅ Yes' : '❌ No'));
// Check configuration values // Check configuration values
$endpoint = config('services.oidc.endpoint'); $endpoint = config('services.oidc.endpoint');
@ -40,11 +42,11 @@ class OidcTestCommand extends Command
$redirect = config('services.oidc.redirect'); $redirect = config('services.oidc.redirect');
$scopes = config('services.oidc.scopes', []); $scopes = config('services.oidc.scopes', []);
$this->line("OIDC Endpoint: " . ($endpoint ? "{$endpoint}" : '❌ Not set')); $this->line('OIDC Endpoint: '.($endpoint ? "{$endpoint}" : '❌ Not set'));
$this->line("Client ID: " . ($clientId ? "{$clientId}" : '❌ Not set')); $this->line('Client ID: '.($clientId ? "{$clientId}" : '❌ Not set'));
$this->line("Client Secret: " . ($clientSecret ? '✅ Set' : '❌ Not set')); $this->line('Client Secret: '.($clientSecret ? '✅ Set' : '❌ Not set'));
$this->line("Redirect URL: " . ($redirect ? "{$redirect}" : '❌ Not set')); $this->line('Redirect URL: '.($redirect ? "{$redirect}" : '❌ Not set'));
$this->line("Scopes: " . (empty($scopes) ? '❌ Not set' : '✅ ' . implode(', ', $scopes))); $this->line('Scopes: '.(empty($scopes) ? '❌ Not set' : '✅ '.implode(', ', $scopes)));
$this->newLine(); $this->newLine();
@ -53,38 +55,45 @@ class OidcTestCommand extends Command
// Only test driver if we have basic configuration // Only test driver if we have basic configuration
if ($endpoint && $clientId && $clientSecret) { if ($endpoint && $clientId && $clientSecret) {
$driver = Socialite::driver('oidc'); $driver = Socialite::driver('oidc');
$this->line("OIDC Driver: ✅ Successfully registered and accessible"); $this->line('OIDC Driver: ✅ Successfully registered and accessible');
if ($enabled) { if ($enabled) {
$this->info("✅ OIDC is fully configured and ready to use!"); $this->info('✅ OIDC is fully configured and ready to use!');
$this->line("You can test the login flow at: /auth/oidc/redirect"); $this->line('You can test the login flow at: /auth/oidc/redirect');
} else { } else {
$this->warn("⚠️ OIDC driver is working but OIDC_ENABLED is false."); $this->warn('⚠️ OIDC driver is working but OIDC_ENABLED is false.');
} }
} else { } else {
$this->line("OIDC Driver: ✅ Registered (configuration test skipped due to missing values)"); $this->line('OIDC Driver: ✅ Registered (configuration test skipped due to missing values)');
$this->warn("⚠️ OIDC driver is registered but missing required configuration."); $this->warn('⚠️ OIDC driver is registered but missing required configuration.');
$this->line("Please set the following environment variables:"); $this->line('Please set the following environment variables:');
if (!$enabled) $this->line(" - OIDC_ENABLED=true"); if (! $enabled) {
$this->line(' - OIDC_ENABLED=true');
}
if (! $endpoint) { if (! $endpoint) {
$this->line(" - OIDC_ENDPOINT=https://your-oidc-provider.com (base URL)"); $this->line(' - OIDC_ENDPOINT=https://your-oidc-provider.com (base URL)');
$this->line(" OR"); $this->line(' OR');
$this->line(" - OIDC_ENDPOINT=https://your-oidc-provider.com/.well-known/openid-configuration (full URL)"); $this->line(' - OIDC_ENDPOINT=https://your-oidc-provider.com/.well-known/openid-configuration (full URL)');
} }
if (!$clientId) $this->line(" - OIDC_CLIENT_ID=your-client-id"); if (! $clientId) {
if (!$clientSecret) $this->line(" - OIDC_CLIENT_SECRET=your-client-secret"); $this->line(' - OIDC_CLIENT_ID=your-client-id');
} }
} catch (\InvalidArgumentException $e) { if (! $clientSecret) {
$this->line(' - OIDC_CLIENT_SECRET=your-client-secret');
}
}
} catch (InvalidArgumentException $e) {
if (str_contains($e->getMessage(), 'Driver [oidc] not supported')) { if (str_contains($e->getMessage(), 'Driver [oidc] not supported')) {
$this->error("❌ OIDC Driver registration failed: Driver not supported"); $this->error('❌ OIDC Driver registration failed: Driver not supported');
} else { } else {
$this->error("❌ OIDC Driver error: " . $e->getMessage()); $this->error('❌ OIDC Driver error: '.$e->getMessage());
} }
} catch (\Exception $e) { } catch (Exception $e) {
$this->warn("⚠️ OIDC Driver registered but configuration error: " . $e->getMessage()); $this->warn('⚠️ OIDC Driver registered but configuration error: '.$e->getMessage());
} }
$this->newLine(); $this->newLine();
return Command::SUCCESS; return Command::SUCCESS;
} }
} }

View file

@ -4,6 +4,7 @@ namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\User; use App\Models\User;
use Exception;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@ -26,14 +27,16 @@ class OidcController extends Controller
foreach ($requiredConfig as $key) { foreach ($requiredConfig as $key) {
if (! config("services.oidc.{$key}")) { if (! config("services.oidc.{$key}")) {
Log::error("OIDC configuration missing: {$key}"); Log::error("OIDC configuration missing: {$key}");
return redirect()->route('login')->withErrors(['oidc' => 'OIDC is not properly configured.']); return redirect()->route('login')->withErrors(['oidc' => 'OIDC is not properly configured.']);
} }
} }
try { try {
return Socialite::driver('oidc')->redirect(); return Socialite::driver('oidc')->redirect();
} catch (\Exception $e) { } catch (Exception $e) {
Log::error('OIDC redirect error: '.$e->getMessage()); Log::error('OIDC redirect error: '.$e->getMessage());
return redirect()->route('login')->withErrors(['oidc' => 'Failed to initiate OIDC authentication.']); return redirect()->route('login')->withErrors(['oidc' => 'Failed to initiate OIDC authentication.']);
} }
} }
@ -52,6 +55,7 @@ class OidcController extends Controller
foreach ($requiredConfig as $key) { foreach ($requiredConfig as $key) {
if (! config("services.oidc.{$key}")) { if (! config("services.oidc.{$key}")) {
Log::error("OIDC configuration missing: {$key}"); Log::error("OIDC configuration missing: {$key}");
return redirect()->route('login')->withErrors(['oidc' => 'OIDC is not properly configured.']); return redirect()->route('login')->withErrors(['oidc' => 'OIDC is not properly configured.']);
} }
} }
@ -67,8 +71,9 @@ class OidcController extends Controller
return redirect()->intended(route('dashboard', absolute: false)); return redirect()->intended(route('dashboard', absolute: false));
} catch (\Exception $e) { } catch (Exception $e) {
Log::error('OIDC callback error: '.$e->getMessage()); Log::error('OIDC callback error: '.$e->getMessage());
return redirect()->route('login')->withErrors(['oidc' => 'Failed to authenticate with OIDC provider.']); return redirect()->route('login')->withErrors(['oidc' => 'Failed to authenticate with OIDC provider.']);
} }
} }
@ -87,6 +92,7 @@ class OidcController extends Controller
'name' => $oidcUser->getName() ?: $user->name, 'name' => $oidcUser->getName() ?: $user->name,
'email' => $oidcUser->getEmail() ?: $user->email, 'email' => $oidcUser->getEmail() ?: $user->email,
]); ]);
return $user; return $user;
} }
@ -100,6 +106,7 @@ class OidcController extends Controller
'oidc_sub' => $oidcUser->getId(), 'oidc_sub' => $oidcUser->getId(),
'name' => $oidcUser->getName() ?: $user->name, 'name' => $oidcUser->getName() ?: $user->name,
]); ]);
return $user; return $user;
} }
} }

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Liquid\FileSystems; namespace App\Liquid\FileSystems;
use InvalidArgumentException;
use Keepsuit\Liquid\Contracts\LiquidFileSystem; use Keepsuit\Liquid\Contracts\LiquidFileSystem;
/** /**
@ -53,7 +54,7 @@ class InlineTemplatesFileSystem implements LiquidFileSystem
public function readTemplateFile(string $templateName): string public function readTemplateFile(string $templateName): string
{ {
if (! isset($this->templates[$templateName])) { if (! isset($this->templates[$templateName])) {
throw new \InvalidArgumentException("Template '{$templateName}' not found in inline templates"); throw new InvalidArgumentException("Template '{$templateName}' not found in inline templates");
} }
return $this->templates[$templateName]; return $this->templates[$templateName];

View file

@ -20,6 +20,7 @@ use Keepsuit\Liquid\TagBlock;
class TemplateTag extends TagBlock class TemplateTag extends TagBlock
{ {
protected string $templateName; protected string $templateName;
protected Raw $body; protected Raw $body;
public static function tagName(): string public static function tagName(): string
@ -41,7 +42,7 @@ class TemplateTag extends TagBlock
is_string($templateNameExpression) => trim($templateNameExpression), is_string($templateNameExpression) => trim($templateNameExpression),
is_numeric($templateNameExpression) => (string) $templateNameExpression, is_numeric($templateNameExpression) => (string) $templateNameExpression,
$templateNameExpression instanceof VariableLookup => (string) $templateNameExpression, $templateNameExpression instanceof VariableLookup => (string) $templateNameExpression,
default => throw new SyntaxException("Template name must be a string, number, or variable"), default => throw new SyntaxException('Template name must be a string, number, or variable'),
}; };
// Validate template name (letters, numbers, underscores, and slashes only) // Validate template name (letters, numbers, underscores, and slashes only)

View file

@ -182,10 +182,12 @@ class Device extends Model
{ {
return $this->belongsTo(Firmware::class, 'update_firmware_id'); return $this->belongsTo(Firmware::class, 'update_firmware_id');
} }
public function deviceModel(): BelongsTo public function deviceModel(): BelongsTo
{ {
return $this->belongsTo(DeviceModel::class); return $this->belongsTo(DeviceModel::class);
} }
public function logs(): HasMany public function logs(): HasMany
{ {
return $this->hasMany(DeviceLog::class); return $this->hasMany(DeviceLog::class);
@ -224,19 +226,20 @@ class Device extends Model
if ($from < $to) { if ($from < $to) {
// Normal range, same day // Normal range, same day
return $now->between($from, $to) ? (int) $now->diffInSeconds($to, false) : null; return $now->between($from, $to) ? (int) $now->diffInSeconds($to, false) : null;
} else { }
// Overnight range // Overnight range
if ($now->gte($from)) { if ($now->gte($from)) {
// After 'from', before midnight // After 'from', before midnight
return (int) $now->diffInSeconds($to->copy()->addDay(), false); return (int) $now->diffInSeconds($to->copy()->addDay(), false);
} elseif ($now->lt($to)) { }
if ($now->lt($to)) {
// After midnight, before 'to' // After midnight, before 'to'
return (int) $now->diffInSeconds($to, false); return (int) $now->diffInSeconds($to, false);
} else { }
// Not in sleep window // Not in sleep window
return null; return null;
}
}
} }
public function isPauseActive(): bool public function isPauseActive(): bool

View file

@ -41,6 +41,7 @@ class AppServiceProvider extends ServiceProvider
// Register OIDC provider with Socialite // Register OIDC provider with Socialite
Socialite::extend('oidc', function ($app) { Socialite::extend('oidc', function ($app) {
$config = $app['config']['services.oidc'] ?? []; $config = $app['config']['services.oidc'] ?? [];
return new OidcProvider( return new OidcProvider(
$app['request'], $app['request'],
$config['client_id'] ?? null, $config['client_id'] ?? null,

View file

@ -51,7 +51,7 @@ class ImageGenerationService
if (config('app.puppeteer_wait_for_network_idle')) { if (config('app.puppeteer_wait_for_network_idle')) {
$browsershot->waitUntilNetworkIdle(); $browsershot->waitUntilNetworkIdle();
} }
if (config('app.puppeteer_window_size_strategy') == 'v2') { if (config('app.puppeteer_window_size_strategy') === 'v2') {
$browsershot->windowSize($imageSettings['width'], $imageSettings['height']); $browsershot->windowSize($imageSettings['width'], $imageSettings['height']);
} else { } else {
$browsershot->windowSize(800, 480); $browsershot->windowSize(800, 480);

View file

@ -2,11 +2,11 @@
namespace App\Services; namespace App\Services;
use Exception;
use GuzzleHttp\Client;
use Laravel\Socialite\Two\AbstractProvider; use Laravel\Socialite\Two\AbstractProvider;
use Laravel\Socialite\Two\ProviderInterface; use Laravel\Socialite\Two\ProviderInterface;
use Laravel\Socialite\Two\User; use Laravel\Socialite\Two\User;
use GuzzleHttp\Client;
use Illuminate\Support\Arr;
class OidcProvider extends AbstractProvider implements ProviderInterface class OidcProvider extends AbstractProvider implements ProviderInterface
{ {
@ -39,7 +39,7 @@ class OidcProvider extends AbstractProvider implements ProviderInterface
$endpoint = config('services.oidc.endpoint'); $endpoint = config('services.oidc.endpoint');
if (! $endpoint) { if (! $endpoint) {
throw new \Exception('OIDC endpoint is not configured. Please set OIDC_ENDPOINT environment variable.'); throw new Exception('OIDC endpoint is not configured. Please set OIDC_ENDPOINT environment variable.');
} }
// Handle both full well-known URL and base URL // Handle both full well-known URL and base URL
@ -65,15 +65,15 @@ class OidcProvider extends AbstractProvider implements ProviderInterface
$this->oidcConfig = json_decode($response->getBody()->getContents(), true); $this->oidcConfig = json_decode($response->getBody()->getContents(), true);
if (! $this->oidcConfig) { if (! $this->oidcConfig) {
throw new \Exception('OIDC configuration is empty or invalid JSON'); throw new Exception('OIDC configuration is empty or invalid JSON');
} }
if (! isset($this->oidcConfig['authorization_endpoint'])) { if (! isset($this->oidcConfig['authorization_endpoint'])) {
throw new \Exception('authorization_endpoint not found in OIDC configuration'); throw new Exception('authorization_endpoint not found in OIDC configuration');
} }
} catch (\Exception $e) { } catch (Exception $e) {
throw new \Exception('Failed to load OIDC configuration: ' . $e->getMessage()); throw new Exception('Failed to load OIDC configuration: '.$e->getMessage());
} }
} }
@ -83,8 +83,9 @@ class OidcProvider extends AbstractProvider implements ProviderInterface
protected function getAuthUrl($state) protected function getAuthUrl($state)
{ {
if (! $this->oidcConfig || ! isset($this->oidcConfig['authorization_endpoint'])) { if (! $this->oidcConfig || ! isset($this->oidcConfig['authorization_endpoint'])) {
throw new \Exception('OIDC configuration not loaded or authorization_endpoint not found.'); throw new Exception('OIDC configuration not loaded or authorization_endpoint not found.');
} }
return $this->buildAuthUrlFromBase($this->oidcConfig['authorization_endpoint'], $state); return $this->buildAuthUrlFromBase($this->oidcConfig['authorization_endpoint'], $state);
} }
@ -94,8 +95,9 @@ class OidcProvider extends AbstractProvider implements ProviderInterface
protected function getTokenUrl() protected function getTokenUrl()
{ {
if (! $this->oidcConfig || ! isset($this->oidcConfig['token_endpoint'])) { if (! $this->oidcConfig || ! isset($this->oidcConfig['token_endpoint'])) {
throw new \Exception('OIDC configuration not loaded or token_endpoint not found.'); throw new Exception('OIDC configuration not loaded or token_endpoint not found.');
} }
return $this->oidcConfig['token_endpoint']; return $this->oidcConfig['token_endpoint'];
} }
@ -105,7 +107,7 @@ class OidcProvider extends AbstractProvider implements ProviderInterface
protected function getUserByToken($token) protected function getUserByToken($token)
{ {
if (! $this->oidcConfig || ! isset($this->oidcConfig['userinfo_endpoint'])) { if (! $this->oidcConfig || ! isset($this->oidcConfig['userinfo_endpoint'])) {
throw new \Exception('OIDC configuration not loaded or userinfo_endpoint not found.'); throw new Exception('OIDC configuration not loaded or userinfo_endpoint not found.');
} }
$response = $this->getHttpClient()->get($this->oidcConfig['userinfo_endpoint'], [ $response = $this->getHttpClient()->get($this->oidcConfig['userinfo_endpoint'], [

View file

@ -2,7 +2,8 @@
declare(strict_types=1); declare(strict_types=1);
use App\Models\{Device, User}; use App\Models\Device;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class); uses(RefreshDatabase::class);
@ -16,8 +17,8 @@ test('dashboard shows device image with correct rotation', function () {
]); ]);
// Mock the file existence check // Mock the file existence check
\Illuminate\Support\Facades\Storage::fake('public'); Illuminate\Support\Facades\Storage::fake('public');
\Illuminate\Support\Facades\Storage::disk('public')->put('images/generated/test-image-uuid.png', 'fake-image-content'); Illuminate\Support\Facades\Storage::disk('public')->put('images/generated/test-image-uuid.png', 'fake-image-content');
$response = $this->actingAs($user) $response = $this->actingAs($user)
->get(route('dashboard')); ->get(route('dashboard'));
@ -36,8 +37,8 @@ test('device configure page shows device image with correct rotation', function
]); ]);
// Mock the file existence check // Mock the file existence check
\Illuminate\Support\Facades\Storage::fake('public'); Illuminate\Support\Facades\Storage::fake('public');
\Illuminate\Support\Facades\Storage::disk('public')->put('images/generated/test-image-uuid.png', 'fake-image-content'); Illuminate\Support\Facades\Storage::disk('public')->put('images/generated/test-image-uuid.png', 'fake-image-content');
$response = $this->actingAs($user) $response = $this->actingAs($user)
->get(route('devices.configure', $device)); ->get(route('devices.configure', $device));
@ -56,8 +57,8 @@ test('device with no rotation shows no transform style', function () {
]); ]);
// Mock the file existence check // Mock the file existence check
\Illuminate\Support\Facades\Storage::fake('public'); Illuminate\Support\Facades\Storage::fake('public');
\Illuminate\Support\Facades\Storage::disk('public')->put('images/generated/test-image-uuid.png', 'fake-image-content'); Illuminate\Support\Facades\Storage::disk('public')->put('images/generated/test-image-uuid.png', 'fake-image-content');
$response = $this->actingAs($user) $response = $this->actingAs($user)
->get(route('dashboard')); ->get(route('dashboard'));
@ -75,8 +76,8 @@ test('device with null rotation defaults to 0', function () {
]); ]);
// Mock the file existence check // Mock the file existence check
\Illuminate\Support\Facades\Storage::fake('public'); Illuminate\Support\Facades\Storage::fake('public');
\Illuminate\Support\Facades\Storage::disk('public')->put('images/generated/test-image-uuid.png', 'fake-image-content'); Illuminate\Support\Facades\Storage::disk('public')->put('images/generated/test-image-uuid.png', 'fake-image-content');
$response = $this->actingAs($user) $response = $this->actingAs($user)
->get(route('dashboard')); ->get(route('dashboard'));

View file

@ -3,10 +3,6 @@
use App\Models\Plugin; use App\Models\Plugin;
use App\Models\User; use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Livewire\Volt\Volt;
use Symfony\Component\Yaml\Yaml;
uses(RefreshDatabase::class); uses(RefreshDatabase::class);
@ -22,23 +18,23 @@ test('plugin import extracts default values from custom_fields and stores in con
'field_type' => 'string', 'field_type' => 'string',
'name' => 'Reading Days', 'name' => 'Reading Days',
'description' => 'Select days of the week to read', 'description' => 'Select days of the week to read',
'default' => 'Monday,Friday,Saturday,Sunday' 'default' => 'Monday,Friday,Saturday,Sunday',
], ],
[ [
'keyname' => 'refresh_interval', 'keyname' => 'refresh_interval',
'field_type' => 'number', 'field_type' => 'number',
'name' => 'Refresh Interval', 'name' => 'Refresh Interval',
'description' => 'How often to refresh data', 'description' => 'How often to refresh data',
'default' => 15 'default' => 15,
], ],
[ [
'keyname' => 'timezone', 'keyname' => 'timezone',
'field_type' => 'time_zone', 'field_type' => 'time_zone',
'name' => 'Timezone', 'name' => 'Timezone',
'description' => 'Select your timezone' 'description' => 'Select your timezone',
// No default value // No default value
] ],
] ],
]; ];
// Extract default values from custom_fields and populate configuration // Extract default values from custom_fields and populate configuration
@ -53,7 +49,7 @@ test('plugin import extracts default values from custom_fields and stores in con
// Create the plugin directly // Create the plugin directly
$plugin = Plugin::create([ $plugin = Plugin::create([
'uuid' => \Illuminate\Support\Str::uuid(), 'uuid' => Illuminate\Support\Str::uuid(),
'user_id' => $user->id, 'user_id' => $user->id,
'name' => 'Test Plugin with Defaults', 'name' => 'Test Plugin with Defaults',
'data_stale_minutes' => 30, 'data_stale_minutes' => 30,
@ -89,9 +85,9 @@ test('plugin import handles custom_fields without default values', function () {
'keyname' => 'timezone', 'keyname' => 'timezone',
'field_type' => 'time_zone', 'field_type' => 'time_zone',
'name' => 'Timezone', 'name' => 'Timezone',
'description' => 'Select your timezone' 'description' => 'Select your timezone',
] ],
] ],
]; ];
// Extract default values from custom_fields and populate configuration // Extract default values from custom_fields and populate configuration
@ -106,7 +102,7 @@ test('plugin import handles custom_fields without default values', function () {
// Create the plugin directly // Create the plugin directly
$plugin = Plugin::create([ $plugin = Plugin::create([
'uuid' => \Illuminate\Support\Str::uuid(), 'uuid' => Illuminate\Support\Str::uuid(),
'user_id' => $user->id, 'user_id' => $user->id,
'name' => 'Test Plugin No Defaults', 'name' => 'Test Plugin No Defaults',
'data_stale_minutes' => 30, 'data_stale_minutes' => 30,