DeutschLernen/GermanApp/Application/DTOs/QuizQuestionDto.cs
Lasse Rune Hansen 04ad7ef008 feat(backend/domain): add quiz question feature with Docker migration support
- Add QuizQuestion and QuizOption domain entities with QuestionType enum
- Add IQuizQuestionRepository and IQuizOptionRepository interfaces
- Add QuizQuestionRepository and QuizOptionRepository EF Core implementations
- Add QuizQuestionService with CRUD, quiz submission, and statistics
- Add QuizQuestionsController with comprehensive REST API endpoints
- Add QuizQuestionDto and related DTOs for API communication
- Add EF Core migration (20260612050652_AddQuizQuestionTables) for QuizQuestion and QuizOption
- Add seed data with sample quiz questions for Greetings, Numbers, Grammar lessons
- Update AppDbContext with DbSets and entity configurations
- Update Program.cs with migration retry logic for Docker
- Update docker-compose.yml with SeedDatabase configuration
- Add unit tests for QuizQuestionService

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-12 16:49:27 +02:00

191 lines
5.2 KiB
C#

using GermanApp.Domain.Entities;
namespace GermanApp.Application.DTOs;
/// <summary>
/// Data Transfer Object for QuizQuestion - used for API responses.
/// This is a read-only representation of a QuizQuestion entity.
/// </summary>
public record QuizQuestionDto(
int Id,
int LessonId,
string LessonTitle,
string QuestionText,
QuestionType Type,
string? CorrectAnswer,
int Difficulty,
int Order,
bool IsActive,
DateTime CreatedAt,
DateTime? UpdatedAt,
IReadOnlyList<QuizOptionDto> Options);
/// <summary>
/// Data Transfer Object for creating a new QuizQuestion.
/// </summary>
public record CreateQuizQuestionDto(
int LessonId,
string QuestionText,
QuestionType Type,
string? CorrectAnswer,
int Difficulty,
int Order,
IReadOnlyList<CreateQuizOptionDto>? Options);
/// <summary>
/// Data Transfer Object for updating an existing QuizQuestion.
/// </summary>
public record UpdateQuizQuestionDto(
int LessonId,
string QuestionText,
QuestionType Type,
string? CorrectAnswer,
int Difficulty,
int Order,
bool IsActive,
IReadOnlyList<UpdateQuizOptionDto>? Options);
/// <summary>
/// Data Transfer Object for QuizOption - used for API responses.
/// </summary>
public record QuizOptionDto(
int Id,
int QuizQuestionId,
string Text,
bool IsCorrect,
int Order);
/// <summary>
/// Data Transfer Object for creating a new QuizOption.
/// </summary>
public record CreateQuizOptionDto(
string Text,
bool IsCorrect,
int Order);
/// <summary>
/// Data Transfer Object for updating an existing QuizOption.
/// </summary>
public record UpdateQuizOptionDto(
int Id,
string Text,
bool IsCorrect,
int Order);
/// <summary>
/// Data Transfer Object for quiz question with user's answer.
/// </summary>
public record QuizQuestionWithAnswerDto(
int QuizQuestionId,
int LessonId,
string QuestionText,
QuestionType Type,
IReadOnlyList<QuizOptionDto> Options,
string? UserAnswer,
bool IsCorrect);
/// <summary>
/// Data Transfer Object for submitting quiz answers.
/// </summary>
public record SubmitQuizAnswersDto(
int LessonId,
IReadOnlyList<QuizAnswerDto> Answers);
/// <summary>
/// Data Transfer Object for a single quiz answer submission.
/// </summary>
public record QuizAnswerDto(
int QuizQuestionId,
string? AnswerText,
int[]? SelectedOptionIds);
/// <summary>
/// Data Transfer Object for quiz result.
/// </summary>
public record QuizResultDto(
int LessonId,
int TotalQuestions,
int CorrectAnswers,
double ScorePercentage,
bool Passed,
TimeSpan TimeTaken,
IReadOnlyList<QuizQuestionResultDto> QuestionResults);
/// <summary>
/// Data Transfer Object for individual question result.
/// </summary>
public record QuizQuestionResultDto(
int QuizQuestionId,
string QuestionText,
QuestionType Type,
bool IsCorrect,
string? CorrectAnswer,
string? UserAnswer);
/// <summary>
/// Extension methods for mapping between QuizQuestion entity and DTOs.
/// </summary>
public static class QuizQuestionDtoExtensions
{
public static QuizQuestionDto ToDto(this QuizQuestion quizQuestion) => new(
quizQuestion.Id,
quizQuestion.LessonId,
quizQuestion.Lesson?.Title ?? "Unknown",
quizQuestion.QuestionText,
quizQuestion.Type,
quizQuestion.CorrectAnswer,
quizQuestion.Difficulty,
quizQuestion.Order,
quizQuestion.IsActive,
quizQuestion.CreatedAt,
quizQuestion.UpdatedAt,
quizQuestion.Options?.OrderBy(o => o.Order).Select(o => o.ToDto()).ToList() ?? new List<QuizOptionDto>());
public static QuizQuestion ToEntity(this CreateQuizQuestionDto dto) =>
QuizQuestion.Create(
dto.LessonId,
dto.QuestionText,
dto.Type,
dto.CorrectAnswer ?? string.Empty,
dto.Difficulty,
dto.Order);
public static void UpdateFromDto(this QuizQuestion quizQuestion, UpdateQuizQuestionDto dto)
{
quizQuestion.UpdateLesson(dto.LessonId);
quizQuestion.UpdateQuestionText(dto.QuestionText);
quizQuestion.UpdateType(dto.Type);
quizQuestion.UpdateCorrectAnswer(dto.CorrectAnswer ?? string.Empty);
quizQuestion.UpdateDifficulty(dto.Difficulty);
quizQuestion.UpdateOrder(dto.Order);
if (dto.IsActive != quizQuestion.IsActive)
{
if (dto.IsActive)
quizQuestion.Activate();
else
quizQuestion.Deactivate();
}
}
public static QuizOptionDto ToDto(this QuizOption quizOption) => new(
quizOption.Id,
quizOption.QuizQuestionId,
quizOption.Text,
quizOption.IsCorrect,
quizOption.Order);
public static QuizOption ToEntity(this CreateQuizOptionDto dto, int quizQuestionId) =>
QuizOption.Create(
quizQuestionId,
dto.Text,
dto.IsCorrect,
dto.Order);
public static void UpdateFromDto(this QuizOption quizOption, UpdateQuizOptionDto dto)
{
quizOption.UpdateText(dto.Text);
quizOption.UpdateIsCorrect(dto.IsCorrect);
quizOption.UpdateOrder(dto.Order);
}
}