'required|string|max:255', 'description' => 'required|string', 'category_id' => 'nullable|exists:categories,id', 'questions' => 'required|array|min:1', 'questions.*' => 'exists:questions,id', 'closed_at' => 'nullable|date', ]; /** * @OA\Get( * path="/api/tests", * summary="Get a list of tests (paginated)", * description="Retrieve a paginated list of tests. Optionally filter by category_id.", * tags={"Tests"}, * @OA\Parameter( * name="category_id", * in="query", * required=false, * description="Filter tests by category ID", * @OA\Schema(type="integer") * ), * @OA\Response( * response=200, * description="Paginated list of tests", * @OA\JsonContent( * type="object", * @OA\Property( * property="data", * type="array", * @OA\Items(ref="#/components/schemas/TestResource") * ), * @OA\Property( * property="links", * type="object", * @OA\Property(property="first", type="string", example="http://api.example.com/tests?page=1"), * @OA\Property(property="last", type="string", example="http://api.example.com/tests?page=10"), * @OA\Property(property="prev", type="string", nullable=true, example=null), * @OA\Property(property="next", type="string", nullable=true, example="http://api.example.com/tests?page=2") * ), * @OA\Property( * property="meta", * type="object", * @OA\Property(property="current_page", type="integer", example=1), * @OA\Property(property="from", type="integer", example=1), * @OA\Property(property="last_page", type="integer", example=10), * @OA\Property(property="path", type="string", example="http://api.example.com/tests"), * @OA\Property(property="per_page", type="integer", example=15), * @OA\Property(property="to", type="integer", example=15), * @OA\Property(property="total", type="integer", example=150) * ) * ) * ), * @OA\Response( * response=401, * description="Unauthorized" * ) * ) */ public function index(Request $request) { $query = Test::with(['author', 'category']); if ($request->has('category_id')) { $query->where('category_id', $request->query('category_id')); } $questions = $query->paginate(self::PAGINATION_COUNT); return TestResource::collection($questions); } /** * @OA\Post( * path="/api/tests", * summary="Create a new test (only admin or creator)", * description="Store a new test in the system (only admin or creator).", * tags={"Tests"}, * security={{"bearerAuth":{}}}, * @OA\RequestBody( * required=true, * @OA\JsonContent( * required={"title","closed_at","questions"}, * @OA\Property(property="title", type="string", maxLength=255, example="Sample Test"), * @OA\Property(property="description", type="string", nullable=true, example="Optional description"), * @OA\Property(property="closed_at", type="string", format="date-time", nullable=true, example="2025-12-01 23:59:59"), * @OA\Property(property="category_id", type="integer", nullable=true, example=3), * @OA\Property( * property="questions", * type="array", * description="Array of question IDs to attach to this test", * @OA\Items(type="integer", example=1) * ) * ) * ), * @OA\Response( * response=200, * description="Test created successfully", * @OA\JsonContent(ref="#/components/schemas/TestResource") * ), * @OA\Response( * response=401, * description="Unauthorized" * ), * @OA\Response( * response=422, * description="Validation error" * ) * ) */ public function store(Request $request) { $this->authorize('create', Test::class); $fields = $request->validate(self::FIELD_RULES); $fields['author_id'] = $request->user()->id; $test = Test::create($fields); $test->questions()->sync($fields['questions']); $test->load(['category', 'author', 'questions']); Log::writeLog("Test '" . $test->title . "' is created by " . $request->user()->username); return new TestResource($test); } /** * @OA\Get( * path="/api/tests/{id}", * summary="Get a single test", * description="Retrieve a single test with its questions, category, and author", * tags={"Tests"}, * @OA\Parameter( * name="id", * in="path", * required=true, * description="Test ID", * @OA\Schema(type="integer") * ), * @OA\Response( * response=200, * description="Test retrieved successfully", * @OA\JsonContent(ref="#/components/schemas/TestResource") * ), * @OA\Response( * response=404, * description="Test not found" * ) * ) */ public function show(Test $test) { $test->load(['author', 'category', 'questions']); return new TestResource($test); } /** * @OA\Put( * path="/api/tests/{id}", * summary="Update a test (only admin or creator)", * description="Update a test's data and associated questions (only admin/creator).", * tags={"Tests"}, * security={{"bearerAuth":{}}}, * @OA\Parameter( * name="id", * in="path", * required=true, * description="Test ID", * @OA\Schema(type="integer") * ), * @OA\RequestBody( * required=true, * @OA\JsonContent( * required={"title","questions"}, * @OA\Property(property="title", type="string", maxLength=255, example="Updated Test Title"), * @OA\Property(property="description", type="string", nullable=true, example="Optional description"), * @OA\Property(property="category_id", type="integer", nullable=true, example=3), * @OA\Property(property="closed_at", type="string", format="date-time", nullable=true, example="2025-12-01T23:59:59Z"), * @OA\Property( * property="questions", * type="array", * description="Array of question IDs to attach to this test", * @OA\Items(type="integer", example=1) * ) * ) * ), * @OA\Response( * response=200, * description="Test updated successfully", * @OA\JsonContent(ref="#/components/schemas/TestResource") * ), * @OA\Response( * response=401, * description="Unauthorized" * ), * @OA\Response( * response=422, * description="Validation error" * ) * ) */ public function update(Request $request, Test $test) { $this->authorize('update', $test); $fields = $request->validate(self::FIELD_RULES); $test->update($fields); $test->questions()->sync($fields['questions']); Log::writeLog("Test '" . $test->title . "' is updated by " . $request->user()->username); $test->load(['category', 'author', 'questions']); return new TestResource($test); } /** * @OA\Delete( * path="/api/tests/{id}", * summary="Delete a test (only admin or creator)", * description="Delete a test by ID (only admin or creator).", * tags={"Tests"}, * security={{"bearerAuth":{}}}, * @OA\Parameter( * name="id", * in="path", * required=true, * description="Test ID", * @OA\Schema(type="integer") * ), * @OA\Response( * response=200, * description="Test deleted successfully", * @OA\JsonContent( * type="object", * @OA\Property(property="message", type="string", example="The test was deleted") * ) * ), * @OA\Response( * response=401, * description="Unauthorized" * ), * @OA\Response( * response=404, * description="Test not found" * ) * ) */ public function destroy(Request $request, Test $test) { $this->authorize('delete', $test); $test->delete(); Log::writeLog("Test '" . $test->title . "' is deleted by " . $request->user()->username); return ['message' => 'The hitcount was deleted']; } }