8ac593d36f
Backend CI / build-and-test (push) Failing after 14m19s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Failing after 12m5s
Frontend CI / build-and-check (push) Failing after 17m58s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Failing after 10m11s
🚀 Create and publish a Docker image / Build & publish backend image (push) Failing after 11m3s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Failing after 14m58s
127 lines
5.1 KiB
C#
127 lines
5.1 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using UniVerse.Application.DTOs.Common;
|
|
using UniVerse.Application.DTOs.Reviews;
|
|
using UniVerse.Application.Interfaces;
|
|
using UniVerse.Application.Mappings;
|
|
using UniVerse.Domain.Entities;
|
|
using UniVerse.Domain.Enums;
|
|
using UniVerse.Domain.Exceptions;
|
|
using UniVerse.Infrastructure.Data;
|
|
|
|
namespace UniVerse.Infrastructure.Services;
|
|
|
|
public class ReviewService : IReviewService
|
|
{
|
|
private readonly AppDbContext _db;
|
|
private readonly IGamificationService _gamification;
|
|
private readonly IReviewAnalysisQueue _reviewAnalysisQueue;
|
|
|
|
public ReviewService(
|
|
AppDbContext db,
|
|
IGamificationService gamification,
|
|
IReviewAnalysisQueue reviewAnalysisQueue)
|
|
{
|
|
_db = db;
|
|
_gamification = gamification;
|
|
_reviewAnalysisQueue = reviewAnalysisQueue;
|
|
}
|
|
|
|
private IQueryable<Review> BaseQuery() => _db.Reviews
|
|
.Include(r => r.Lecture).Include(r => r.User);
|
|
|
|
public async Task<ReviewDto> CreateAsync(int userId, CreateReviewRequest req)
|
|
{
|
|
_ = await _db.Lectures.FindAsync(req.LectureId) ?? throw new NotFoundException("Lecture", req.LectureId);
|
|
if (await _db.Reviews.AnyAsync(r => r.LectureId == req.LectureId && r.UserId == userId))
|
|
throw new ConflictException("You already reviewed this lecture.");
|
|
var review = new Review
|
|
{
|
|
LectureId = req.LectureId, UserId = userId,
|
|
Rating = req.Rating, Text = req.Text,
|
|
LlmStatus = ReviewLlmStatus.Pending
|
|
};
|
|
_db.Reviews.Add(review);
|
|
await _db.SaveChangesAsync();
|
|
await _gamification.CheckAndAwardAchievementsAsync(userId);
|
|
await _reviewAnalysisQueue.EnqueueAsync(review.Id);
|
|
var full = await BaseQuery().FirstAsync(r => r.Id == review.Id);
|
|
return full.ToDto();
|
|
}
|
|
|
|
public async Task<ReviewDto> GetByIdAsync(int id)
|
|
{
|
|
var review = await BaseQuery().FirstOrDefaultAsync(r => r.Id == id)
|
|
?? throw new NotFoundException("Review", id);
|
|
return review.ToDto();
|
|
}
|
|
|
|
public async Task<ReviewDto> UpdateAsync(int id, int userId, UpdateReviewRequest req)
|
|
{
|
|
var review = await _db.Reviews.FindAsync(id) ?? throw new NotFoundException("Review", id);
|
|
if (review.UserId != userId) throw new ForbiddenException();
|
|
review.Rating = req.Rating; review.Text = req.Text;
|
|
ResetLlmAnalysis(review);
|
|
review.UpdatedAt = DateTime.UtcNow;
|
|
await _db.SaveChangesAsync();
|
|
await _reviewAnalysisQueue.EnqueueAsync(review.Id);
|
|
return await GetByIdAsync(id);
|
|
}
|
|
|
|
public async Task DeleteAsync(int id, int userId, bool isAdmin = false)
|
|
{
|
|
var review = await _db.Reviews.FindAsync(id) ?? throw new NotFoundException("Review", id);
|
|
if (review.UserId != userId && !isAdmin) throw new ForbiddenException();
|
|
_db.Reviews.Remove(review);
|
|
await _db.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task<PagedResult<ReviewDto>> GetByLectureAsync(int lectureId, PaginationRequest pagination)
|
|
{
|
|
var query = BaseQuery().Where(r => r.LectureId == lectureId);
|
|
var total = await query.CountAsync();
|
|
var items = await query.OrderByDescending(r => r.CreatedAt)
|
|
.Skip((pagination.Page - 1) * pagination.PageSize).Take(pagination.PageSize).ToListAsync();
|
|
return PagedResult<ReviewDto>.Create(items.Select(r => r.ToDto()).ToList(), total, pagination.Page, pagination.PageSize);
|
|
}
|
|
|
|
public async Task<PagedResult<ReviewDto>> GetByUserAsync(int userId, PaginationRequest pagination)
|
|
{
|
|
var query = BaseQuery().Where(r => r.UserId == userId);
|
|
var total = await query.CountAsync();
|
|
var items = await query.OrderByDescending(r => r.CreatedAt)
|
|
.Skip((pagination.Page - 1) * pagination.PageSize).Take(pagination.PageSize).ToListAsync();
|
|
return PagedResult<ReviewDto>.Create(items.Select(r => r.ToDto()).ToList(), total, pagination.Page, pagination.PageSize);
|
|
}
|
|
|
|
public async Task<PagedResult<ReviewDto>> GetAllAsync(ReviewFilterRequest filter)
|
|
{
|
|
var query = BaseQuery();
|
|
if (filter.LlmStatus.HasValue)
|
|
query = query.Where(r => r.LlmStatus == filter.LlmStatus.Value);
|
|
|
|
var total = await query.CountAsync();
|
|
var items = await query.OrderByDescending(r => r.CreatedAt)
|
|
.Skip((filter.Page - 1) * filter.PageSize).Take(filter.PageSize).ToListAsync();
|
|
return PagedResult<ReviewDto>.Create(items.Select(r => r.ToDto()).ToList(), total, filter.Page, filter.PageSize);
|
|
}
|
|
|
|
public async Task ReanalyzeAsync(int id)
|
|
{
|
|
var review = await _db.Reviews.FindAsync(id) ?? throw new NotFoundException("Review", id);
|
|
ResetLlmAnalysis(review);
|
|
review.UpdatedAt = DateTime.UtcNow;
|
|
await _db.SaveChangesAsync();
|
|
await _reviewAnalysisQueue.EnqueueAsync(review.Id);
|
|
}
|
|
|
|
private static void ResetLlmAnalysis(Review review)
|
|
{
|
|
review.LlmStatus = ReviewLlmStatus.Pending;
|
|
review.Sentiment = null;
|
|
review.QualityScore = null;
|
|
review.IsInformative = null;
|
|
review.LlmTags = null;
|
|
review.LlmRawOutput = null;
|
|
}
|
|
}
|