feat: hunts and middleware

This commit is contained in:
Leon 2025-12-18 10:48:48 +01:00
parent e991c57055
commit 1da3515fe9
5 changed files with 240 additions and 0 deletions

View File

@ -0,0 +1,110 @@
<?php
namespace App\Http\Controllers;
use App\Models\Hunts;
use Illuminate\Http\Request;
class HuntsController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
$hunts = Hunts::paginate(10);
return response()->json($hunts);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$validated = $request->validate([
'partner_id' => 'required|string',
'title' => 'required|string',
'slug' => 'required|string|unique:hunts,slug',
'description' => 'nullable|string',
'status' => 'required|string',
'difficulty' => 'required|string',
'city' => 'required|string',
'latitude' => 'nullable|numeric',
'longitude' => 'nullable|numeric',
'is_public' => 'boolean',
'estimated_duration_min' => 'nullable|integer',
'start_at' => 'nullable|date',
'end_at' => 'nullable|date',
'image' => 'nullable|string',
'creator_id' => 'nullable|exists:users,id',
]);
$hunt = Hunts::create($validated);
return response()->json($hunt, 201);
}
/**
* Display the specified resource.
*/
public function show($id)
{
$hunt = Hunts::find($id);
if (!$hunt) {
return response()->json(['message' => 'Hunt not found'], 404);
}
return response()->json($hunt);
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, $id)
{
$hunt = Hunts::find($id);
if (!$hunt) {
return response()->json(['message' => 'Hunt not found'], 404);
}
$validated = $request->validate([
'partner_id' => 'sometimes|string',
'title' => 'sometimes|string',
'slug' => 'sometimes|string|unique:hunts,slug,' . $id,
'description' => 'nullable|string',
'status' => 'sometimes|string',
'difficulty' => 'sometimes|string',
'city' => 'sometimes|string',
'latitude' => 'nullable|numeric',
'longitude' => 'nullable|numeric',
'is_public' => 'boolean',
'estimated_duration_min' => 'nullable|integer',
'start_at' => 'nullable|date',
'end_at' => 'nullable|date',
'image' => 'nullable|string',
'creator_id' => 'nullable|exists:users,id',
]);
$hunt->update($validated);
return response()->json($hunt);
}
/**
* Remove the specified resource from storage.
*/
public function destroy($id)
{
$hunt = Hunts::find($id);
if (!$hunt) {
return response()->json(['message' => 'Hunt not found'], 404);
}
$hunt->delete();
return response()->json(['message' => 'Hunt deleted successfully']);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureUserIsOrga
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
/** @var \App\Models\User $user */
$user = $request->user();
if (
!$user ||
($user->role !== \App\Enums\UserRole::ORGA && $user->role !== \App\Enums\UserRole::ADMIN)
) {
abort(403, 'Unauthorized action.');
}
return $next($request);
}
}

40
app/Models/Hunts.php Normal file
View File

@ -0,0 +1,40 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Hunts extends Model
{
use HasFactory;
protected $table = 'hunts';
protected $fillable = [
'partner_id',
'title',
'slug',
'description',
'status',
'difficulty',
'city',
'latitude',
'longitude',
'is_public',
'estimated_duration_min',
'start_at',
'end_at',
'image',
'creator_id',
];
protected $casts = [
'is_public' => 'boolean',
'start_at' => 'datetime',
'end_at' => 'datetime',
'latitude' => 'float',
'longitude' => 'float',
'estimated_duration_min' => 'integer',
];
}

View File

@ -0,0 +1,50 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('hunts', function (Blueprint $table) {
$table->string('partner_id')->index();
$table->string('title');
$table->string('slug')->unique();
$table->text('description')->nullable();
$table->string('status')->index();
$table->string('difficulty')->index();
$table->string('city')->index();
$table->decimal('latitude', 10, 7)->nullable();
$table->decimal('longitude', 10, 7)->nullable();
$table->boolean('is_public')->default(false);
$table->unsignedSmallInteger('estimated_duration_min')->nullable();
$table->timestamp('start_at')->nullable();
$table->timestamp('end_at')->nullable();
$table->string('image')->nullable();
$table->foreignId('creator_id')->nullable()->constrained('users')->nullOnDelete();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('hunts');
}
};

View File

@ -6,6 +6,9 @@ use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HuntsController;
use App\Http\Middleware\EnsureUserIsOrga;
Route::prefix('auth')->group(function (): void {
Route::post('register', [AuthController::class, 'register']);
Route::post('login', [AuthController::class, 'login']);
@ -15,7 +18,14 @@ Route::prefix('auth')->group(function (): void {
});
Route::get('hunts', [HuntsController::class, 'index']);
Route::get('hunts/{hunt}', [HuntsController::class, 'show']);
Route::middleware(['auth:sanctum', EnsureUserIsOrga::class])->group(function () {
Route::post('hunts', [HuntsController::class, 'store']);
Route::match(['put', 'patch'], 'hunts/{hunt}', [HuntsController::class, 'update']);
Route::delete('hunts/{hunt}', [HuntsController::class, 'destroy']);
});
Route::middleware('auth:sanctum')->group(function (): void {
// Route::get('/user', function (Request $request) {