HoshiAI-be/app/Http/Controllers/QuestionController.php
2025-11-12 23:04:55 +01:00

276 lines
10 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Http\Resources\QuestionResource;
use App\Models\Log;
use App\Models\Question;
use App\Rules\ValidVariants;
use Illuminate\Http\Request;
class QuestionController extends Controller
{
const PAGINATION_COUNT = 20;
private static function get_field_rules(): array
{
return [
'title' => 'required|string|max:255',
'description' => 'nullable|string',
'type' => 'required|in:single,multiple,text',
'difficulty' => 'required|integer',
'category_id' => 'nullable|exists:categories,id',
'variants' => ['array', 'nullable'],
'variants.*.id' => ['required', 'integer'],
'variants.*.text' => ['required', 'string'],
'correct_answers' => 'required|array',
'is_pending_question' => 'integer'
];
}
/**
* @OA\Get(
* path="/api/questions",
* summary="Get a paginated list of questions (paginated)",
* description="Retrieve questions. Optional filter by category_id.",
* tags={"Questions"},
* @OA\Parameter(
* name="category_id",
* in="query",
* description="Filter questions by category ID",
* required=false,
* @OA\Schema(type="integer")
* ),
* @OA\Parameter(
* name="page",
* in="query",
* description="Page number for pagination",
* required=false,
* @OA\Schema(type="integer", default=1)
* ),
* @OA\Response(
* response=200,
* description="Paginated list of questions",
* @OA\JsonContent(
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/QuestionResource")
* ),
* @OA\Property(
* property="links",
* type="object",
* example={
* "first": "http://localhost/api/questions?page=1",
* "last": "http://localhost/api/questions?page=10",
* "prev": null,
* "next": "http://localhost/api/questions?page=2"
* }
* ),
* @OA\Property(
* property="meta",
* type="object",
* example={
* "current_page": 1,
* "from": 1,
* "last_page": 10,
* "path": "http://localhost/api/questions",
* "per_page": 15,
* "to": 15,
* "total": 150
* }
* )
* )
* )
* )
*/
public function index(Request $request)
{
$query = Question::with(['author', 'category']);
if ($request->has('category_id')) {
$query->where('category_id', $request->query('category_id'));
}
$questions = $query->paginate(self::PAGINATION_COUNT);
return QuestionResource::collection($questions);
}
/**
* @OA\Get(
* path="/api/questions/{id}",
* summary="Get a single question",
* description="Retrieve a single question by its ID, including author and category",
* tags={"Questions"},
* @OA\Parameter(
* name="id",
* in="path",
* description="ID of the question to retrieve",
* required=true,
* @OA\Schema(type="integer")
* ),
* @OA\Response(
* response=200,
* description="Question retrieved successfully",
* @OA\JsonContent(ref="#/components/schemas/QuestionResource")
* )
* )
*/
public function show(Question $question)
{
$question->load(['author', 'category']);
return new QuestionResource($question);
}
/**
* @OA\Post(
* path="/api/questions",
* summary="Create a new question (only admin or creator)",
* description="Store a new question in the system.",
* tags={"Questions"},
* security={{"bearerAuth":{}}},
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* required={"title","type","difficulty","variants","correct_answers"},
* @OA\Property(property="title", type="string", maxLength=255, example="Sample question"),
* @OA\Property(property="description", type="string", nullable=true, example="Optional description"),
* @OA\Property(property="type", type="string", enum={"single","multiply","text"}, example="single"),
* @OA\Property(property="difficulty", type="integer", example=2),
* @OA\Property(
* property="variants",
* type="array",
* @OA\Items(
* type="object",
* @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="text", type="string", example="Option 1")
* )
* ),
* @OA\Property(
* property="correct_answers",
* type="array",
* @OA\Items(
* type="integer",
* example=1
* )
* ),
* @OA\Property(property="category_id", type="integer", nullable=true, example=3),
* @OA\Property(property="is_pending_question", type="integer", example=0)
* )
* ),
* @OA\Response(
* response=200,
* description="Question created successfully",
* @OA\JsonContent(ref="#/components/schemas/QuestionResource")
* )
* )
*/
public function store(Request $request)
{
$this->authorize('create', Question::class);
$fields = $request->validate(self::get_field_rules());
$fields['author_id'] = $request->user()->id;
$question = Question::create($fields);
Log::writeLog("Question '" . $question->title . "' is created by " . $request->user()->username);
return new QuestionResource($question);
}
/**
* @OA\Put(
* path="/api/questions/{id}",
* summary="Update a question (only admin or creator)",
* description="Update an existing question by ID.",
* tags={"Questions"},
* security={{"bearerAuth":{}}},
* @OA\Parameter(
* name="id",
* in="path",
* required=true,
* description="ID of the question to update",
* @OA\Schema(type="integer")
* ),
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* required={"title","type","difficulty","variants","correct_answers"},
* @OA\Property(property="title", type="string", maxLength=255, example="Updated question"),
* @OA\Property(property="description", type="string", nullable=true, example="Updated description"),
* @OA\Property(property="type", type="string", enum={"single","multiply","text"}, example="multiply"),
* @OA\Property(property="difficulty", type="integer", example=3),
* @OA\Property(
* property="variants",
* type="array",
* @OA\Items(
* type="object",
* @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="text", type="string", example="Option 1")
* )
* ),
* @OA\Property(
* property="correct_answers",
* type="array",
* @OA\Items(
* type="integer",
* example=1
* )
* ),
* @OA\Property(property="category_id", type="integer", nullable=true, example=2),
* @OA\Property(property="is_pending_question", type="integer", example=0)
* )
* ),
* @OA\Response(
* response=200,
* description="Question updated successfully",
* @OA\JsonContent(ref="#/components/schemas/QuestionResource")
* )
* )
*/
public function update(Request $request, Question $question)
{
$this->authorize('update', $question);
$fields = $request->validate(self::get_field_rules());
$fields['variants'] = json_encode($fields['variants']);
$question->update($fields);
Log::writeLog("Question '" . $question->title . "' is updated by " . $request->user()->username);
return new QuestionResource($question);
}
/**
* @OA\Delete(
* path="/api/questions/{id}",
* summary="Delete a question (only admin or creator)",
* description="Delete a question by ID .",
* tags={"Questions"},
* security={{"bearerAuth":{}}},
* @OA\Parameter(
* name="id",
* in="path",
* required=true,
* description="ID of the question to delete",
* @OA\Schema(type="integer")
* ),
* @OA\Response(
* response=200,
* description="Question deleted successfully",
* @OA\JsonContent(
* @OA\Property(property="message", type="string", example="The hitcount was deleted")
* )
* )
* )
*/
public function destroy(Request $request, Question $question)
{
$this->authorize('delete', $question);
$question->delete();
Log::writeLog("Question '" . $question->title . "' is deleted by " . $request->user()->username);
return ['message' => 'The question was deleted'];
}
}