feat(analytics): add site analytics with grouped navigation sections
- Add Analytics container: models, tasks, jobs, controllers, routes, services - Add analytics config with section groups (structure, institute, content, services) - Add database tables: analytics_sessions, analytics_hits, analytics_daily_stats - Add frontend: Analytics page, section detail, chart, overview, navigation components - Add consent banner and JS tracking service (sendBeacon + Inertia listener) - Add permission sync for view_analytics, view_any_analytic - Fix trailing slash URL matching in GetNavigationSectionsTask - Fix event propagation on expand arrows in navigation sections - Fix RecordVisitJob to not depend on dropped analytics_geo_cache table - Replace plain text views/visitors with badge-style icons - Group navigation sections by category with separate blocks - Add config-driven non-CMS sections (faculties, divisions, DPO, journals) - Remove Events, TV, Sveden from analytics sections
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Containers\Analytics\Jobs;
|
||||
|
||||
use App\Containers\Analytics\Models\AnalyticsHit;
|
||||
use App\Containers\Analytics\Models\AnalyticsSession;
|
||||
use App\Containers\Analytics\Services\DeviceDetectorService;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class RecordVisitJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public int $tries = 3;
|
||||
|
||||
public int $timeout = 15;
|
||||
|
||||
public function __construct(
|
||||
public array $data,
|
||||
) {}
|
||||
|
||||
public function handle(
|
||||
DeviceDetectorService $detector,
|
||||
): void {
|
||||
$userAgent = $this->data['user_agent'] ?? '';
|
||||
|
||||
if ($detector->isBot($userAgent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$device = $detector->parse($userAgent);
|
||||
|
||||
$utmParams = array_filter([
|
||||
'utm_source' => $this->data['utm_source'] ?? null,
|
||||
'utm_medium' => $this->data['utm_medium'] ?? null,
|
||||
'utm_campaign' => $this->data['utm_campaign'] ?? null,
|
||||
], fn($v) => $v !== null);
|
||||
|
||||
$session = (new AnalyticsSession())->firstOrCreateSession(
|
||||
visitorId: $this->data['visitor_id'],
|
||||
ip: $this->data['ip'] ?? '0.0.0.0',
|
||||
userId: $this->data['user_id'] ?? null,
|
||||
entryPage: $this->data['url'],
|
||||
utmParams: $utmParams,
|
||||
);
|
||||
|
||||
if (empty($session->browser)) {
|
||||
$session->update([
|
||||
'browser' => $device['browser'],
|
||||
'os' => $device['os'],
|
||||
'device_type' => $device['type'],
|
||||
]);
|
||||
}
|
||||
|
||||
AnalyticsHit::create([
|
||||
'session_id' => $session->id,
|
||||
'user_id' => $this->data['user_id'] ?? null,
|
||||
'url' => $this->data['url'],
|
||||
'referrer' => $this->data['referrer'] ?? null,
|
||||
'title' => $this->data['title'] ?? null,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user