134 lines
4.7 KiB
PHP
134 lines
4.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\V1;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Resources\V1\EventResource;
|
|
use App\Http\Resources\V1\PageResource;
|
|
use App\Http\Resources\V1\ReferrerResource;
|
|
use App\Http\Resources\V1\StatsResource;
|
|
use App\Http\Resources\V1\VisitorBreakdownResource;
|
|
use App\Http\Resources\V1\WebsiteResource;
|
|
use App\Models\Website;
|
|
use App\Services\AnalyticsQueryService;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
|
use Illuminate\Support\Carbon;
|
|
|
|
class WebsiteController extends Controller
|
|
{
|
|
public function index(Request $request): AnonymousResourceCollection
|
|
{
|
|
$websites = $request->user()->websites()->orderBy('name')->get();
|
|
|
|
return WebsiteResource::collection($websites);
|
|
}
|
|
|
|
public function stats(Request $request, Website $website): StatsResource
|
|
{
|
|
$this->authorizeWebsite($request, $website);
|
|
[$from, $to] = $this->parseDateRange($request);
|
|
$service = AnalyticsQueryService::for($website, $from, $to);
|
|
|
|
return new StatsResource([
|
|
'from' => $from->toDateString(),
|
|
'to' => $to->toDateString(),
|
|
'metrics' => $service->summary(),
|
|
'timeseries' => $service->visitorsOverTime(),
|
|
]);
|
|
}
|
|
|
|
public function pages(Request $request, Website $website): AnonymousResourceCollection
|
|
{
|
|
$this->authorizeWebsite($request, $website);
|
|
[$from, $to] = $this->parseDateRange($request);
|
|
$limit = $this->parseLimit($request);
|
|
$service = AnalyticsQueryService::for($website, $from, $to);
|
|
|
|
return PageResource::collection($service->topPages($limit));
|
|
}
|
|
|
|
public function referrers(Request $request, Website $website): AnonymousResourceCollection
|
|
{
|
|
$this->authorizeWebsite($request, $website);
|
|
[$from, $to] = $this->parseDateRange($request);
|
|
$limit = $this->parseLimit($request);
|
|
$service = AnalyticsQueryService::for($website, $from, $to);
|
|
|
|
return ReferrerResource::collection($service->trafficSources($limit));
|
|
}
|
|
|
|
public function events(Request $request, Website $website): AnonymousResourceCollection
|
|
{
|
|
$this->authorizeWebsite($request, $website);
|
|
[$from, $to] = $this->parseDateRange($request);
|
|
$limit = $this->parseLimit($request);
|
|
$service = AnalyticsQueryService::for($website, $from, $to);
|
|
|
|
return EventResource::collection($service->eventsOverview($limit));
|
|
}
|
|
|
|
public function visitors(Request $request, Website $website): VisitorBreakdownResource
|
|
{
|
|
$this->authorizeWebsite($request, $website);
|
|
[$from, $to] = $this->parseDateRange($request);
|
|
$service = AnalyticsQueryService::for($website, $from, $to);
|
|
|
|
return new VisitorBreakdownResource([
|
|
'from' => $from->toDateString(),
|
|
'to' => $to->toDateString(),
|
|
'countries' => $service->visitorsByCountry(20)->map(fn ($r) => [
|
|
'country' => $r->country,
|
|
'visitors' => $r->visitors,
|
|
]),
|
|
'browsers' => $service->visitorsByBrowser(10)->map(fn ($r) => [
|
|
'browser' => $r->browser,
|
|
'visitors' => $r->visitors,
|
|
]),
|
|
'operating_systems' => $service->visitorsByOS(10)->map(fn ($r) => [
|
|
'os' => $r->os,
|
|
'visitors' => $r->visitors,
|
|
]),
|
|
'device_types' => $service->visitorsByDeviceType(5)->map(fn ($r) => [
|
|
'device_type' => $r->device_type,
|
|
'visitors' => $r->visitors,
|
|
]),
|
|
'languages' => $service->visitorsByLanguage(10)->map(fn ($r) => [
|
|
'language' => $r->language,
|
|
'visitors' => $r->visitors,
|
|
]),
|
|
'new_vs_returning' => $service->newVsReturning(),
|
|
]);
|
|
}
|
|
|
|
private function authorizeWebsite(Request $request, Website $website): void
|
|
{
|
|
if ($website->user_id !== $request->user()->id) {
|
|
abort(403, 'You do not own this website.');
|
|
}
|
|
}
|
|
|
|
private function parseDateRange(Request $request): array
|
|
{
|
|
$request->validate([
|
|
'from' => 'nullable|date|before_or_equal:to',
|
|
'to' => 'nullable|date|after_or_equal:from',
|
|
]);
|
|
|
|
$from = $request->has('from')
|
|
? Carbon::parse($request->get('from'))
|
|
: Carbon::today()->subDays(6);
|
|
|
|
$to = $request->has('to')
|
|
? Carbon::parse($request->get('to'))
|
|
: Carbon::today();
|
|
|
|
return [$from, $to];
|
|
}
|
|
|
|
private function parseLimit(Request $request): int
|
|
{
|
|
return min((int) $request->get('limit', 50), 200);
|
|
}
|
|
}
|