diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..9be30f5 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,28 @@ +{ + "useTabs": true, + "tabWidth": 4, + "semi": true, + "singleQuote": false, + "printWidth": 140, + "trailingComma": "none", + "quoteProps": "consistent", + "arrowParens": "avoid", + "bracketSpacing": true, + + "overrides": [ + { + "files": ["*.yml", "*.yaml"], + "options": { + "useTabs": false, + "tabWidth": 2 + } + }, + { + "files": ["Dockerfile", "Dockerfile.*"], + "options": { + "useTabs": false, + "tabWidth": 2 + } + } + ] +} diff --git a/note2quiz-backend/Note2Quiz.API/Controllers/QuizController.cs b/note2quiz-backend/Note2Quiz.API/Controllers/QuizController.cs index c0d2a63..926db4a 100644 --- a/note2quiz-backend/Note2Quiz.API/Controllers/QuizController.cs +++ b/note2quiz-backend/Note2Quiz.API/Controllers/QuizController.cs @@ -1,4 +1,99 @@ -// POST /api/quiz/generate -// GET /api/quiz/history +// POST /api/quiz/submit +using System.Security.Claims; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Note2Quiz.API.DTOs; +using Note2Quiz.API.Interfaces; + namespace Note2Quiz.API.Controllers; +[ApiController] +[Route("api/[controller]")] +[Authorize] +public class QuizController : ControllerBase +{ + private readonly IQuizService _quizService; + + public QuizController(IQuizService quizService) + { + _quizService = quizService; + } + + [HttpPost] + [RequestSizeLimit(20 * 1024 * 1024)] + public async Task> Create( + [FromForm] IFormFile file, + [FromForm] Difficulty difficulty, + CancellationToken ct + ) + { + if (file == null || file.Length == 0) + return BadRequest("File is required."); + + if (file.Length > 20 * 1024 * 1024) + return BadRequest("File too large. Max size is 20MB."); + + if (file.ContentType is not ("image/jpeg" or "image/png")) + return BadRequest("Only jpeg or png allowed."); + + var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + if (userId == null) + return Unauthorized(); + + var request = new CreateQuizRequest(file, difficulty); + + var result = await _quizService.CreateQuizAsync(userId, request, ct); + + return Ok(result); + } + + [HttpGet("history")] + public async Task>> GetQuizHistory(CancellationToken ct) + { + var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + + if (userId == null) + return Unauthorized(); + + var result = await _quizService.GetQuizzesAsync(userId, ct); + + return Ok(result); + } + + + [HttpGet("{quizSessionId}")] + public async Task> GetQuiz(int quizSessionId, CancellationToken ct) + { + var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + + if (userId == null) + return Unauthorized(); + + var result = await _quizService.GetQuizAsync(userId, quizSessionId, ct); + + return Ok(result); + } + + [HttpPost("submit")] + public async Task> Submit( + [FromBody] SubmitQuizRequest request, + CancellationToken ct) + { + var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + if (userId == null) + return Unauthorized(); + + if (request == null) + return BadRequest("Request is required."); + + if (request.QuizSessionId <= 0) + return BadRequest("QuizSessionId is invalid."); + + if (request.Answers == null || request.Answers.Count == 0) + return BadRequest("Answers are required."); + + var result = await _quizService.SubmitQuizAsync(userId, request, ct); + + return Ok(result); + } +} diff --git a/note2quiz-backend/Note2Quiz.API/DTOs/QuizDto.cs b/note2quiz-backend/Note2Quiz.API/DTOs/QuizDto.cs index 20842fa..ba73797 100644 --- a/note2quiz-backend/Note2Quiz.API/DTOs/QuizDto.cs +++ b/note2quiz-backend/Note2Quiz.API/DTOs/QuizDto.cs @@ -4,29 +4,20 @@ public enum Difficulty { Easy, Medium, - Hard + Hard, } -public record CreateQuizRequest( - string ImageBase64, - Difficulty Difficulty -); +public record CreateQuizRequest(IFormFile Image, Difficulty Difficulty); -public record QuizResponse( - int QuizSessionId, - List Questions -); +public record QuizResponse(int QuizSessionId, List Questions); -public record QuestionDto( - int Id, - string Text, - List Options -); +public record QuestionDto(int Id, string Text, List Options); -public record SubmitQuizRequest( - int QuizSessionId, - List SelectedOptionsIds -); +public record OptionDto(int OptionId, string OptionText); + +public record SubmitQuizRequest(int QuizSessionId, List Answers); + +public record AnswerDto(int QuestionId, int SelectedOptionId); public record SubmitQuizResponse( int QuizSessionId, @@ -46,5 +37,7 @@ public record QuizHistoryItemDto( int QuizSessionId, DateTime CreatedAt, int QuestionCount, - int? Score -); \ No newline at end of file + int? Score, + Difficulty Difficulty, + string Title +); diff --git a/note2quiz-backend/Note2Quiz.API/Data/Note2QuizDbContext.cs b/note2quiz-backend/Note2Quiz.API/Data/Note2QuizDbContext.cs index 9a6054c..7e8d956 100644 --- a/note2quiz-backend/Note2Quiz.API/Data/Note2QuizDbContext.cs +++ b/note2quiz-backend/Note2Quiz.API/Data/Note2QuizDbContext.cs @@ -1 +1,71 @@ +using Microsoft.EntityFrameworkCore; +using Note2Quiz.API.Models; + namespace Note2Quiz.API.Data; + +public class Note2QuizDbContext : DbContext +{ + public Note2QuizDbContext(DbContextOptions options) + : base(options) + { + } + + public DbSet QuizSessions { get; set; } + public DbSet Questions { get; set; } + public DbSet