mirror of
https://github.com/usetrmnl/byos_laravel.git
synced 2026-01-13 15:07:49 +00:00
This commit is contained in:
parent
0322ec899e
commit
b10bbca774
9 changed files with 168 additions and 12 deletions
|
|
@ -121,6 +121,10 @@ class GenerateDefaultImagesCommand extends Command
|
|||
|
||||
$browserStage = new BrowserStage($browsershotInstance);
|
||||
$browserStage->html($html);
|
||||
|
||||
// Set timezone from app config (no user context in this command)
|
||||
$browserStage->timezone(config('app.timezone'));
|
||||
|
||||
$browserStage
|
||||
->width($deviceModel->width)
|
||||
->height($deviceModel->height);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use App\Liquid\Filters\StringMarkup;
|
|||
use App\Liquid\Filters\Uniqueness;
|
||||
use App\Liquid\Tags\TemplateTag;
|
||||
use App\Services\PluginImportService;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -454,6 +455,12 @@ class Plugin extends Model
|
|||
$renderedContent = '';
|
||||
|
||||
if ($this->markup_language === 'liquid') {
|
||||
// Get timezone from user or fall back to app timezone
|
||||
$timezone = $this->user->timezone ?? config('app.timezone');
|
||||
|
||||
// Calculate UTC offset in seconds
|
||||
$utcOffset = (string) Carbon::now($timezone)->getOffset();
|
||||
|
||||
// Build render context
|
||||
$context = [
|
||||
'size' => $size,
|
||||
|
|
@ -465,10 +472,10 @@ class Plugin extends Model
|
|||
'timestamp_utc' => now()->utc()->timestamp,
|
||||
],
|
||||
'user' => [
|
||||
'utc_offset' => '0',
|
||||
'utc_offset' => $utcOffset,
|
||||
'name' => $this->user->name ?? 'Unknown User',
|
||||
'locale' => 'en',
|
||||
'time_zone_iana' => config('app.timezone'),
|
||||
'time_zone_iana' => $timezone,
|
||||
],
|
||||
'plugin_settings' => [
|
||||
'instance_name' => $this->name,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ class User extends Authenticatable // implements MustVerifyEmail
|
|||
'assign_new_devices',
|
||||
'assign_new_device_id',
|
||||
'oidc_sub',
|
||||
'timezone',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class ImageGenerationService
|
|||
{
|
||||
public static function generateImage(string $markup, $deviceId): string
|
||||
{
|
||||
$device = Device::with(['deviceModel', 'palette', 'deviceModel.palette'])->find($deviceId);
|
||||
$device = Device::with(['deviceModel', 'palette', 'deviceModel.palette', 'user'])->find($deviceId);
|
||||
$uuid = Uuid::uuid4()->toString();
|
||||
|
||||
try {
|
||||
|
|
@ -44,6 +44,10 @@ class ImageGenerationService
|
|||
$browserStage = new BrowserStage($browsershotInstance);
|
||||
$browserStage->html($markup);
|
||||
|
||||
// Set timezone from user or fall back to app timezone
|
||||
$timezone = $device->user->timezone ?? config('app.timezone');
|
||||
$browserStage->timezone($timezone);
|
||||
|
||||
if (config('app.puppeteer_window_size_strategy') === 'v2') {
|
||||
$browserStage
|
||||
->width($imageSettings['width'])
|
||||
|
|
@ -352,7 +356,7 @@ class ImageGenerationService
|
|||
|
||||
try {
|
||||
// Load device with relationships
|
||||
$device->load(['palette', 'deviceModel.palette']);
|
||||
$device->load(['palette', 'deviceModel.palette', 'user']);
|
||||
|
||||
// Get image generation settings from DeviceModel if available, otherwise use device settings
|
||||
$imageSettings = self::getImageSettings($device);
|
||||
|
|
@ -372,6 +376,10 @@ class ImageGenerationService
|
|||
$browserStage = new BrowserStage($browsershotInstance);
|
||||
$browserStage->html($html);
|
||||
|
||||
// Set timezone from user or fall back to app timezone
|
||||
$timezone = $device->user->timezone ?? config('app.timezone');
|
||||
$browserStage->timezone($timezone);
|
||||
|
||||
if (config('app.puppeteer_window_size_strategy') === 'v2') {
|
||||
$browserStage
|
||||
->width($imageSettings['width'])
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
"ext-simplexml": "*",
|
||||
"ext-zip": "*",
|
||||
"bnussbau/laravel-trmnl-blade": "2.0.*",
|
||||
"bnussbau/trmnl-pipeline-php": "^0.5.0",
|
||||
"bnussbau/trmnl-pipeline-php": "^0.6.0",
|
||||
"keepsuit/laravel-liquid": "^0.5.2",
|
||||
"laravel/framework": "^12.1",
|
||||
"laravel/sanctum": "^4.0",
|
||||
|
|
|
|||
14
composer.lock
generated
14
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "38e8a7dd90ccc1b777a4c8a5a28f9f14",
|
||||
"content-hash": "7750ff686c4cad7f85390488c28b33ca",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aws/aws-crt-php",
|
||||
|
|
@ -243,16 +243,16 @@
|
|||
},
|
||||
{
|
||||
"name": "bnussbau/trmnl-pipeline-php",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bnussbau/trmnl-pipeline-php.git",
|
||||
"reference": "eb55b89e1f3991764912505872bbce809874d1aa"
|
||||
"reference": "228505afa8a39a5033916e9ae5ccbf1733092c1f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bnussbau/trmnl-pipeline-php/zipball/eb55b89e1f3991764912505872bbce809874d1aa",
|
||||
"reference": "eb55b89e1f3991764912505872bbce809874d1aa",
|
||||
"url": "https://api.github.com/repos/bnussbau/trmnl-pipeline-php/zipball/228505afa8a39a5033916e9ae5ccbf1733092c1f",
|
||||
"reference": "228505afa8a39a5033916e9ae5ccbf1733092c1f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -294,7 +294,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/bnussbau/trmnl-pipeline-php/issues",
|
||||
"source": "https://github.com/bnussbau/trmnl-pipeline-php/tree/0.5.0"
|
||||
"source": "https://github.com/bnussbau/trmnl-pipeline-php/tree/0.6.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -310,7 +310,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-25T17:00:21+00:00"
|
||||
"time": "2025-12-02T15:18:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
<?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->string('timezone')->nullable()->after('oidc_sub');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('timezone');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -11,9 +11,12 @@ use Livewire\Volt\Component;
|
|||
new class extends Component {
|
||||
public ?int $assign_new_device_id = null;
|
||||
|
||||
public ?string $timezone = null;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->assign_new_device_id = Auth::user()->assign_new_device_id;
|
||||
$this->timezone = Auth::user()->timezone ?? config('app.timezone');
|
||||
}
|
||||
|
||||
public function updatePreferences(): void
|
||||
|
|
@ -26,6 +29,11 @@ new class extends Component {
|
|||
->whereNull('mirror_device_id');
|
||||
}),
|
||||
],
|
||||
'timezone' => [
|
||||
'nullable',
|
||||
'string',
|
||||
Rule::in(timezone_identifiers_list()),
|
||||
],
|
||||
]);
|
||||
|
||||
Auth::user()->update($validated);
|
||||
|
|
@ -39,6 +47,14 @@ new class extends Component {
|
|||
|
||||
<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="timezone" label="Timezone">
|
||||
<flux:select.option value="" disabled>Select timezone...</flux:select.option>
|
||||
@foreach(timezone_identifiers_list() as $tz)
|
||||
<flux:select.option value="{{ $tz }}">{{ $tz }}</flux:select.option>
|
||||
@endforeach
|
||||
</flux:select>
|
||||
|
||||
<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)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Plugin;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
uses(Illuminate\Foundation\Testing\RefreshDatabase::class);
|
||||
|
|
@ -587,3 +589,93 @@ LIQUID
|
|||
return str_contains($command, 'trmnl-liquid-cli');
|
||||
});
|
||||
});
|
||||
|
||||
test('plugin render uses user timezone when set', function (): void {
|
||||
$user = User::factory()->create([
|
||||
'timezone' => 'America/New_York',
|
||||
]);
|
||||
|
||||
$plugin = Plugin::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => '{{ trmnl.user.time_zone_iana }}',
|
||||
]);
|
||||
|
||||
$rendered = $plugin->render();
|
||||
|
||||
expect($rendered)->toContain('America/New_York');
|
||||
});
|
||||
|
||||
test('plugin render falls back to app timezone when user timezone is not set', function (): void {
|
||||
$user = User::factory()->create([
|
||||
'timezone' => null,
|
||||
]);
|
||||
|
||||
config(['app.timezone' => 'Europe/London']);
|
||||
|
||||
$plugin = Plugin::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => '{{ trmnl.user.time_zone_iana }}',
|
||||
]);
|
||||
|
||||
$rendered = $plugin->render();
|
||||
|
||||
expect($rendered)->toContain('Europe/London');
|
||||
});
|
||||
|
||||
test('plugin render calculates correct UTC offset from user timezone', function (): void {
|
||||
$user = User::factory()->create([
|
||||
'timezone' => 'America/New_York', // UTC-5 (EST) or UTC-4 (EDT)
|
||||
]);
|
||||
|
||||
$plugin = Plugin::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => '{{ trmnl.user.utc_offset }}',
|
||||
]);
|
||||
|
||||
$rendered = $plugin->render();
|
||||
|
||||
// America/New_York offset should be -18000 (EST) or -14400 (EDT) in seconds
|
||||
$expectedOffset = (string) Carbon::now('America/New_York')->getOffset();
|
||||
expect($rendered)->toContain($expectedOffset);
|
||||
});
|
||||
|
||||
test('plugin render calculates correct UTC offset from app timezone when user timezone is null', function (): void {
|
||||
$user = User::factory()->create([
|
||||
'timezone' => null,
|
||||
]);
|
||||
|
||||
config(['app.timezone' => 'Europe/London']);
|
||||
|
||||
$plugin = Plugin::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => '{{ trmnl.user.utc_offset }}',
|
||||
]);
|
||||
|
||||
$rendered = $plugin->render();
|
||||
|
||||
// Europe/London offset should be 0 (GMT) or 3600 (BST) in seconds
|
||||
$expectedOffset = (string) Carbon::now('Europe/London')->getOffset();
|
||||
expect($rendered)->toContain($expectedOffset);
|
||||
});
|
||||
|
||||
test('plugin render includes utc_offset and time_zone_iana in trmnl.user context', function (): void {
|
||||
$user = User::factory()->create([
|
||||
'timezone' => 'America/Chicago', // UTC-6 (CST) or UTC-5 (CDT)
|
||||
]);
|
||||
|
||||
$plugin = Plugin::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'markup_language' => 'liquid',
|
||||
'render_markup' => '{{ trmnl.user.time_zone_iana }}|{{ trmnl.user.utc_offset }}',
|
||||
]);
|
||||
|
||||
$rendered = $plugin->render();
|
||||
|
||||
expect($rendered)
|
||||
->toContain('America/Chicago')
|
||||
->and($rendered)->toMatch('/\|-?\d+/'); // Should contain a pipe followed by a number (offset in seconds)
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue