- Created LevelDto.cs with LevelDto, CreateLevelDto, UpdateLevelDto - Created UserProgressDto.cs with UserProgressDto, UpdateUserProgressDto, LevelCompletionDto - Created LevelService.cs with CRUD operations for CEFR levels - Created LessonService.cs with CRUD operations and filtering by level - Created ProgressService.cs with user progress tracking, completion percentage, and lesson unlocking logic - Registered all new services in Program.cs - Fixed UserProgressDto ToEntity/UpdateFromDto to use domain entity methods Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
159 lines
5.9 KiB
C#
159 lines
5.9 KiB
C#
using GermanApp.Application.DTOs;
|
|
using GermanApp.Domain.Entities;
|
|
using GermanApp.Domain.Interfaces;
|
|
|
|
namespace GermanApp.Application.Services;
|
|
|
|
/// <summary>
|
|
/// Application service for managing lessons.
|
|
/// This is part of the Application layer.
|
|
/// </summary>
|
|
public class LessonService
|
|
{
|
|
private readonly ILessonRepository _lessonRepository;
|
|
private readonly ILevelRepository _levelRepository;
|
|
|
|
public LessonService(ILessonRepository lessonRepository, ILevelRepository levelRepository)
|
|
{
|
|
_lessonRepository = lessonRepository;
|
|
_levelRepository = levelRepository;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all lessons.
|
|
/// </summary>
|
|
public async Task<IReadOnlyList<LessonDto>> GetAllLessonsAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
var lessons = await _lessonRepository.GetAllAsync(cancellationToken);
|
|
return lessons.Select(l => l.ToDto()).ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all lessons ordered by level and lesson order.
|
|
/// </summary>
|
|
public async Task<IReadOnlyList<LessonDto>> GetAllOrderedLessonsAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
var lessons = await _lessonRepository.GetAllOrderedAsync(cancellationToken);
|
|
return lessons.Select(l => l.ToDto()).ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a lesson by its ID.
|
|
/// </summary>
|
|
public async Task<LessonDto?> GetLessonByIdAsync(int id, CancellationToken cancellationToken = default)
|
|
{
|
|
var lesson = await _lessonRepository.GetByIdAsync(id, cancellationToken);
|
|
return lesson?.ToDto();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets lessons by level ID.
|
|
/// </summary>
|
|
public async Task<IReadOnlyList<LessonDto>> GetLessonsByLevelAsync(int levelId, CancellationToken cancellationToken = default)
|
|
{
|
|
var lessons = await _lessonRepository.GetByLevelAsync(levelId, cancellationToken);
|
|
return lessons.Select(l => l.ToDto()).ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets beginner lessons (A1 and A2 - levels 1 and 2).
|
|
/// </summary>
|
|
public async Task<IReadOnlyList<LessonDto>> GetBeginnerLessonsAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
var level1Lessons = await _lessonRepository.GetByLevelAsync(1, cancellationToken);
|
|
var level2Lessons = await _lessonRepository.GetByLevelAsync(2, cancellationToken);
|
|
var allLessons = level1Lessons.Concat(level2Lessons)
|
|
.OrderBy(l => l.LevelId)
|
|
.ThenBy(l => l.Order)
|
|
.ToList();
|
|
return allLessons.Select(l => l.ToDto()).ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets advanced lessons (B2 and C1 - levels 4 and 5).
|
|
/// </summary>
|
|
public async Task<IReadOnlyList<LessonDto>> GetAdvancedLessonsAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
var level4Lessons = await _lessonRepository.GetByLevelAsync(4, cancellationToken);
|
|
var level5Lessons = await _lessonRepository.GetByLevelAsync(5, cancellationToken);
|
|
var allLessons = level4Lessons.Concat(level5Lessons)
|
|
.OrderBy(l => l.LevelId)
|
|
.ThenBy(l => l.Order)
|
|
.ToList();
|
|
return allLessons.Select(l => l.ToDto()).ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new lesson.
|
|
/// </summary>
|
|
public async Task<LessonDto> CreateLessonAsync(CreateLessonDto dto, CancellationToken cancellationToken = default)
|
|
{
|
|
// Validate that the level exists
|
|
var level = await _levelRepository.GetByIdAsync(dto.LevelId, cancellationToken);
|
|
if (level == null)
|
|
throw new ArgumentException("Level does not exist");
|
|
|
|
var lesson = dto.ToEntity();
|
|
var createdLesson = await _lessonRepository.AddAsync(lesson, cancellationToken);
|
|
return createdLesson.ToDto();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates an existing lesson.
|
|
/// </summary>
|
|
public async Task<LessonDto?> UpdateLessonAsync(int id, UpdateLessonDto dto, CancellationToken cancellationToken = default)
|
|
{
|
|
var lesson = await _lessonRepository.GetByIdAsync(id, cancellationToken);
|
|
if (lesson == null)
|
|
return null;
|
|
|
|
// Validate that the level exists
|
|
var level = await _levelRepository.GetByIdAsync(dto.LevelId, cancellationToken);
|
|
if (level == null)
|
|
throw new ArgumentException("Level does not exist");
|
|
|
|
lesson.UpdateFromDto(dto);
|
|
await _lessonRepository.UpdateAsync(lesson, cancellationToken);
|
|
return lesson.ToDto();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes a lesson by its ID.
|
|
/// </summary>
|
|
public async Task<bool> DeleteLessonAsync(int id, CancellationToken cancellationToken = default)
|
|
{
|
|
var lesson = await _lessonRepository.GetByIdAsync(id, cancellationToken);
|
|
if (lesson == null)
|
|
return false;
|
|
|
|
await _lessonRepository.DeleteAsync(lesson, cancellationToken);
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the first lesson in a level.
|
|
/// </summary>
|
|
public async Task<LessonDto?> GetFirstLessonInLevelAsync(int levelId, CancellationToken cancellationToken = default)
|
|
{
|
|
var lesson = await _lessonRepository.GetFirstLessonInLevelAsync(levelId, cancellationToken);
|
|
return lesson?.ToDto();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the next lesson after the specified one.
|
|
/// </summary>
|
|
public async Task<LessonDto?> GetNextLessonAsync(int currentLessonId, CancellationToken cancellationToken = default)
|
|
{
|
|
var lesson = await _lessonRepository.GetNextLessonAsync(currentLessonId, cancellationToken);
|
|
return lesson?.ToDto();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets lessons that the user can access (based on completion of previous lessons).
|
|
/// </summary>
|
|
public async Task<IReadOnlyList<LessonDto>> GetAccessibleLessonsAsync(int userId, CancellationToken cancellationToken = default)
|
|
{
|
|
var lessons = await _lessonRepository.GetAccessibleLessonsAsync(userId, cancellationToken);
|
|
return lessons.Select(l => l.ToDto()).ToList();
|
|
}
|
|
}
|