Add settings-driven Artisan scheduler registry with Etsy sync and token refresh jobs
Introduces App\Support\DashboardSchedule (modelled on LHITS_Dashboard's pattern) as a single settings-driven registry for recurring Artisan jobs, replacing the two hard-coded Schedule::command() lines in routes/console.php. Migrated unchanged: - integrations_refresh (integrations:refresh), every_30_seconds, withoutOverlapping(5) - alerts_scan (alerts:scan), every_30_seconds, withoutOverlapping(5) New: - etsy_sync (etsy:sync), every_15_minutes - forces a fresh pull of Etsy receipts/listings into the existing IntegrationCache entries, decoupled from the bundled integrations:refresh job so it can be tuned/disabled independently of Parcel2Go/BamBuddy/dryer refreshes. - etsy_token_refresh (etsy:refresh-token), every_45_minutes - proactively refreshes the Etsy OAuth token (tokens last ~1hr) via a new public Etsy::refreshAccessToken() wrapper around the existing on-demand accessToken() refresh logic, so the connection survives quiet periods. Frequency is persisted to storage/app/dashboard-schedules.json (no app_settings table exists in this app, unlike LHITS's AppSetting-backed store) and surfaced in a new 'Scheduler' section on the existing Settings page (ScheduleSettingsController + routes), with per-job frequency dropdowns and manual 'Run now' buttons, matching the page's existing Tailwind conventions. Tests: SchedulerTest (registry/frequency behavior), ScheduleSettingsTest (settings UI + authorization), EtsySyncScheduledJobsTest (new commands, Http::fake only, no live Etsy calls).
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
['parcel2go', 'Parcel2Go', $integrations['parcel2go']['configured'], $integrations['parcel2go']['stored'], 'Shipping and labels'],
|
||||
['bambuddy', 'BamBuddy', $integrations['bambuddy']['configured'], $integrations['bambuddy']['stored'], 'Print farm'],
|
||||
['dryer', 'Filament dryer', $integrations['dryer']['configured'], $integrations['dryer']['stored'], 'Drying controls'],
|
||||
['scheduler', 'Scheduler', true, true, 'Job frequencies'],
|
||||
] as [$section, $name, $isConfigured, $isStored, $description])
|
||||
<a href="#{{ $section }}" class="group rounded-2xl border border-slate-800 bg-slate-900 p-4 transition-colors hover:border-brand/60 hover:bg-slate-800/70">
|
||||
<span class="flex items-center justify-between gap-2"><strong class="text-sm text-white">{{ $name }}</strong><span aria-hidden="true" class="text-slate-500 group-hover:text-brand">↗</span></span>
|
||||
@@ -127,4 +128,44 @@
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<section id="scheduler" class="scroll-mt-6 rounded-2xl border border-slate-800 bg-slate-900 p-6">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold">Scheduler</h3>
|
||||
<p class="mt-1 text-sm text-slate-400">Tune how often recurring Artisan jobs run. Laravel applies a changed frequency on its next scheduler tick, no redeploy needed.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" action="{{ route('settings.schedules.update') }}" class="mt-6 grid gap-4">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="grid gap-3">
|
||||
@foreach($scheduleJobs as $job)
|
||||
<div class="grid gap-3 rounded-xl border border-slate-700 bg-slate-950 p-4 sm:grid-cols-[1fr_auto_auto] sm:items-center">
|
||||
<div>
|
||||
<p class="text-sm font-semibold text-white">{{ $job['name'] }}</p>
|
||||
<p class="mt-1 text-xs text-slate-400">{{ $job['description'] }}</p>
|
||||
<p class="mt-1 text-xs font-mono text-slate-500">{{ $job['command'] }}</p>
|
||||
</div>
|
||||
<select name="schedules[{{ $job['key'] }}]" class="rounded-xl border border-slate-700 bg-slate-950 px-4 py-3 text-slate-100">
|
||||
@foreach($scheduleFrequencyOptions as $value => $label)
|
||||
<option value="{{ $value }}" @selected(old('schedules.'.$job['key'], $job['frequency']) === $value)>{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@if($job['manual'] ?? false)
|
||||
<button type="submit" form="schedule-run-{{ $job['key'] }}" class="w-fit rounded-xl border border-slate-700 px-4 py-3 text-sm font-semibold text-slate-200 hover:border-brand">Run now</button>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<div><button class="w-fit rounded-xl bg-brand px-5 py-3 text-sm font-semibold text-slate-950 hover:bg-brand/90">Save schedule settings</button></div>
|
||||
</form>
|
||||
|
||||
@foreach($scheduleJobs as $job)
|
||||
@if($job['manual'] ?? false)
|
||||
<form id="schedule-run-{{ $job['key'] }}" method="post" action="{{ route('settings.schedules.run', $job['key']) }}" class="hidden">@csrf</form>
|
||||
@endif
|
||||
@endforeach
|
||||
</section>
|
||||
|
||||
@endsection
|
||||
|
||||
Reference in New Issue
Block a user