199 lines
7.2 KiB
PHP
199 lines
7.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\StoreEventRequest;
|
|
use App\Http\Requests\UpdateEventRequest;
|
|
use App\Http\Resources\EventResource;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
|
|
|
class EventController extends Controller
|
|
{
|
|
/**
|
|
* GET /api/events
|
|
* Cursor-based pagination by date. Supports ?since=ISO for delta sync.
|
|
*/
|
|
public function index(Request $request): AnonymousResourceCollection
|
|
{
|
|
$query = $request->user()->events()->with('media')->orderBy('date');
|
|
|
|
// Delta sync: only events updated since a given timestamp
|
|
if ($request->has('since')) {
|
|
$since = $request->date('since');
|
|
$query->where('updated_at', '>', $since);
|
|
}
|
|
|
|
// Cursor-based pagination (default 50, max 200)
|
|
$limit = min((int) $request->input('limit', 50), 200);
|
|
|
|
return EventResource::collection(
|
|
$query->cursorPaginate($limit)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* POST /api/events
|
|
*/
|
|
public function store(StoreEventRequest $request): JsonResponse
|
|
{
|
|
$event = $request->user()->events()->create([
|
|
'client_id' => $request->validated('id'),
|
|
'title' => $request->validated('title'),
|
|
'date' => $request->validated('date'),
|
|
'emotion' => $request->validated('emotion'),
|
|
'custom_color' => $request->validated('customColor'),
|
|
'gradient_preset' => $request->validated('gradientPreset'),
|
|
'image' => $request->validated('image'),
|
|
'note' => $request->validated('note'),
|
|
]);
|
|
|
|
return (new EventResource($event->load('media')))
|
|
->response()
|
|
->setStatusCode(201);
|
|
}
|
|
|
|
/**
|
|
* GET /api/events/{clientId}
|
|
*/
|
|
public function show(Request $request, string $clientId): EventResource
|
|
{
|
|
$event = $request->user()->events()
|
|
->where('client_id', $clientId)
|
|
->firstOrFail();
|
|
|
|
return new EventResource($event->load('media'));
|
|
}
|
|
|
|
/**
|
|
* PUT /api/events/{clientId}
|
|
*/
|
|
public function update(UpdateEventRequest $request, string $clientId): EventResource
|
|
{
|
|
$event = $request->user()->events()
|
|
->where('client_id', $clientId)
|
|
->firstOrFail();
|
|
|
|
$data = [];
|
|
$validated = $request->validated();
|
|
|
|
if (isset($validated['title'])) {
|
|
$data['title'] = $validated['title'];
|
|
}
|
|
if (isset($validated['date'])) {
|
|
$data['date'] = $validated['date'];
|
|
}
|
|
if (isset($validated['emotion'])) {
|
|
$data['emotion'] = $validated['emotion'];
|
|
}
|
|
if (array_key_exists('customColor', $validated)) {
|
|
$data['custom_color'] = $validated['customColor'];
|
|
}
|
|
if (array_key_exists('gradientPreset', $validated)) {
|
|
$data['gradient_preset'] = $validated['gradientPreset'];
|
|
}
|
|
if (array_key_exists('image', $validated)) {
|
|
$data['image'] = $validated['image'];
|
|
}
|
|
if (array_key_exists('note', $validated)) {
|
|
$data['note'] = $validated['note'];
|
|
}
|
|
|
|
$event->update($data);
|
|
|
|
return new EventResource($event->fresh()->load('media'));
|
|
}
|
|
|
|
/**
|
|
* DELETE /api/events/{clientId}
|
|
*/
|
|
public function destroy(Request $request, string $clientId): JsonResponse
|
|
{
|
|
$event = $request->user()->events()
|
|
->where('client_id', $clientId)
|
|
->firstOrFail();
|
|
|
|
$event->delete();
|
|
|
|
return response()->json(null, 204);
|
|
}
|
|
|
|
/**
|
|
* POST /api/events/sync
|
|
* Batch sync: process multiple mutations in one request.
|
|
*/
|
|
public function sync(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'mutations' => ['required', 'array', 'max:100'],
|
|
'mutations.*.action' => ['required', 'in:create,update,delete'],
|
|
'mutations.*.eventId' => ['required', 'uuid'],
|
|
'mutations.*.payload' => ['nullable', 'array'],
|
|
]);
|
|
|
|
$user = $request->user();
|
|
$results = [];
|
|
|
|
foreach ($request->input('mutations') as $mutation) {
|
|
$action = $mutation['action'];
|
|
$clientId = $mutation['eventId'];
|
|
$payload = $mutation['payload'] ?? [];
|
|
|
|
try {
|
|
if ($action === 'create') {
|
|
$event = $user->events()->where('client_id', $clientId)->first();
|
|
if (! $event) {
|
|
$event = $user->events()->create([
|
|
'client_id' => $clientId,
|
|
'title' => $payload['title'] ?? 'Untitled',
|
|
'date' => $payload['date'] ?? now()->format('Y-m-d'),
|
|
'emotion' => $payload['emotion'] ?? 0,
|
|
'custom_color' => $payload['customColor'] ?? null,
|
|
'gradient_preset' => $payload['gradientPreset'] ?? null,
|
|
'image' => $payload['image'] ?? null,
|
|
'note' => $payload['note'] ?? null,
|
|
]);
|
|
}
|
|
$results[] = ['eventId' => $clientId, 'status' => 'ok'];
|
|
} elseif ($action === 'update') {
|
|
$event = $user->events()->where('client_id', $clientId)->first();
|
|
if ($event) {
|
|
$data = [];
|
|
if (isset($payload['title'])) {
|
|
$data['title'] = $payload['title'];
|
|
}
|
|
if (isset($payload['date'])) {
|
|
$data['date'] = $payload['date'];
|
|
}
|
|
if (isset($payload['emotion'])) {
|
|
$data['emotion'] = $payload['emotion'];
|
|
}
|
|
if (array_key_exists('customColor', $payload)) {
|
|
$data['custom_color'] = $payload['customColor'];
|
|
}
|
|
if (array_key_exists('gradientPreset', $payload)) {
|
|
$data['gradient_preset'] = $payload['gradientPreset'];
|
|
}
|
|
if (array_key_exists('image', $payload)) {
|
|
$data['image'] = $payload['image'];
|
|
}
|
|
if (array_key_exists('note', $payload)) {
|
|
$data['note'] = $payload['note'];
|
|
}
|
|
$event->update($data);
|
|
}
|
|
$results[] = ['eventId' => $clientId, 'status' => 'ok'];
|
|
} elseif ($action === 'delete') {
|
|
$user->events()->where('client_id', $clientId)->delete();
|
|
$results[] = ['eventId' => $clientId, 'status' => 'ok'];
|
|
}
|
|
} catch (\Throwable $e) {
|
|
$results[] = ['eventId' => $clientId, 'status' => 'error', 'message' => $e->getMessage()];
|
|
}
|
|
}
|
|
|
|
return response()->json(['results' => $results]);
|
|
}
|
|
}
|