From 644de2d8182a4800ee7ecdf44799ccd05591f1f8 Mon Sep 17 00:00:00 2001 From: Anu Viswan Date: Sat, 19 Jul 2025 12:53:45 +0530 Subject: [PATCH 1/4] basic skeleton for review controller --- .../Operations/IReviewService.cs | 1 + .../Queries/GetRecentReviewsForUsersQuery.cs | 10 +++++ .../GetRecentReviewsForUsersQueryHandler.cs | 19 ++++++++++ .../Operations/ReviewService.cs | 18 +++++++++ .../Repositories/IReviewRepository.cs | 1 + .../Repositories/ReviewRepository.cs | 32 ++++++++++++++++ .../Controllers/UserReviewsController.cs | 38 +++++++++++++++++++ .../Models/CreateReviewRequest.cs | 23 ++++++++++- 8 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 server/nt.microservice/services/ReviewService/ReviewService.Application.Orchestration/Queries/GetRecentReviewsForUsersQuery.cs create mode 100644 server/nt.microservice/services/ReviewService/ReviewService.Application.Orchestration/Queries/GetRecentReviewsForUsersQueryHandler.cs create mode 100644 server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Application.Interfaces/Operations/IReviewService.cs b/server/nt.microservice/services/ReviewService/ReviewService.Application.Interfaces/Operations/IReviewService.cs index 7ff857d6..067fcdee 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Application.Interfaces/Operations/IReviewService.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Application.Interfaces/Operations/IReviewService.cs @@ -4,6 +4,7 @@ namespace ReviewService.Application.Interfaces.Operations; public interface IReviewService { + Task> GetRecentReviewsForUsersAsync(IEnumerable userIds, int count = 3); Task> GetReviewsByMovieIdAsync(Guid movieId); Task CreateReviewAsync(ReviewDto reviewDto); } diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Application.Orchestration/Queries/GetRecentReviewsForUsersQuery.cs b/server/nt.microservice/services/ReviewService/ReviewService.Application.Orchestration/Queries/GetRecentReviewsForUsersQuery.cs new file mode 100644 index 00000000..ea9b6c04 --- /dev/null +++ b/server/nt.microservice/services/ReviewService/ReviewService.Application.Orchestration/Queries/GetRecentReviewsForUsersQuery.cs @@ -0,0 +1,10 @@ +using MediatR; +using ReviewService.Application.DTO.Reviews; + +namespace ReviewService.Application.Orchestration.Queries; + +public class GetRecentReviewsForUsersQuery : IRequest> +{ + public IEnumerable UserIds { get; set; } = []; + public int Count { get; set; } +} \ No newline at end of file diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Application.Orchestration/Queries/GetRecentReviewsForUsersQueryHandler.cs b/server/nt.microservice/services/ReviewService/ReviewService.Application.Orchestration/Queries/GetRecentReviewsForUsersQueryHandler.cs new file mode 100644 index 00000000..ea3d2b34 --- /dev/null +++ b/server/nt.microservice/services/ReviewService/ReviewService.Application.Orchestration/Queries/GetRecentReviewsForUsersQueryHandler.cs @@ -0,0 +1,19 @@ +using MediatR; +using ReviewService.Application.DTO.Reviews; +using ReviewService.Application.Interfaces.Operations; + +namespace ReviewService.Application.Orchestration.Queries +{ + public class GetRecentReviewsForUsersQueryHandler : IRequestHandler> + { + private readonly IReviewService _reviewService; + public GetRecentReviewsForUsersQueryHandler(IReviewService reviewService) + { + _reviewService = reviewService; + } + public async Task> Handle(GetRecentReviewsForUsersQuery request, CancellationToken cancellationToken) + { + return await _reviewService.GetRecentReviewsForUsersAsync(request.UserIds, request.Count).ConfigureAwait(false); ; + } + } +} diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Application.Services/Operations/ReviewService.cs b/server/nt.microservice/services/ReviewService/ReviewService.Application.Services/Operations/ReviewService.cs index 49c51e9d..91f7b661 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Application.Services/Operations/ReviewService.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Application.Services/Operations/ReviewService.cs @@ -36,4 +36,22 @@ public async Task CreateReviewAsync(ReviewDto reviewDto) throw; } } + + public Task> GetRecentReviewsForUsersAsync(IEnumerable userIds, int count = 3) + { + try + { + // Fetch User Details + + // Fetch reviews from the repository + + // Fetch Movie details from the repository' + throw new NotImplementedException(); + } + catch (Exception) + { + + throw; + } + } } diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Domain/Repositories/IReviewRepository.cs b/server/nt.microservice/services/ReviewService/ReviewService.Domain/Repositories/IReviewRepository.cs index 0aac5f82..b4be932f 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Domain/Repositories/IReviewRepository.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Domain/Repositories/IReviewRepository.cs @@ -8,4 +8,5 @@ public interface IReviewRepository : IGenericRepository Task> GetReviewsByUserIdAsync(Guid userId); Task> GetReviewsByRatingAsync(int rating); Task> GetReviewsByDateRangeAsync(DateTime startDate, DateTime endDate); + Task> GetRecentReviewsForUsersAsync(IEnumerable userIds, int count = 3); } \ No newline at end of file diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs new file mode 100644 index 00000000..a5ea37b2 --- /dev/null +++ b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs @@ -0,0 +1,32 @@ +using ReviewService.Domain.Entities; +using ReviewService.Domain.Repositories; + +namespace ReviewService.Infrastructure.Repository.Repositories; + +public class ReviewRepository : GenericRepository, IReviewRepository +{ + public Task> GetRecentReviewsForUsersAsync(IEnumerable userIds, int count = 3) + { + throw new NotImplementedException(); + } + + public Task> GetReviewsByDateRangeAsync(DateTime startDate, DateTime endDate) + { + throw new NotImplementedException(); + } + + public Task> GetReviewsByMovieIdAsync(Guid movieId) + { + throw new NotImplementedException(); + } + + public Task> GetReviewsByRatingAsync(int rating) + { + throw new NotImplementedException(); + } + + public Task> GetReviewsByUserIdAsync(Guid userId) + { + throw new NotImplementedException(); + } +} diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Controllers/UserReviewsController.cs b/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Controllers/UserReviewsController.cs index 30abe7cc..405ef800 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Controllers/UserReviewsController.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Controllers/UserReviewsController.cs @@ -2,6 +2,7 @@ using MediatR; using Microsoft.AspNetCore.Mvc; using ReviewService.Application.Orchestration.Commands; +using ReviewService.Application.Orchestration.Queries; using ReviewService.Presenation.Api.Models; namespace ReviewService.Api.Controllers; @@ -28,6 +29,43 @@ public ActionResult GetReviewsForMovie(Guid movieId) return default!; } + + public async Task GetRecentReviewsForUsers(GetRecentReviewsForUsersRequest request) + { + try + { + if (request.UserIds == null || !request.UserIds.Any()) + { + _logger.LogWarning("No user IDs provided for fetching recent reviews."); + return new GetRecentReviewsForUsersResponse(); + } + var reviews = await _mediator.Send(new GetRecentReviewsForUsersQuery + { + UserIds = request.UserIds, + Count = request.Count + }).ConfigureAwait(false); + return new GetRecentReviewsForUsersResponse + { + Reviews = reviews.Select(r => new GetRcentReviewsForUserReviewItem + { + ReviewId = r.Id, + MovieId = r.MovieId, + MovieTitle = r.MovieTitle, + Content = r.Content, + Rating = r.Rating, + UserName = r.UserName, + UserDisplayName = r.UserDisplayName + }).ToList() + }; + } + catch (Exception e) + { + _logger.LogError(e, "An error occurred while fetching recent reviews for users."); + throw; // Consider handling this more gracefully in production code. + } + } + + [HttpPost] [Route("CreateReview")] public async Task> CreateReview(CreateReviewRequest request) diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Models/CreateReviewRequest.cs b/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Models/CreateReviewRequest.cs index f08df856..4aeb03fc 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Models/CreateReviewRequest.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Models/CreateReviewRequest.cs @@ -1,9 +1,28 @@ namespace ReviewService.Presenation.Api.Models; -public class CreateReviewRequest +public record CreateReviewRequest { public Guid MovieId { get; set; } public string Content { get; set; } = string.Empty; public int Rating { get; set; } public string UserName { get; set; } = string.Empty; -} \ No newline at end of file +} + +public record GetRecentReviewsForUsersRequest(IEnumerable UserIds, int Count = 3); + +public record GetRecentReviewsForUsersResponse +{ + public IEnumerable Reviews { get; init; } = []; +}; + + +public record GetRcentReviewsForUserReviewItem +{ + public Guid ReviewId { get; init; } + public Guid MovieId { get; init; } + public string MovieTitle { get; init; } = string.Empty; + public string Content { get; init; } = string.Empty; + public int Rating { get; init; } + public string UserName { get; init; } = string.Empty; + public string UserDisplayName { get; set; } = string.Empty; +} From 632a22ce056f64f9ccef204085e746ae0566c66c Mon Sep 17 00:00:00 2001 From: Anu Viswan Date: Sat, 19 Jul 2025 21:35:11 +0530 Subject: [PATCH 2/4] working on review repository --- .../CreateUserInitiatedConsumer.cs | 2 +- .../Reviews/ReviewDto.cs | 2 +- .../Operations/ReviewService.cs | 10 ++--- .../Repositories/IGenericRepository.cs | 2 +- .../Repositories/GenericRepository.cs | 40 ++++++++++++++----- .../Repositories/ReviewRepository.cs | 9 ++++- .../Controllers/UserReviewsController.cs | 2 - 7 files changed, 42 insertions(+), 25 deletions(-) diff --git a/server/nt.microservice/services/AuthService/AuthService.Api/ConsumerServices/CreateUserInitiatedConsumer.cs b/server/nt.microservice/services/AuthService/AuthService.Api/ConsumerServices/CreateUserInitiatedConsumer.cs index 5fe0a90d..9889fec8 100644 --- a/server/nt.microservice/services/AuthService/AuthService.Api/ConsumerServices/CreateUserInitiatedConsumer.cs +++ b/server/nt.microservice/services/AuthService/AuthService.Api/ConsumerServices/CreateUserInitiatedConsumer.cs @@ -46,7 +46,7 @@ await _publishEndPoint.Publish(new () } } -public class CreateUserInitiatedConsumerDefinition: ConsumerDefinition +public class CreateUserInitiatedConsumerDefinition : ConsumerDefinition { public CreateUserInitiatedConsumerDefinition() { diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Application.DTO/Reviews/ReviewDto.cs b/server/nt.microservice/services/ReviewService/ReviewService.Application.DTO/Reviews/ReviewDto.cs index 3a3b36bd..8f5c2e43 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Application.DTO/Reviews/ReviewDto.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Application.DTO/Reviews/ReviewDto.cs @@ -2,7 +2,7 @@ public class ReviewDto { - public Guid ReviewId { get; set; } + public Guid Id { get; set; } public Guid MovieId { get; set; } public string Content { get; set; } = string.Empty; diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Application.Services/Operations/ReviewService.cs b/server/nt.microservice/services/ReviewService/ReviewService.Application.Services/Operations/ReviewService.cs index 91f7b661..f6e5af83 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Application.Services/Operations/ReviewService.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Application.Services/Operations/ReviewService.cs @@ -37,16 +37,12 @@ public async Task CreateReviewAsync(ReviewDto reviewDto) } } - public Task> GetRecentReviewsForUsersAsync(IEnumerable userIds, int count = 3) + public async Task> GetRecentReviewsForUsersAsync(IEnumerable userIds, int count = 3) { try { - // Fetch User Details - - // Fetch reviews from the repository - - // Fetch Movie details from the repository' - throw new NotImplementedException(); + var results = await _reviewRepository.GetRecentReviewsForUsersAsync(userIds, count); + return _mapper.Map, IEnumerable>(results); } catch (Exception) { diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Domain/Repositories/IGenericRepository.cs b/server/nt.microservice/services/ReviewService/ReviewService.Domain/Repositories/IGenericRepository.cs index 57d022e1..6313535f 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Domain/Repositories/IGenericRepository.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Domain/Repositories/IGenericRepository.cs @@ -5,7 +5,7 @@ namespace ReviewService.Domain.Repositories; public interface IGenericRepository where TEntity : class, IEntity, new() { Task> GetAll(); - Task GetByIdAsync(long id); + Task GetByIdAsync(Guid id); Task AddAsync(TEntity entity); Task UpdateAsync(TEntity entity); Task DeleteAsync(TEntity entity); diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs index 0dab4f8b..7931542f 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs @@ -1,32 +1,50 @@ -using ReviewService.Domain.Entities; +using MongoDB.Driver; +using ReviewService.Domain.Entities; using ReviewService.Domain.Repositories; +using System.Data; namespace ReviewService.Infrastructure.Repository.Repositories; public class GenericRepository : IGenericRepository where TEntity : class, IEntity, new() { - public Task AddAsync(TEntity entity) + private readonly IMongoDatabase _database; + private readonly IMongoCollection _collection; + public GenericRepository(IMongoDatabase database, string collectionNaem) { - throw new NotImplementedException(); + _database = database ?? throw new ArgumentNullException(nameof(database)); + _collection = _database.GetCollection(collectionNaem ?? throw new ArgumentNullException(nameof(collectionNaem))); } - public Task DeleteAsync(TEntity entity) + public async Task> GetAll() { - throw new NotImplementedException(); + return await _collection.Find(Builders.Filter.Empty).ToListAsync(); + + } + + public async Task GetByIdAsync(Guid id) + { + var filter = Builders.Filter.Eq(e => e.Id, id); + var entity = await _collection.Find(filter).FirstOrDefaultAsync(); + return entity ?? throw new KeyNotFoundException($"Entity with ID {id} not found."); } - public Task> GetAll() + public async Task AddAsync(TEntity entity) { - throw new NotImplementedException(); + await _collection.InsertOneAsync(entity).ConfigureAwait(false); + return entity; } - public Task GetByIdAsync(long id) + public async Task UpdateAsync(TEntity entity) { - throw new NotImplementedException(); + var filter = Builders.Filter.Eq(e => e.Id, entity.Id); + await _collection.ReplaceOneAsync(filter,entity).ConfigureAwait(false); + return entity; } - public Task UpdateAsync(TEntity entity) + public async Task DeleteAsync(TEntity entity) { - throw new NotImplementedException(); + var filter = Builders.Filter.Eq(e => e.Id, entity.Id); + await _collection.DeleteOneAsync(filter).ConfigureAwait(false); + return entity; } } diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs index a5ea37b2..07af3156 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs @@ -1,10 +1,15 @@ -using ReviewService.Domain.Entities; +using MongoDB.Driver; +using ReviewService.Domain.Entities; using ReviewService.Domain.Repositories; namespace ReviewService.Infrastructure.Repository.Repositories; public class ReviewRepository : GenericRepository, IReviewRepository { + public ReviewRepository(IMongoDatabase mongoDatabase):base(mongoDatabase, "Reviews") + { + + } public Task> GetRecentReviewsForUsersAsync(IEnumerable userIds, int count = 3) { throw new NotImplementedException(); @@ -15,7 +20,7 @@ public Task> GetReviewsByDateRangeAsync(DateTime startDate, throw new NotImplementedException(); } - public Task> GetReviewsByMovieIdAsync(Guid movieId) + public async Task> GetReviewsByMovieIdAsync(Guid movieId) { throw new NotImplementedException(); } diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Controllers/UserReviewsController.cs b/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Controllers/UserReviewsController.cs index 405ef800..422f131b 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Controllers/UserReviewsController.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Presentation.Api/Controllers/UserReviewsController.cs @@ -50,11 +50,9 @@ public async Task GetRecentReviewsForUsers(Get { ReviewId = r.Id, MovieId = r.MovieId, - MovieTitle = r.MovieTitle, Content = r.Content, Rating = r.Rating, UserName = r.UserName, - UserDisplayName = r.UserDisplayName }).ToList() }; } From 2a328dfc4ef8d5df7ffd9486da233d8bf49bdd38 Mon Sep 17 00:00:00 2001 From: Anu Viswan Date: Sun, 20 Jul 2025 06:18:18 +0530 Subject: [PATCH 3/4] working review repository --- .../ReviewService.Domain/Entities/Review.cs | 1 + .../Repositories/GenericRepository.cs | 1 + .../Repositories/ReviewRepository.cs | 41 +++++++++++++++---- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Domain/Entities/Review.cs b/server/nt.microservice/services/ReviewService/ReviewService.Domain/Entities/Review.cs index 30c3e64f..189c50d2 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Domain/Entities/Review.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Domain/Entities/Review.cs @@ -9,4 +9,5 @@ public class Review : IEntity public DateTime CreatedOn { get; set; } = DateTime.UtcNow; public IEnumerable UpvotedBy { get; set; } = []; public IEnumerable DownvotedBy { get; set; } = []; + public int Rating { get; set; } = 0; } diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs index 7931542f..9f5f9c7e 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs @@ -15,6 +15,7 @@ public GenericRepository(IMongoDatabase database, string collectionNaem) _collection = _database.GetCollection(collectionNaem ?? throw new ArgumentNullException(nameof(collectionNaem))); } + public IMongoCollection Collection => _collection; public async Task> GetAll() { return await _collection.Find(Builders.Filter.Empty).ToListAsync(); diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs index 07af3156..7ddf86df 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs @@ -10,28 +10,51 @@ public ReviewRepository(IMongoDatabase mongoDatabase):base(mongoDatabase, "Revie { } - public Task> GetRecentReviewsForUsersAsync(IEnumerable userIds, int count = 3) + public async Task> GetRecentReviewsForUsersAsync(IEnumerable userIds, int count = 10) { - throw new NotImplementedException(); + var filter = Builders.Filter.In(r => r.Author, userIds.Select(u => u.ToString())); + return (await Collection + .Find(filter) + .SortByDescending(r => r.CreatedOn) + .Limit(count).ToCursorAsync().ConfigureAwait(false)).ToEnumerable(); } - public Task> GetReviewsByDateRangeAsync(DateTime startDate, DateTime endDate) + public async Task> GetReviewsByDateRangeAsync(DateTime startDate, DateTime endDate) { - throw new NotImplementedException(); + var filter = Builders.Filter.And( + Builders.Filter.Gte(r => r.CreatedOn, startDate), + Builders.Filter.Lte(r => r.CreatedOn, endDate) + ); + + return (await Collection + .Find(filter) + .ToCursorAsync() + .ConfigureAwait(false)).ToEnumerable(); } public async Task> GetReviewsByMovieIdAsync(Guid movieId) { - throw new NotImplementedException(); + var filter = Builders.Filter.Eq(r => r.MovieId, movieId.ToString()); + return (await Collection + .Find(filter) + .ToCursorAsync().ConfigureAwait(false)).ToEnumerable(); } - public Task> GetReviewsByRatingAsync(int rating) + public async Task> GetReviewsByRatingAsync(int rating) { - throw new NotImplementedException(); + var filter = Builders.Filter.Eq(r => r.Rating, rating); + return (await Collection + .Find(filter) + .ToCursorAsync() + .ConfigureAwait(false)).ToEnumerable(); } - public Task> GetReviewsByUserIdAsync(Guid userId) + public async Task> GetReviewsByUserIdAsync(Guid userId) { - throw new NotImplementedException(); + var filter = Builders.Filter.Eq(r => r.Author, userId.ToString()); + return (await Collection + .Find(filter) + .ToCursorAsync() + .ConfigureAwait(false)).ToEnumerable(); } } From 89b853d07d32acb974549a5b2ea641b88f802737 Mon Sep 17 00:00:00 2001 From: Anu Viswan Date: Sun, 20 Jul 2025 07:04:12 +0530 Subject: [PATCH 4/4] Use ReviewDocument in Repository --- .../Documents/ReviewDocument.cs | 9 ++- .../Repositories/GenericRepository.cs | 54 ++++++++--------- .../Repositories/ReviewRepository.cs | 59 +++++++++++-------- ...ewService.Infrastructure.Repository.csproj | 1 + .../Seed/MalayalamReviewsSeed.cs | 39 ++++++------ 5 files changed, 89 insertions(+), 73 deletions(-) diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Documents/ReviewDocument.cs b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Documents/ReviewDocument.cs index a0ffa456..0add6001 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Documents/ReviewDocument.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Documents/ReviewDocument.cs @@ -20,7 +20,10 @@ public class ReviewDocument:Entity [Field("rating")] public int Rating { get; set; } - [Field("userName")] - public string UserName { get; set; } = string.Empty; - + [Field("author")] + public string Author { get; set; } = string.Empty; + + [Field("createdOn")] + public DateTime CreatedOn { get; set; } = DateTime.UtcNow; + } diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs index 9f5f9c7e..96d03526 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/GenericRepository.cs @@ -1,51 +1,49 @@ -using MongoDB.Driver; -using ReviewService.Domain.Entities; +using AutoMapper; +using MongoDB.Driver; +using MongoDB.Entities; using ReviewService.Domain.Repositories; -using System.Data; namespace ReviewService.Infrastructure.Repository.Repositories; -public class GenericRepository : IGenericRepository where TEntity : class, IEntity, new() +public class GenericRepository(IMongoDatabase database, IMapper mapper, string collectionName) : IGenericRepository + where TDomain : class, Domain.Entities.IEntity, new() + where TDocument : Entity { - private readonly IMongoDatabase _database; - private readonly IMongoCollection _collection; - public GenericRepository(IMongoDatabase database, string collectionNaem) + protected readonly IMapper Mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + protected IMongoDatabase Database => database ?? throw new ArgumentNullException(nameof(database)); + protected IMongoCollection Collection => database.GetCollection(collectionName ?? throw new ArgumentNullException(nameof(collectionName))); + public async Task> GetAll() { - _database = database ?? throw new ArgumentNullException(nameof(database)); - _collection = _database.GetCollection(collectionNaem ?? throw new ArgumentNullException(nameof(collectionNaem))); + var result = await Collection.Find(Builders.Filter.Empty).ToCursorAsync().ConfigureAwait(false); + return Mapper.Map>(result.ToEnumerable()) ?? throw new InvalidOperationException("No entities found in the collection."); } - public IMongoCollection Collection => _collection; - public async Task> GetAll() + public async Task GetByIdAsync(Guid id) { - return await _collection.Find(Builders.Filter.Empty).ToListAsync(); - - } - - public async Task GetByIdAsync(Guid id) - { - var filter = Builders.Filter.Eq(e => e.Id, id); - var entity = await _collection.Find(filter).FirstOrDefaultAsync(); - return entity ?? throw new KeyNotFoundException($"Entity with ID {id} not found."); + var filter = Builders.Filter.Eq(e => e.ID, id.ToString()); + var entity = await Collection.Find(filter).FirstOrDefaultAsync().ConfigureAwait(false); + return Mapper.Map(entity) ?? throw new KeyNotFoundException($"Entity with ID {id} not found."); } - public async Task AddAsync(TEntity entity) + public async Task AddAsync(TDomain entity) { - await _collection.InsertOneAsync(entity).ConfigureAwait(false); + var entityDocument = Mapper.Map(entity) ?? throw new ArgumentNullException(nameof(entity), "Entity cannot be null."); + await Collection.InsertOneAsync(entityDocument).ConfigureAwait(false); return entity; } - public async Task UpdateAsync(TEntity entity) + public async Task UpdateAsync(TDomain entity) { - var filter = Builders.Filter.Eq(e => e.Id, entity.Id); - await _collection.ReplaceOneAsync(filter,entity).ConfigureAwait(false); + var entityDocument = Mapper.Map(entity) ?? throw new ArgumentNullException(nameof(entity), "Entity cannot be null."); + var filter = Builders.Filter.Eq(e => e.ID, entity.Id.ToString()); + await Collection.ReplaceOneAsync(filter,entityDocument).ConfigureAwait(false); return entity; } - public async Task DeleteAsync(TEntity entity) + public async Task DeleteAsync(TDomain entity) { - var filter = Builders.Filter.Eq(e => e.Id, entity.Id); - await _collection.DeleteOneAsync(filter).ConfigureAwait(false); + var filter = Builders.Filter.Eq(e => e.ID, entity.Id.ToString()); + await Collection.DeleteOneAsync(filter).ConfigureAwait(false); return entity; } } diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs index 7ddf86df..5add2101 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Repositories/ReviewRepository.cs @@ -1,60 +1,73 @@ -using MongoDB.Driver; +using AutoMapper; +using MongoDB.Driver; using ReviewService.Domain.Entities; using ReviewService.Domain.Repositories; +using ReviewService.Infrastructure.Repository.Documents; namespace ReviewService.Infrastructure.Repository.Repositories; -public class ReviewRepository : GenericRepository, IReviewRepository +public class ReviewRepository(IMongoDatabase mongoDatabase,IMapper mapper) : GenericRepository(mongoDatabase,mapper, "Reviews"), IReviewRepository { - public ReviewRepository(IMongoDatabase mongoDatabase):base(mongoDatabase, "Reviews") - { - - } public async Task> GetRecentReviewsForUsersAsync(IEnumerable userIds, int count = 10) { - var filter = Builders.Filter.In(r => r.Author, userIds.Select(u => u.ToString())); - return (await Collection + var filter = Builders.Filter.In(r => r.Author, userIds.Select(u => u.ToString())); + var result = await Collection .Find(filter) .SortByDescending(r => r.CreatedOn) - .Limit(count).ToCursorAsync().ConfigureAwait(false)).ToEnumerable(); + .Limit(count).ToCursorAsync().ConfigureAwait(false); + return Mapper.Map>(result.ToEnumerable()) ?? throw new InvalidOperationException("No recent reviews found for the specified users."); } public async Task> GetReviewsByDateRangeAsync(DateTime startDate, DateTime endDate) { - var filter = Builders.Filter.And( - Builders.Filter.Gte(r => r.CreatedOn, startDate), - Builders.Filter.Lte(r => r.CreatedOn, endDate) + + var filter = Builders.Filter.And( + Builders.Filter.Gte(r => r.CreatedOn, startDate), + Builders.Filter.Lte(r => r.CreatedOn, endDate) ); - return (await Collection + if (startDate == DateTime.MinValue && endDate == DateTime.MaxValue) + { + filter = Builders.Filter.Empty; // No date range filter + } + + var result = await Collection .Find(filter) .ToCursorAsync() - .ConfigureAwait(false)).ToEnumerable(); + .ConfigureAwait(false); + + return Mapper.Map>(result.ToEnumerable() ?? throw new InvalidOperationException("No reviews found in the specified date range.")); } public async Task> GetReviewsByMovieIdAsync(Guid movieId) { - var filter = Builders.Filter.Eq(r => r.MovieId, movieId.ToString()); - return (await Collection + var filter = Builders.Filter.Eq(r => r.MovieId, movieId); + var result = await Collection .Find(filter) - .ToCursorAsync().ConfigureAwait(false)).ToEnumerable(); + .ToCursorAsync().ConfigureAwait(false); + + return Mapper.Map>(result.ToEnumerable() ?? throw new InvalidOperationException("No reviews found for the specified movie.")); } public async Task> GetReviewsByRatingAsync(int rating) { - var filter = Builders.Filter.Eq(r => r.Rating, rating); - return (await Collection + var filter = Builders.Filter.Eq(r => r.Rating, rating); + var result = await Collection .Find(filter) .ToCursorAsync() - .ConfigureAwait(false)).ToEnumerable(); + .ConfigureAwait(false); + + return Mapper.Map>(result.ToEnumerable() ?? throw new InvalidOperationException("No reviews found with the specified rating.")); } public async Task> GetReviewsByUserIdAsync(Guid userId) { - var filter = Builders.Filter.Eq(r => r.Author, userId.ToString()); - return (await Collection + var filter = Builders.Filter.Eq(r => r.Author, userId.ToString()); + var result = await Collection .Find(filter) .ToCursorAsync() - .ConfigureAwait(false)).ToEnumerable(); + .ConfigureAwait(false); + + return Mapper.Map>(result.ToEnumerable() ?? throw new InvalidOperationException("No reviews found for the specified user.")); } } diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/ReviewService.Infrastructure.Repository.csproj b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/ReviewService.Infrastructure.Repository.csproj index 1a510628..cc515cd5 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/ReviewService.Infrastructure.Repository.csproj +++ b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/ReviewService.Infrastructure.Repository.csproj @@ -7,6 +7,7 @@ + diff --git a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Seed/MalayalamReviewsSeed.cs b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Seed/MalayalamReviewsSeed.cs index 26db74b5..c2ad9435 100644 --- a/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Seed/MalayalamReviewsSeed.cs +++ b/server/nt.microservice/services/ReviewService/ReviewService.Infrastructure.Repository/Seed/MalayalamReviewsSeed.cs @@ -11,7 +11,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("6191e634-14c8-45d1-898f-191060cdbec1"), Rating = 5, Title = "Ustad Hotel Feels", - UserName = "moviebuff_91" + Author = "moviebuff_91" }, new() { Content = "Dulquer and Thilakan make this movie a beautiful emotional ride. Music was perfect.", @@ -19,7 +19,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("6191e634-14c8-45d1-898f-191060cdbec1"), Rating = 4, Title = "Beautiful Blend", - UserName = "cinemalover" + Author = "cinemalover" }, new() { Content = "Joji is an intense, slow burn thriller. Brilliant acting by Fahadh as always.", @@ -27,7 +27,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("bea50cb7-41b6-4a35-b77f-358e8c43f850"), Rating = 4, Title = "Dark and Gripping", - UserName = "screenaddict" + Author = "screenaddict" }, new() { Content = "Minimal dialogues, maximum impact. Joji is a masterclass in modern Malayalam cinema.", @@ -35,7 +35,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("bea50cb7-41b6-4a35-b77f-358e8c43f850"), Rating = 5, Title = "Minimalist Brilliance", - UserName = "cinecritic" + Author = "cinecritic" }, new() { Content = "A hilarious ride with unexpected twists. Oru Vadakkan Selfie is pure fun.", @@ -43,7 +43,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("bd4b80a0-1516-4b71-887b-714c52459f23"), Rating = 4, Title = "Comedy Hit", - UserName = "ajay.m" + Author = "ajay.m" }, new() { Content = "Selfie gone wrong but in the best way possible. Loved the storytelling and humor.", @@ -51,7 +51,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("bd4b80a0-1516-4b71-887b-714c52459f23"), Rating = 5, Title = "Smart Comedy", - UserName = "techjunkie" + Author = "techjunkie" }, new() { Content = "Malik is powerful. A political saga with gripping performances. Fahadh nailed it!", @@ -59,7 +59,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("0003be11-f19a-4b9c-a1b2-b7e195b53d3e"), Rating = 5, Title = "Political Power", - UserName = "seriouscinema" + Author = "seriouscinema" }, new() { Content = "One of the best performances by Fahadh. Malik stays with you long after it ends.", @@ -67,7 +67,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("0003be11-f19a-4b9c-a1b2-b7e195b53d3e"), Rating = 5, Title = "Brilliant Execution", - UserName = "rajfilm" + Author = "rajfilm" }, new() { Content = "Premam is nostalgic, fun, and full of charm. Every phase of love was shown beautifully.", @@ -75,7 +75,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("af3e9bed-3e04-4f06-856d-3c572605bf4d"), Rating = 5, Title = "Love Story Goals", - UserName = "dreamy_eyes" + Author = "dreamy_eyes" }, new() { Content = "Great music, wonderful performances. Premam is a modern Malayalam classic.", @@ -83,7 +83,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("af3e9bed-3e04-4f06-856d-3c572605bf4d"), Rating = 5, Title = "Evergreen", - UserName = "anu_reviews" + Author = "anu_reviews" }, new() { Content = "Jana Gana Mana is thought-provoking. Raises valid questions about justice and media.", @@ -91,7 +91,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("47435a1d-6b24-4cfc-b3a6-0be543322187"), Rating = 4, Title = "Relevant and Bold", - UserName = "truthseeker" + Author = "truthseeker" }, new() { Content = "Powerful script and solid performances. Worth watching more than once.", @@ -99,7 +99,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("47435a1d-6b24-4cfc-b3a6-0be543322187"), Rating = 5, Title = "Must Watch", - UserName = "prithvi_rules" + Author = "prithvi_rules" }, new() { Content = "Ustad Hotel remains a comfort movie. It warms the soul and stirs the appetite.", @@ -107,7 +107,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("6191e634-14c8-45d1-898f-191060cdbec1"), Rating = 5, Title = "Feel-Good Watch", - UserName = "greenchili" + Author = "greenchili" }, new() { Content = "Malik's political layers and gripping visuals make it a standout Malayalam film.", @@ -115,7 +115,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("0003be11-f19a-4b9c-a1b2-b7e195b53d3e"), Rating = 4, Title = "Strong Narrative", - UserName = "malayalicritic" + Author = "malayalicritic" }, new() { Content = "Premam redefined romance in Malayalam cinema. A perfect blend of nostalgia and music.", @@ -123,7 +123,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("af3e9bed-3e04-4f06-856d-3c572605bf4d"), Rating = 5, Title = "Romantic Classic", - UserName = "cinepulse" + Author = "cinepulse" }, new() { Content = "Joji’s silence speaks louder than words. A chilling adaptation of Macbeth.", @@ -131,7 +131,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("bea50cb7-41b6-4a35-b77f-358e8c43f850"), Rating = 4, Title = "Psychological Drama", - UserName = "joji_fan" + Author = "joji_fan" }, new() { Content = "Loved every bit of Oru Vadakkan Selfie. Light-hearted and perfect for a rewatch!", @@ -139,7 +139,7 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("bd4b80a0-1516-4b71-887b-714c52459f23"), Rating = 4, Title = "Laugh Riot", - UserName = "minnal_m" + Author = "minnal_m" }, new() { Content = "Jana Gana Mana deserves more attention. Thought-provoking and very well directed.", @@ -147,14 +147,15 @@ public static class MalayalamReviewsSeed MovieId = Guid.Parse("47435a1d-6b24-4cfc-b3a6-0be543322187"), Rating = 5, Title = "Social Eye-Opener", - UserName = "vocalviewer" + Author = "vocalviewer" }, new() { Content = "Premam’s characters grow on you. Sai Pallavi was just magical!", ID = Guid.NewGuid().ToString(), MovieId = Guid.Parse("af3e9bed-3e04-4f06-856d-3c572605bf4d"), Rating = 5, - Title = "Romance and Charm" + Title = "Romance and Charm", + Author = "sai_pallavi_fan" } ]; }