using Api.Database; using Api.Database.Entities; using Api.Extensions; using Api.Mapping; using Api.Services.Interfaces; using Common.Dtos.Common; using Common.Dtos.Subject; using Common.Extensions; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Distributed; namespace Api.Services.Implementation; public class SubjectService(SanStudentContext context, IDistributedCache cache) : ISubjectService, IServiceHelper { private readonly SanStudentContext _context = context; private readonly IDistributedCache _cache = cache; private List _cacheKeys = []; public async Task CreateAsync(CreateSubjectRequest request) { try { var problems = await Validate(request); if (problems.Errors.Count > 0) { return new CreateSubjectResponse { Ok = false, CreateSubjectResult = string.Join(", ", problems.Errors) }; } var subject = new Subject() { Name = request.Name!.Trim(), ShortName = request.ShortName!.Trim() }; _context.Subjects.Add(subject); await _context.SaveChangesAsync(); await RemoveCache(); return new CreateSubjectResponse { Ok = true, CreateSubjectResult = $"Zapisano nowy przedmiot \"{subject.Name}\"", }; } catch (Exception error) { return new CreateSubjectResponse { Ok = false, CreateSubjectResult = $"Błąd podczas próby zapisu przedmiotu: {error.Message}", }; } } public async Task GetAllAsync() { var key = "subjects"; AddKeyToCache(key); var cachedSubjects = await _cache.GetStringAsync(key); if (!string.IsNullOrEmpty(cachedSubjects)) return cachedSubjects.FromJson(); var query = _context.Subjects as IQueryable; var result = await query .OrderBy(s => s.Name) .ThenBy(s => s.ShortName) .Select(s => s.ToSubjectDto()).ToArrayAsync(); await _cache.SetWithExpirationTimeAsync(key, result, 262487); return result; } public async Task> GetAllPagedAsync(GetSubjectsRequest request) { var key = $"subjects_{request.PageNumber}_{request.PageSize}"; if (!string.IsNullOrWhiteSpace(request.Name)) key += $"_{request.Name.ToLower()}"; AddKeyToCache(key); var cachedSubjects = await _cache.GetStringAsync(key); if (!string.IsNullOrEmpty(cachedSubjects)) return cachedSubjects.FromJson>(); var query = _context.Subjects as IQueryable; if (!string.IsNullOrEmpty(request.Name)) query = query.Where(s => s.Name.ToLower().StartsWith(request.Name.ToLower())); var data = query .OrderBy(s => s.Name) .ThenBy(s => s.ShortName) .Select(s => s.ToSubjectDto()); var result = await data.ToPagedListAsync(request.PageNumber, request.PageSize); await _cache.SetWithExpirationTimeAsync(key, result, 262487); return result; } public async Task Validate(CreateSubjectRequest request) { var problems = new ValidationProblems(); if (string.IsNullOrWhiteSpace(request.Name)) problems.Errors.Add("Brak nazwy przedmiotu"); if (string.IsNullOrWhiteSpace(request.ShortName)) problems.Errors.Add("Brak nazwy skróconej przedmiotu"); if (problems.Errors.Count > 0) return problems; var subject = await _context.Subjects .FirstOrDefaultAsync(s => s.Name.ToLower() == request.Name!.ToLower()); if (subject is not null) problems.Errors.Add("Przedmiot o podanej nazwie już istnieje"); subject = await _context.Subjects .FirstOrDefaultAsync(s => s.ShortName.ToLower() == request.ShortName!.ToLower()); if (subject is not null) problems.Errors.Add("Przedmiot o podanej nazwie skróconej już istnieje"); return problems; } public void AddKeyToCache(string key) { if (!_cacheKeys.Contains(key)) _cacheKeys.Add(key); } public async Task RemoveCache() { foreach (var cacheKey in _cacheKeys) await _cache.RemoveAsync(cacheKey); } }