257 lines
8.1 KiB
PHP
257 lines
8.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Http\Requests\StoreHuntRequest;
|
|
use App\Http\Requests\UpdateHuntRequest;
|
|
use App\Models\Hunts;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class HuntsController extends Controller
|
|
{
|
|
/**
|
|
* Display a listing of the resource.
|
|
*/
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
try {
|
|
$searchTerm = $this->resolveSearchTerm($request);
|
|
|
|
if ($searchTerm !== null) {
|
|
$hunts = Hunts::search($searchTerm)
|
|
->query(fn (Builder $query) => $this->applyHuntFilters(
|
|
$query->with('participants:id,avatar_uri'),
|
|
$request
|
|
))
|
|
->paginate(10);
|
|
|
|
return response()->json($hunts);
|
|
}
|
|
|
|
$query = $this->applyHuntFilters(
|
|
Hunts::with('participants:id,avatar_uri'),
|
|
$request
|
|
);
|
|
|
|
$hunts = $query->paginate(10);
|
|
|
|
return response()->json($hunts);
|
|
} catch (\Throwable $e) {
|
|
Log::error('Error fetching hunts: '.$e->getMessage());
|
|
|
|
return response()->json([
|
|
'error' => 'Server Error',
|
|
'message' => $e->getMessage(),
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
private function applyHuntFilters(Builder $query, Request $request): Builder
|
|
{
|
|
if ($request->has('participating')) {
|
|
$participating = filter_var(
|
|
$request->query('participating'),
|
|
FILTER_VALIDATE_BOOLEAN,
|
|
FILTER_NULL_ON_FAILURE
|
|
);
|
|
|
|
$userId = auth('sanctum')->id();
|
|
|
|
Log::info('Participating filter resolved', [
|
|
'participating' => $participating,
|
|
'user_id' => $userId,
|
|
]);
|
|
|
|
if (! $userId) {
|
|
if ($participating === true) {
|
|
$query->whereRaw('1 = 0');
|
|
}
|
|
} else {
|
|
if ($participating === true) {
|
|
$query->whereHas('participants', function ($q) use ($userId) {
|
|
$q->where('user_id', $userId);
|
|
});
|
|
} else {
|
|
$query->whereDoesntHave('participants', function ($q) use ($userId) {
|
|
$q->where('user_id', $userId);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($request->has('active')) {
|
|
$now = Carbon::now();
|
|
$active = filter_var($request->query('active'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
|
|
|
if ($active === true) {
|
|
$query->where('start_at', '<=', $now)
|
|
->where(function ($q) use ($now) {
|
|
$q->whereNull('end_at')
|
|
->orWhere('end_at', '>=', $now);
|
|
});
|
|
} else {
|
|
$query->where(function ($q) use ($now) {
|
|
$q->whereNull('start_at')
|
|
->orWhere('start_at', '>', $now)
|
|
->orWhere(function ($q2) use ($now) {
|
|
$q2->whereNotNull('end_at')
|
|
->where('end_at', '<', $now);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
return $query;
|
|
}
|
|
|
|
private function resolveSearchTerm(Request $request): ?string
|
|
{
|
|
$searchTerm = $request->query('search') ?? $request->query('q');
|
|
|
|
if (! is_string($searchTerm)) {
|
|
return null;
|
|
}
|
|
|
|
$searchTerm = trim($searchTerm);
|
|
|
|
return $searchTerm !== '' ? $searchTerm : null;
|
|
}
|
|
|
|
/**
|
|
* Store a newly created resource in storage.
|
|
*/
|
|
public function store(StoreHuntRequest $request): JsonResponse
|
|
{
|
|
$validated = $request->validated();
|
|
|
|
$validated['creator_id'] = auth()->id();
|
|
|
|
$hunt = Hunts::create($validated);
|
|
|
|
return response()->json($hunt, 201);
|
|
}
|
|
|
|
/**
|
|
* Display the specified resource.
|
|
*/
|
|
/**
|
|
* Display the specified resource.
|
|
*/
|
|
public function show(Request $request, int $id): JsonResponse
|
|
{
|
|
$hunt = Hunts::with(['steps', 'participants:id,avatar_uri'])->find($id);
|
|
|
|
if (! $hunt) {
|
|
return response()->json(['message' => 'Hunt not found'], 404);
|
|
}
|
|
|
|
$user = $request->user('sanctum');
|
|
|
|
if ($user) {
|
|
$participation = $user->participations()->where('hunt_id', $hunt->id)->first();
|
|
|
|
if ($participation) {
|
|
// User is a participant
|
|
$currentStepNumber = $participation->pivot->current_step_number;
|
|
|
|
// Filter steps
|
|
$hunt->setRelation('steps', $hunt->steps->filter(function ($step) use ($currentStepNumber) {
|
|
if ($step->step_number < $currentStepNumber) {
|
|
return true; // Show past steps fully
|
|
}
|
|
if ($step->step_number == $currentStepNumber) {
|
|
// Show hints but hide location for current step
|
|
$step->makeHidden(['latitude', 'longitude', 'radius_m']);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false; // Hide future steps
|
|
})->values());
|
|
|
|
$hunt->participation_status = $participation->pivot;
|
|
} elseif ($hunt->creator_id !== $user->id) {
|
|
// User is logged in but not participant and not creator
|
|
// Show only first step or nothing specific (keep as is for now, maybe hide all steps or just show basic info)
|
|
// For now, let's just hide hints of all steps if not participating?
|
|
// Or maybe just show nothing of steps if not participating?
|
|
// Requirement: "fetch the hunt in question it retrieves me the hunt steps already passed and the next one" implying context of participation.
|
|
// If not participating, maybe just return basic hunt info without steps?
|
|
$hunt->unsetRelation('steps');
|
|
}
|
|
// If creator, show everything (default)
|
|
} else {
|
|
// Guest
|
|
$hunt->unsetRelation('steps');
|
|
}
|
|
|
|
return response()->json($hunt);
|
|
}
|
|
|
|
public function participate(Request $request, int $id): JsonResponse
|
|
{
|
|
$hunt = Hunts::findOrFail($id);
|
|
$user = $request->user();
|
|
|
|
if ($user->participations()->where('hunt_id', $hunt->id)->exists()) {
|
|
return response()->json(['message' => 'Already participating'], 409);
|
|
}
|
|
|
|
$hunt->participants()->attach($user->id, ['current_step_number' => 1, 'status' => 'started']);
|
|
|
|
return response()->json(['message' => 'Participation started'], 201);
|
|
}
|
|
|
|
public function unparticipate(Request $request, int $id): JsonResponse
|
|
{
|
|
$hunt = Hunts::findOrFail($id);
|
|
$user = $request->user();
|
|
|
|
if (! $user->participations()->where('hunt_id', $hunt->id)->exists()) {
|
|
return response()->json(['message' => 'Not participating'], 404);
|
|
}
|
|
|
|
$hunt->participants()->detach($user->id);
|
|
|
|
return response()->json(['message' => 'Participation stopped'], 200);
|
|
}
|
|
|
|
/**
|
|
* Update the specified resource in storage.
|
|
*/
|
|
public function update(UpdateHuntRequest $request, int $id): JsonResponse
|
|
{
|
|
$hunt = Hunts::find($id);
|
|
|
|
if (! $hunt) {
|
|
return response()->json(['message' => 'Hunt not found'], 404);
|
|
}
|
|
|
|
$validated = $request->validated();
|
|
|
|
$hunt->update($validated);
|
|
|
|
return response()->json($hunt);
|
|
}
|
|
|
|
/**
|
|
* Remove the specified resource from storage.
|
|
*/
|
|
public function destroy(int $id): JsonResponse
|
|
{
|
|
$hunt = Hunts::find($id);
|
|
|
|
if (! $hunt) {
|
|
return response()->json(['message' => 'Hunt not found'], 404);
|
|
}
|
|
|
|
$hunt->delete();
|
|
|
|
return response()->json(['message' => 'Hunt deleted successfully']);
|
|
}
|
|
}
|