using System.Dynamic; using AutoMapper; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Server.Data; using Server.Helpers; using Server.Models; using SharedModels.DataTransferObjects.Model; using SharedModels.QueryParameters; using SharedModels.QueryParameters.Objects; using Utils; namespace Server.Services; public class ReviewManagementService : IReviewManagementService { private readonly ApplicationDbContext _dbContext; private readonly IMapper _mapper; private readonly ISortHelper _reviewSortHelper; private readonly IDataShaper _reviewDataShaper; private readonly IPager _pager; private readonly ISessionUserService _sessionUserService; public ReviewManagementService(ApplicationDbContext dbContext, IMapper mapper, ISortHelper reviewSortHelper, IDataShaper reviewDataShaper, IPager pager, ISessionUserService sessionUserService) { _dbContext = dbContext; _mapper = mapper; _reviewSortHelper = reviewSortHelper; _reviewDataShaper = reviewDataShaper; _pager = pager; _sessionUserService = sessionUserService; } public async Task<(bool isSucceed, IActionResult? actionResult, ReviewDto review)> AddReview(CreateReviewDto createReviewDto) { var review = _mapper.Map(createReviewDto); var hasTicketToEnrollment = await _dbContext.TicketGroups.AnyAsync(tg => tg.UserId == _sessionUserService.GetAuthUserId() && tg.Tickets.Any(t => t.VehicleEnrollmentId == review.VehicleEnrollmentId)); if (!hasTicketToEnrollment && _sessionUserService.GetAuthUserRole() != Identity.Roles.Administrator.ToString()) { return (false, new UnauthorizedResult(), null!); } await _dbContext.Reviews.AddAsync(review); await _dbContext.SaveChangesAsync(); return (true, null, _mapper.Map(review)); } public async Task<(bool isSucceed, IActionResult? actionResult, IEnumerable reviews, PagingMetadata pagingMetadata)> GetReviews(ReviewParameters parameters) { var dbReviews = _dbContext.Reviews .Include(r => r.VehicleEnrollment).ThenInclude(ve => ve.Vehicle) .ThenInclude(v => v.Company).Include(r => r.User) .AsQueryable(); if (_sessionUserService.GetAuthUserRole() != Identity.Roles.Administrator.ToString()) { dbReviews = dbReviews.Where(r => r.UserId == _sessionUserService.GetAuthUserId()); } if (!dbReviews.Any()) { return (false, new NotFoundResult(), null!, null!); } FilterByReviewRating(ref dbReviews, parameters.FromRating, parameters.ToRating); FilterByReviewComment(ref dbReviews, parameters.Comment); FilterByReviewUserId(ref dbReviews, parameters.UserId); FilterByReviewCompanyId(ref dbReviews, parameters.CompanyId); var reviewDtos = _mapper.ProjectTo(dbReviews); var shapedData = _reviewDataShaper.ShapeData(reviewDtos, parameters.Fields).AsQueryable(); try { shapedData = _reviewSortHelper.ApplySort(shapedData, parameters.Sort); } catch (Exception e) { return (false, new BadRequestObjectResult("Invalid sorting string"), null!, null!); } var pagingMetadata = _pager.ApplyPaging(ref shapedData, parameters.PageNumber, parameters.PageSize); return (true, null, shapedData, pagingMetadata); void FilterByReviewRating(ref IQueryable reviews, int? fromRating, int? toRating) { if (!reviews.Any() || !fromRating.HasValue && !toRating.HasValue) { return; } reviews = reviews.Where(r => r.Rating >= fromRating && r.Rating <= toRating); } void FilterByReviewComment(ref IQueryable reviews, string? comment) { if (!reviews.Any() || String.IsNullOrWhiteSpace(comment)) { return; } reviews = reviews.Where(r => r.Comment != null && r.Comment.ToLower().Contains(comment.ToLower())); } void FilterByReviewUserId(ref IQueryable reviews, string? userId) { if (!reviews.Any() || String.IsNullOrWhiteSpace(userId)) { return; } reviews = reviews.Where(r => r.UserId.Contains(userId.ToLower())); } void FilterByReviewCompanyId(ref IQueryable reviews, int? companyId) { if (!reviews.Any() || companyId == null) { return; } reviews = reviews.Where(r => r.VehicleEnrollment.Vehicle.CompanyId == companyId); } } public async Task<(bool isSucceed, IActionResult? actionResult, ExpandoObject review)> GetReview(int id, string? fields) { if (!await IsReviewExists(id)) { return (false, new NotFoundResult(), null!); } var dbReview = await _dbContext.Reviews.Where(r => r.Id == id) .Include(r => r.VehicleEnrollment).ThenInclude(ve => ve.Vehicle) .ThenInclude(v => v.Company).Include(r => r.User) .FirstAsync(); if (_sessionUserService.GetAuthUserRole() != Identity.Roles.Administrator.ToString() && dbReview.UserId != _sessionUserService.GetAuthUserId()) { return (false, new UnauthorizedResult(), null!); } if (String.IsNullOrWhiteSpace(fields)) { fields = ReviewParameters.DefaultFields; } var reviewDto = _mapper.Map(dbReview); var shapedData = _reviewDataShaper.ShapeData(reviewDto, fields); return (true, null, shapedData); } public async Task<(bool isSucceed, IActionResult? actionResult, ReviewDto review)> UpdateReview(UpdateReviewDto updateReviewDto) { var review = _mapper.Map(updateReviewDto); _dbContext.Entry(review).State = EntityState.Modified; if (!await _sessionUserService.IsAuthUserReview(updateReviewDto.Id) && _sessionUserService.GetAuthUserRole() != Identity.Roles.Administrator.ToString()) { return (false, new UnauthorizedResult(), null!); } try { await _dbContext.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!await IsReviewExists(updateReviewDto.Id)) { return (false, new NotFoundResult(), null!); } } var dbReview = await _dbContext.Reviews.FirstAsync(r => r.Id == review.Id); return (true, null, _mapper.Map(dbReview)); } public async Task<(bool isSucceed, IActionResult? actionResult)> DeleteReview(int id) { if (!await IsReviewExists(id)) { return (false, new NotFoundResult()); } if (!await _sessionUserService.IsAuthUserReview(id)) { return (false, new UnauthorizedResult()); } var dbReview = await _dbContext.Reviews.FirstAsync(r => r.Id == id); _dbContext.Reviews.Remove(dbReview); await _dbContext.SaveChangesAsync(); return (true, null); } public async Task IsReviewExists(int id) { return await _dbContext.Reviews.AnyAsync(r => r.Id == id); } }