diff --git a/app/Console/Commands/CaldavSyncCommand.php b/app/Console/Commands/CaldavSyncCommand.php
index 04b1823..8eb71c0 100644
--- a/app/Console/Commands/CaldavSyncCommand.php
+++ b/app/Console/Commands/CaldavSyncCommand.php
@@ -18,6 +18,7 @@ public function handle(CaldavService $service)
// only run every 5 minutes although the task is called every minute
$cacheKey = 'caldav_sync_last_run';
if (\Illuminate\Support\Facades\Cache::has($cacheKey)) {
+ Log::info('CalDAV sync Throttled');
return 0;
}
Cache::put($cacheKey, true, 300);
@@ -33,6 +34,7 @@ public function handle(CaldavService $service)
$count++;
}
+ Log::info("Synced " . count($todos) . " todos.");
$this->info("Synced " . count($todos) . " todos.");
return 0;
}
diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php
index 0b51b8b..aee2b99 100644
--- a/app/Http/Middleware/HandleInertiaRequests.php
+++ b/app/Http/Middleware/HandleInertiaRequests.php
@@ -2,7 +2,7 @@
namespace App\Http\Middleware;
-use Illuminate\Foundation\Inspiring;
+use App\Models\Setting;
use Illuminate\Http\Request;
use Inertia\Middleware;
@@ -39,10 +39,9 @@ public function share(Request $request): array
return [
...parent::share($request),
'name' => config('app.name'),
- 'auth' => [
- 'user' => $request->user(),
- ],
+ 'auth' => ['user' => $request->user(),],
'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
+ 'cron' => Setting::get('app.cron_method') === 'request'
];
}
}
diff --git a/app/Listeners/ScheduleListener.php b/app/Listeners/ScheduleListener.php
deleted file mode 100644
index 9759219..0000000
--- a/app/Listeners/ScheduleListener.php
+++ /dev/null
@@ -1,48 +0,0 @@
-value('value') ?? 'internal';
- if ($method !== 'internal') {
- return;
- }
-
- // throttle key: run at most once every 55 seconds
- $cacheKey = 'caramel_scheduler_last_run';
- $ttlSeconds = 55;
-
- if (Cache::has($cacheKey)) {
- return;
- }
-
- // mark as run
- Cache::put($cacheKey, true, $ttlSeconds);
-
- try {
- Log::info('Triggering scheduler via ScheduleListener');
- Artisan::call('schedule:run');
- } catch (\Throwable $e) {
- Log::error('Error running scheduler: ' . $e->getMessage());
- }
- }
-}
diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php
index 0df9e53..8246185 100644
--- a/app/Providers/EventServiceProvider.php
+++ b/app/Providers/EventServiceProvider.php
@@ -4,11 +4,6 @@
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Schedule;
-use Illuminate\Support\Facades\Event;
-use Illuminate\Support\Facades\Schema;
-use Illuminate\Routing\Events\RouteMatched;
-use App\Models\Setting;
-use App\Listeners\ScheduleListener;
use App\Jobs\CheckInvoiceDueDatesJob;
class EventServiceProvider extends ServiceProvider
@@ -22,16 +17,9 @@ public function boot(): void
{
parent::boot();
- if (Schema::hasTable('settings')) {
- $method = Setting::where('key', 'app.schedule_method')->value('value') ?? 'internal';
- if ($method === 'internal') {
- Event::listen(RouteMatched::class, [ScheduleListener::class, 'handle']);
- }
- }
-
- // TODO: read where to put these or ask in the forums
- // it seems to work here, but where is the apropriate place?
- // Kernel::schedule did not work
+ // // TODO: read where to put these or ask in the forums
+ // // it seems to work here, but where is the apropriate place?
+ // // Kernel::schedule did not work
Schedule::command('caldav:sync')
->everyMinute()
->withoutOverlapping();
diff --git a/database/seeders/SettingsTableSeeder.php b/database/seeders/SettingsTableSeeder.php
index 7c4a1ef..bbe0a91 100644
--- a/database/seeders/SettingsTableSeeder.php
+++ b/database/seeders/SettingsTableSeeder.php
@@ -11,6 +11,6 @@ public function run(): void
{
Setting::updateOrCreate(['key' => 'invoices.number_format'], ['value' => 'RE-{number}']);
Setting::updateOrCreate(['key' => 'invoices.number_start'], ['value' => '1']);
- Setting::updateOrCreate(['key' => 'app.schedule_method'], ['value' => '1']);
+ Setting::updateOrCreate(['key' => 'app.cron_method'], ['value' => 'request']);
}
}
\ No newline at end of file
diff --git a/resources/js/layouts/AppLayout.vue b/resources/js/layouts/AppLayout.vue
index 5b76af4..0dd476d 100644
--- a/resources/js/layouts/AppLayout.vue
+++ b/resources/js/layouts/AppLayout.vue
@@ -1,5 +1,5 @@
diff --git a/resources/js/layouts/AuthLayout.vue b/resources/js/layouts/AuthLayout.vue
index db24ffb..d4d4969 100644
--- a/resources/js/layouts/AuthLayout.vue
+++ b/resources/js/layouts/AuthLayout.vue
@@ -2,11 +2,35 @@
// import AuthLayout from '@/layouts/auth/AuthSimpleLayout.vue';
// import AuthLayout from '@/layouts/auth/AuthCardLayout.vue';
import AuthLayout from '@/layouts/auth/AuthSplitLayout.vue';
+import { onMounted } from 'vue';
+import { usePage } from '@inertiajs/vue3'
+import axios from 'axios';
defineProps<{
title?: string;
description?: string;
}>();
+const cron = usePage().props.cron
+
+
+onMounted(() => {
+ if (navigator.platform.toUpperCase().indexOf('MAC') >= 0) {
+ document.body.classList.add('is-mac')
+ }
+
+ if (cron) {
+ triggerWebcron()
+ }
+})
+
+const triggerWebcron = async function () {
+ await axios.get('/webcron')
+ .catch(function (response) {
+ if (response.status >= 400) {
+ console.error(response)
+ }
+ })
+}
diff --git a/routes/web.php b/routes/web.php
index 342d7be..c862a1f 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -9,6 +9,7 @@
use App\Http\Controllers\InvoiceController;
use App\Http\Controllers\CustomerController;
use App\Http\Controllers\ProductController;
+use App\Models\Setting;
Route::middleware('auth')->group(function () {
@@ -54,8 +55,6 @@
// Products
Route::get('products', [ProductController::class, 'show'])->name('products');
-
-
Route::get('timesheets', function () {
return Inertia::render('Timesheets');
})->name('timesheets');
@@ -64,53 +63,62 @@
Route::get('proceduralDocumentation', function () {
return Inertia::render('ProceduralDocumentation');
})->name('proceduralDocumentation');
-
-
- /*
- |--------------------------------------------------------------------------
- | Web cron route
- |--------------------------------------------------------------------------
- |
- | Example: GET /webcron?token=SECRET or set header X-WEBCron-Token: SECRET
- | Configure secret in .env as WEBCRON_SECRET (optional). If no secret is set,
- | the route is open (not recommended in production).
- |
- */
- Route::get('/webcron', function (Request $request) {
- // only allow if scheduling method is webcron
- $method = \App\Models\Setting::where('key', 'app.schedule_method')->value('value') ?? 'internal';
- if ($method !== 'webcron') {
- return response('Not Found', 404);
- }
-
- $secret = env('WEBCRON_SECRET', null);
-
- // basic token protection
- if ($secret) {
- $token = $request->query('token') ?? $request->header('X-WEBCron-Token');
- if (!$token || !hash_equals((string)$secret, (string)$token)) {
- return response('Forbidden', 403);
- }
- }
-
- // quick throttle to avoid abuse (server-side)
- $cacheKey = 'caramel_webcron_last_run';
- if (\Illuminate\Support\Facades\Cache::has($cacheKey)) {
- return response('Throttled', 429);
- }
- Cache::put($cacheKey, true, 55);
-
- try {
- Log::info('Triggering scheduler via /webcron route');
- Artisan::call('schedule:run');
- return response('OK', 200);
- } catch (\Throwable $e) {
- Log::error('Error running scheduler: ' . $e->getMessage());
- return response('Error', 500);
- }
- });
});
+/*
+|--------------------------------------------------------------------------
+| Web cron route
+|--------------------------------------------------------------------------
+|
+| Example: GET /webcron?token=SECRET or set header X-WEBCron-Token: SECRET
+| Configure secret in .env as WEBCRON_SECRET (optional). If no secret is set,
+| the route is open (not recommended in production).
+|
+*/
+Route::get('/webcron', function (Request $request) {
+
+ // Return early of cron method is set to anything other then 'webcron' or 'request'
+ $method = \App\Models\Setting::where('key', 'app.cron_method')->value('value') ?? 'request';
+ if (!in_array($method, ['webcron', 'request'])) {
+ return response('Not Found', 404);
+ }
+
+ // TODO: Only allow requests from the same host or with the secret token
+ // $clientHost = ;
+ // $serverHost = ;
+ $sameHost = true;
+
+ $secret = env('WEBCRON_SECRET', null);
+ $token = null;
+ if ($secret) {
+ $token = $request->query('token') ?? $request->header('X-WEBCron-Token');
+ }
+ if (
+ !hash_equals((string)$secret, (string)$token) &&
+ !$sameHost
+ ) {
+ return response('Forbidden', 403);
+ }
+
+ // Throttle to avoid abuse (server-side)
+ $cacheKey = 'caramel_webcron_last_run';
+ if (\Illuminate\Support\Facades\Cache::has($cacheKey)) {
+ return response('Throttled', 304);
+ }
+ Cache::put($cacheKey, true, 55);
+
+ // Run scheduler
+ try {
+ Log::info('Triggering scheduler via /webcron route');
+ $output = '';
+ Artisan::call('schedule:run');
+ return response('OK', 200);
+ } catch (\Throwable $e) {
+ Log::error('Error running scheduler: ' . $e->getMessage());
+ return response('Error', 500);
+ }
+});
+
require __DIR__ . '/settings.php';
require __DIR__ . '/auth.php';