From 1b5987ca1946419994d81e4bca7f8d284085151c Mon Sep 17 00:00:00 2001 From: eggwhat Date: Mon, 20 May 2024 17:59:26 +0200 Subject: [PATCH 1/7] (#32) add posts service --- .../Services/IPostsService.cs | 10 +++++ .../Wrappers/PagedResponse.cs | 28 +++++++++++++ .../Wrappers/Response.cs | 10 +++++ .../Services/PostsService.cs | 42 +++++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/IPostsService.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Wrappers/PagedResponse.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Wrappers/Response.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/IPostsService.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/IPostsService.cs new file mode 100644 index 000000000..667f97f2b --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/IPostsService.cs @@ -0,0 +1,10 @@ +using MiniSpace.Services.Posts.Application.Dto; +using MiniSpace.Services.Posts.Core.Wrappers; + +namespace MiniSpace.Services.Posts.Application.Services +{ + public interface IPostsService + { + Task>> BrowsePostsAsync(SearchPosts command); + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Wrappers/PagedResponse.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Wrappers/PagedResponse.cs new file mode 100644 index 000000000..bc82a2d4a --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Wrappers/PagedResponse.cs @@ -0,0 +1,28 @@ +namespace MiniSpace.Services.Posts.Core.Wrappers +{ + public class PagedResponse : Response + { + public int TotalPages { get; } + public int TotalElements { get; } + public int Size { get; } + public int Number { get; } + public bool First { get; } + public bool Last { get; } + public bool Empty { get; } + + public PagedResponse(T content, int pageNumber, int pageSize, int totalPages, int totalElements) + { + Content = content; + TotalPages = totalPages; + TotalElements = totalElements; + Size = pageSize; + Number = pageNumber; + First = pageNumber == 0; + Last = pageNumber == totalPages - 1; + Empty = totalElements == 0; + Succeeded = true; + Errors = null; + Message = null; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Wrappers/Response.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Wrappers/Response.cs new file mode 100644 index 000000000..2de1fbc49 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Wrappers/Response.cs @@ -0,0 +1,10 @@ +namespace MiniSpace.Services.Posts.Core.Wrappers +{ + public class Response + { + public T Content { get; set; } + public bool Succeeded { get; set; } + public string[] Errors { get; set; } + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs new file mode 100644 index 000000000..92a70df10 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs @@ -0,0 +1,42 @@ +using MiniSpace.Services.Posts.Application; +using MiniSpace.Services.Posts.Application.Commands; +using MiniSpace.Services.Posts.Application.Dto; +using MiniSpace.Services.Posts.Application.Exceptions; +using MiniSpace.Services.Posts.Application.Services; +using MiniSpace.Services.Posts.Core.Wrappers; +using MiniSpace.Services.Posts.Core.Entities; +using MiniSpace.Services.Posts.Core.Repositories; +using MiniSpace.Services.Posts.Infrastructure.Mongo.Documents; + +namespace MiniSpace.Services.Posts.Infrastructure.Services +{ + public class PostsService : IPostsService + { + private readonly IPostRepository _postRepository; + private readonly IAppContext _appContext; + + public PostsService(IPostRepository postRepository, IAppContext appContext) + { + _postRepository = postRepository; + _appContext = appContext; + } + + public async Task>> BrowsePostsAsync(SearchPosts command) + { + var identity = _appContext.Identity; + + var pageNumber = command.Pageable.Page < 1 ? 1 : command.Pageable.Page; + var pageSize = command.Pageable.Size > 10 ? 10 : command.Pageable.Size; + + var result = await _postRepository.BrowseCommentsAsync( + pageNumber, pageSize, command.ContextId, context, command.ParentId, + command.Pageable.Sort.SortBy, command.Pageable.Sort.Direction); + + var pagedEvents = new PagedResponse>( + result.comments.Select(p => new PostDto(p)), + result.pageNumber, result.pageSize, result.totalPages, result.totalElements); + + return pagedEvents; + } + } +} \ No newline at end of file From 9c8af0b70c8cb3922c9a17f9bf07872dad11dc82 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Mon, 20 May 2024 18:09:45 +0200 Subject: [PATCH 2/7] (#32) update post mongo repository --- .../Commands/SearchPosts.cs | 11 +++ .../Dto/PageableDto.cs | 9 ++ .../Dto/SortDto.cs | 8 ++ .../UnauthorizedPostSearchException.cs | 15 +++ .../Services/IPostsService.cs | 3 +- .../Mongo/Repositories/Extensions.cs | 96 +++++++++++++++++++ .../Mongo/Repositories/PostMongoRepository.cs | 27 ++++++ .../Services/PostsService.cs | 8 +- 8 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/SearchPosts.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PageableDto.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/SortDto.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/UnauthorizedPostSearchException.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/SearchPosts.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/SearchPosts.cs new file mode 100644 index 000000000..e6776a5a0 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/SearchPosts.cs @@ -0,0 +1,11 @@ +using Convey.CQRS.Commands; +using MiniSpace.Services.Posts.Application.Dto; + +namespace MiniSpace.Services.Posts.Application.Commands +{ + public class SearchPosts : ICommand + { + public Guid StudentId { get; set; } + public PageableDto Pageable { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PageableDto.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PageableDto.cs new file mode 100644 index 000000000..9d6928419 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PageableDto.cs @@ -0,0 +1,9 @@ +namespace MiniSpace.Services.Posts.Application.Dto +{ + public class PageableDto + { + public int Page { get; set; } + public int Size { get; set; } + public SortDto Sort { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/SortDto.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/SortDto.cs new file mode 100644 index 000000000..0fa08bb89 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/SortDto.cs @@ -0,0 +1,8 @@ +namespace MiniSpace.Services.Posts.Application.Dto +{ + public class SortDto + { + public IEnumerable SortBy { get; set; } + public string Direction { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/UnauthorizedPostSearchException.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/UnauthorizedPostSearchException.cs new file mode 100644 index 000000000..49464f74c --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/UnauthorizedPostSearchException.cs @@ -0,0 +1,15 @@ +namespace MiniSpace.Services.Posts.Application.Exceptions +{ + public class UnauthorizedPostSearchException : AppException + { + public override string Code { get; } = "unauthorized_post_search"; + public Guid StudentId { get; } + public Guid IdentityId { get; } + + public UnauthorizedPostSearchException(Guid studentId, Guid identityId) : base("Unauthorized post search.") + { + StudentId = studentId; + IdentityId = identityId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/IPostsService.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/IPostsService.cs index 667f97f2b..6c2dc71ce 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/IPostsService.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/IPostsService.cs @@ -1,4 +1,5 @@ -using MiniSpace.Services.Posts.Application.Dto; +using MiniSpace.Services.Posts.Application.Commands; +using MiniSpace.Services.Posts.Application.Dto; using MiniSpace.Services.Posts.Core.Wrappers; namespace MiniSpace.Services.Posts.Application.Services diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs new file mode 100644 index 000000000..a52cc824e --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs @@ -0,0 +1,96 @@ +using MiniSpace.Services.Posts.Core.Entities; +using MiniSpace.Services.Posts.Infrastructure.Mongo.Documents; +using MongoDB.Driver; + +namespace MiniSpace.Services.Posts.Infrastructure.Mongo.Repositories +{ + public static class Extensions + { + private static readonly FilterDefinitionBuilder FilterDefinitionBuilder = Builders.Filter; + public static async Task<(int totalPages, int totalElements, IReadOnlyList data)> AggregateByPage( + this IMongoCollection collection, + FilterDefinition filterDefinition, + SortDefinition sortDefinition, + int page, + int pageSize) + { + var countFacet = AggregateFacet.Create("count", + PipelineDefinition.Create(new[] + { + PipelineStageDefinitionBuilder.Count() + })); + + var dataFacet = AggregateFacet.Create("data", + PipelineDefinition.Create(new[] + { + PipelineStageDefinitionBuilder.Sort(sortDefinition), + PipelineStageDefinitionBuilder.Skip((page - 1) * pageSize), + PipelineStageDefinitionBuilder.Limit(pageSize), + })); + + + var aggregation = await collection.Aggregate() + .Match(filterDefinition) + .Facet(countFacet, dataFacet) + .ToListAsync(); + + var count = aggregation.First() + .Facets.First(x => x.Name == "count") + .Output() + ?.FirstOrDefault() + ?.Count; + + if (count == null) + { + return (0, 0, Array.Empty()); + } + var totalPages = (int)Math.Ceiling((double)count / pageSize); + + var data = aggregation.First() + .Facets.First(x => x.Name == "data") + .Output(); + + return (totalPages, (int)count, data); + } + + public static FilterDefinition ToFilterDefinition(Guid contextId, PostDocument context) + { + var filterDefinition = FilterDefinitionBuilder.Empty; + + filterDefinition &= FilterDefinitionBuilder.Eq(x => x.ContextId, contextId); + filterDefinition &= FilterDefinitionBuilder.Eq(x => x.CommentContext, context); + + return filterDefinition; + } + + public static FilterDefinition AddParentFilter (this FilterDefinition filterDefinition) + { + filterDefinition &= FilterDefinitionBuilder.Eq(x => x.ParentId, Guid.Empty); + return filterDefinition; + } + + public static FilterDefinition AddChildrenFilter (this FilterDefinition filterDefinition, + Guid parentId) + { + filterDefinition &= FilterDefinitionBuilder.Eq(x => x.ParentId, parentId); + return filterDefinition; + } + + public static SortDefinition ToSortDefinition(IEnumerable sortByArguments, string direction) + { + var sort = sortByArguments.ToList(); + if(!sort.Any()) + { + sort.Add("LastReplyAt"); + sort.Add("LastUpdatedAt");sadadasdadaadas + } + var sortDefinitionBuilder = Builders.Sort; + var sortDefinition = sort + .Select(sortBy => direction == "asc" + ? sortDefinitionBuilder.Ascending(sortBy) + : sortDefinitionBuilder.Descending(sortBy)); + var sortCombined = sortDefinitionBuilder.Combine(sortDefinition); + return sortCombined; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs index 86d5c5ff8..3d8f25bbc 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs @@ -49,5 +49,32 @@ public Task DeleteAsync(Guid id) public Task ExistsAsync(Guid id) => _repository.ExistsAsync(p => p.Id == id); + + private async Task<(int totalPages, int totalElements, IEnumerable data)> BrowseAsync( + FilterDefinition filterDefinition, SortDefinition sortDefinition, + int pageNumber, int pageSize) + { + var pagedEvents = await _repository.Collection.AggregateByPage( + filterDefinition, + sortDefinition, + pageNumber, + pageSize); + + return pagedEvents; + } + + public async Task<(IEnumerable comments, int pageNumber,int pageSize, int totalPages, int totalElements)> BrowseCommentsAsync(int pageNumber, int pageSize, + IEnumerable sortBy, string direction) + { + var filterDefinition = parentId == Guid.Empty + ? Extensions.ToFilterDefinition(contextId, context).AddParentFilter() + : Extensions.ToFilterDefinition(contextId, context).AddChildrenFilter(parentId); + var sortDefinition = Extensions.ToSortDefinition(sortBy, direction); + + var pagedEvents = await BrowseAsync(filterDefinition, sortDefinition, pageNumber, pageSize); + + return (pagedEvents.data.Select(e => e.AsEntity()), pageNumber, pageSize, + pagedEvents.totalPages, pagedEvents.totalElements); + } } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs index 92a70df10..c4c2043d9 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs @@ -24,12 +24,18 @@ public PostsService(IPostRepository postRepository, IAppContext appContext) public async Task>> BrowsePostsAsync(SearchPosts command) { var identity = _appContext.Identity; + if (identity.IsAuthenticated && identity.Id != command.StudentId) + { + throw new UnauthorizedPostSearchException(command.StudentId, identity.Id); + } + + var pageNumber = command.Pageable.Page < 1 ? 1 : command.Pageable.Page; var pageSize = command.Pageable.Size > 10 ? 10 : command.Pageable.Size; var result = await _postRepository.BrowseCommentsAsync( - pageNumber, pageSize, command.ContextId, context, command.ParentId, + pageNumber, pageSize, , command.Pageable.Sort.SortBy, command.Pageable.Sort.Direction); var pagedEvents = new PagedResponse>( From 82e329b69b42a4bf6d3a5b11fad70aba4ba18936 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Mon, 20 May 2024 18:34:21 +0200 Subject: [PATCH 3/7] (#32) add students service client --- .../appsettings.docker.json | 4 ++- .../appsettings.local.json | 6 ++-- .../Dto/PostDto.cs | 19 ++++++++++++ .../Dto/StudentEventsDto.cs | 9 ++++++ .../Clients/IStudentsServiceClient.cs | 9 ++++++ ...idStudentServiceClientResponseException.cs | 14 +++++++++ .../Repositories/IPostRepository.cs | 3 ++ .../Extensions.cs | 4 +++ .../Mongo/Repositories/Extensions.cs | 30 +++++-------------- .../Mongo/Repositories/PostMongoRepository.cs | 9 +++--- .../Services/Clients/StudentsServiceClient.cs | 24 +++++++++++++++ .../Services/PostsService.cs | 22 ++++++++++---- 12 files changed, 117 insertions(+), 36 deletions(-) create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/StudentEventsDto.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/Clients/IStudentsServiceClient.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Exceptions/InvalidStudentServiceClientResponseException.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/Clients/StudentsServiceClient.cs diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/appsettings.docker.json b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/appsettings.docker.json index 07c6d2bc2..18539c4d2 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/appsettings.docker.json +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/appsettings.docker.json @@ -22,7 +22,9 @@ "httpClient": { "type": "fabio", "retries": 3, - "services": {} + "services": { + "students": "students-service" + } }, "jwt": { "certificate": { diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/appsettings.local.json b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/appsettings.local.json index 29f59a9ca..535b691a9 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/appsettings.local.json +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/appsettings.local.json @@ -21,9 +21,11 @@ "service": "posts-service" }, "httpClient": { - "type": "fabio", + "type": "direct", "retries": 3, - "services": {}, + "services": { + "students": "http://localhost:5007" + }, "requestMasking": { "enabled": true, "maskTemplate": "*****" diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PostDto.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PostDto.cs index 49c7359cb..8545cc0b6 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PostDto.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PostDto.cs @@ -1,3 +1,5 @@ +using MiniSpace.Services.Posts.Core.Entities; + namespace MiniSpace.Services.Posts.Application.Dto { public class PostDto @@ -11,5 +13,22 @@ public class PostDto public DateTime? PublishDate { get; set; } public DateTime CreatedAt { get; set; } public DateTime? UpdatedAt { get; set; } + + public PostDto() + { + } + + public PostDto(Post post) + { + Id = post.Id; + EventId = post.EventId; + OrganizerId = post.OrganizerId; + TextContent = post.TextContent; + MediaFiles = post.MediaFiles; + State = post.State.ToString(); + PublishDate = post.PublishDate; + CreatedAt = post.CreatedAt; + UpdatedAt = post.UpdatedAt; + } } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/StudentEventsDto.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/StudentEventsDto.cs new file mode 100644 index 000000000..2f27c2fa3 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/StudentEventsDto.cs @@ -0,0 +1,9 @@ +namespace MiniSpace.Services.Posts.Application.Dto +{ + public class StudentEventsDto + { + public Guid StudentId { get; set; } + public IEnumerable InterestedInEvents { get; set; } + public IEnumerable SignedUpEvents { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/Clients/IStudentsServiceClient.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/Clients/IStudentsServiceClient.cs new file mode 100644 index 000000000..849818345 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Services/Clients/IStudentsServiceClient.cs @@ -0,0 +1,9 @@ +using MiniSpace.Services.Posts.Application.Dto; + +namespace MiniSpace.Services.Posts.Application.Services.Clients +{ + public interface IStudentsServiceClient + { + Task GetAsync(Guid id); + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Exceptions/InvalidStudentServiceClientResponseException.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Exceptions/InvalidStudentServiceClientResponseException.cs new file mode 100644 index 000000000..c76e981b4 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Exceptions/InvalidStudentServiceClientResponseException.cs @@ -0,0 +1,14 @@ +namespace MiniSpace.Services.Posts.Core.Exceptions +{ + public class InvalidStudentServiceClientResponseException : DomainException + { + public override string Code { get; } = "invalid_student_service_client_response"; + public Guid StudentId { get; } + + public InvalidStudentServiceClientResponseException(Guid studentId) + : base($"Invalid student service client response for student with ID: '{studentId}'.") + { + StudentId = studentId; + } + } +} diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Repositories/IPostRepository.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Repositories/IPostRepository.cs index 56566f803..f2c68e399 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Repositories/IPostRepository.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Repositories/IPostRepository.cs @@ -1,4 +1,5 @@ using MiniSpace.Services.Posts.Core.Entities; +using MiniSpace.Services.Posts.Core.Wrappers; namespace MiniSpace.Services.Posts.Core.Repositories { @@ -11,5 +12,7 @@ public interface IPostRepository Task UpdateAsync(Post post); Task DeleteAsync(Guid id); Task ExistsAsync(Guid id); + Task<(IEnumerable posts, int pageNumber,int pageSize, int totalPages, int totalElements)> BrowseCommentsAsync(int pageNumber, int pageSize, + IEnumerable eventsIds, IEnumerable sortBy, string direction); } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Extensions.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Extensions.cs index c5e400ecb..0a91bf72a 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Extensions.cs @@ -25,11 +25,13 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; +using MiniSpace.Services.Events.Infrastructure.Services.Clients; using Newtonsoft.Json; using MiniSpace.Services.Posts.Application; using MiniSpace.Services.Posts.Application.Commands; using MiniSpace.Services.Posts.Application.Events.External; using MiniSpace.Services.Posts.Application.Services; +using MiniSpace.Services.Posts.Application.Services.Clients; using MiniSpace.Services.Posts.Core.Repositories; using MiniSpace.Services.Posts.Infrastructure.Contexts; using MiniSpace.Services.Posts.Infrastructure.Decorators; @@ -52,6 +54,8 @@ public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) builder.Services.AddSingleton(); builder.Services.AddTransient(); builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); builder.Services.AddTransient(ctx => ctx.GetRequiredService().Create()); builder.Services.TryDecorate(typeof(ICommandHandler<>), typeof(OutboxCommandHandlerDecorator<>)); builder.Services.TryDecorate(typeof(IEventHandler<>), typeof(OutboxEventHandlerDecorator<>)); diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs index a52cc824e..cc3baed57 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs @@ -1,4 +1,5 @@ -using MiniSpace.Services.Posts.Core.Entities; +using System.Collections; +using MiniSpace.Services.Posts.Core.Entities; using MiniSpace.Services.Posts.Infrastructure.Mongo.Documents; using MongoDB.Driver; @@ -52,37 +53,22 @@ public static class Extensions return (totalPages, (int)count, data); } - - public static FilterDefinition ToFilterDefinition(Guid contextId, PostDocument context) + + public static FilterDefinition ToFilterDefinition(IEnumerable eventsIds) { var filterDefinition = FilterDefinitionBuilder.Empty; - filterDefinition &= FilterDefinitionBuilder.Eq(x => x.ContextId, contextId); - filterDefinition &= FilterDefinitionBuilder.Eq(x => x.CommentContext, context); + filterDefinition &= FilterDefinitionBuilder.In(p => p.EventId, eventsIds); return filterDefinition; } - - public static FilterDefinition AddParentFilter (this FilterDefinition filterDefinition) - { - filterDefinition &= FilterDefinitionBuilder.Eq(x => x.ParentId, Guid.Empty); - return filterDefinition; - } - - public static FilterDefinition AddChildrenFilter (this FilterDefinition filterDefinition, - Guid parentId) - { - filterDefinition &= FilterDefinitionBuilder.Eq(x => x.ParentId, parentId); - return filterDefinition; - } - + public static SortDefinition ToSortDefinition(IEnumerable sortByArguments, string direction) { var sort = sortByArguments.ToList(); - if(!sort.Any()) + if(sort.Count == 0) { - sort.Add("LastReplyAt"); - sort.Add("LastUpdatedAt");sadadasdadaadas + sort.Add("PublishDate"); } var sortDefinitionBuilder = Builders.Sort; var sortDefinition = sort diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs index 3d8f25bbc..feb7e0619 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs @@ -1,3 +1,4 @@ +using System.Collections; using Convey.Persistence.MongoDB; using MiniSpace.Services.Posts.Core.Entities; using MiniSpace.Services.Posts.Core.Repositories; @@ -63,12 +64,10 @@ public Task ExistsAsync(Guid id) return pagedEvents; } - public async Task<(IEnumerable comments, int pageNumber,int pageSize, int totalPages, int totalElements)> BrowseCommentsAsync(int pageNumber, int pageSize, - IEnumerable sortBy, string direction) + public async Task<(IEnumerable posts, int pageNumber,int pageSize, int totalPages, int totalElements)> BrowseCommentsAsync(int pageNumber, int pageSize, + IEnumerable eventsIds, IEnumerable sortBy, string direction) { - var filterDefinition = parentId == Guid.Empty - ? Extensions.ToFilterDefinition(contextId, context).AddParentFilter() - : Extensions.ToFilterDefinition(contextId, context).AddChildrenFilter(parentId); + var filterDefinition = Extensions.ToFilterDefinition(eventsIds); var sortDefinition = Extensions.ToSortDefinition(sortBy, direction); var pagedEvents = await BrowseAsync(filterDefinition, sortDefinition, pageNumber, pageSize); diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/Clients/StudentsServiceClient.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/Clients/StudentsServiceClient.cs new file mode 100644 index 000000000..d58c856c5 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/Clients/StudentsServiceClient.cs @@ -0,0 +1,24 @@ +using System; +using System.Threading.Tasks; +using Convey.HTTP; +using MiniSpace.Services.Posts.Application.Dto; +using MiniSpace.Services.Posts.Application.Services.Clients; + +namespace MiniSpace.Services.Events.Infrastructure.Services.Clients +{ + public class StudentsServiceClient : IStudentsServiceClient + { + private readonly IHttpClient _httpClient; + private readonly string _url; + + public StudentsServiceClient(IHttpClient httpClient, HttpClientOptions options) + { + _httpClient = httpClient; + _url = options.Services["students"]; + } + + public Task GetAsync(Guid id) + => _httpClient.GetAsync($"{_url}/students/{id}/events"); + + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs index c4c2043d9..1cce33758 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Services/PostsService.cs @@ -3,8 +3,10 @@ using MiniSpace.Services.Posts.Application.Dto; using MiniSpace.Services.Posts.Application.Exceptions; using MiniSpace.Services.Posts.Application.Services; +using MiniSpace.Services.Posts.Application.Services.Clients; using MiniSpace.Services.Posts.Core.Wrappers; using MiniSpace.Services.Posts.Core.Entities; +using MiniSpace.Services.Posts.Core.Exceptions; using MiniSpace.Services.Posts.Core.Repositories; using MiniSpace.Services.Posts.Infrastructure.Mongo.Documents; @@ -13,11 +15,14 @@ namespace MiniSpace.Services.Posts.Infrastructure.Services public class PostsService : IPostsService { private readonly IPostRepository _postRepository; + private readonly IStudentsServiceClient _studentsServiceClient; private readonly IAppContext _appContext; - public PostsService(IPostRepository postRepository, IAppContext appContext) + public PostsService(IPostRepository postRepository, IStudentsServiceClient studentsServiceClient, + IAppContext appContext) { _postRepository = postRepository; + _studentsServiceClient = studentsServiceClient; _appContext = appContext; } @@ -28,18 +33,23 @@ public async Task>> BrowsePostsAsync(SearchPo { throw new UnauthorizedPostSearchException(command.StudentId, identity.Id); } - - + + var studentEvents = await _studentsServiceClient.GetAsync(command.StudentId); + if (studentEvents is null) + { + throw new InvalidStudentServiceClientResponseException(command.StudentId); + } + + var eventsIds = studentEvents.InterestedInEvents.Union(studentEvents.SignedUpEvents).ToList(); var pageNumber = command.Pageable.Page < 1 ? 1 : command.Pageable.Page; var pageSize = command.Pageable.Size > 10 ? 10 : command.Pageable.Size; var result = await _postRepository.BrowseCommentsAsync( - pageNumber, pageSize, , - command.Pageable.Sort.SortBy, command.Pageable.Sort.Direction); + pageNumber, pageSize, eventsIds, command.Pageable.Sort.SortBy, command.Pageable.Sort.Direction); var pagedEvents = new PagedResponse>( - result.comments.Select(p => new PostDto(p)), + result.posts.Select(p => new PostDto(p)), result.pageNumber, result.pageSize, result.totalPages, result.totalElements); return pagedEvents; From 53cbccaf65a3d65aa26733c09a4e388d3ae04f71 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Mon, 20 May 2024 18:39:57 +0200 Subject: [PATCH 4/7] (#32) add new endpoint declaration --- .../src/MiniSpace.Services.Posts.Api/Program.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/Program.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/Program.cs index bdbec8ae4..06d1e8349 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/Program.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Api/Program.cs @@ -13,6 +13,7 @@ using MiniSpace.Services.Posts.Application.Commands; using MiniSpace.Services.Posts.Application.Dto; using MiniSpace.Services.Posts.Application.Queries; +using MiniSpace.Services.Posts.Application.Services; using MiniSpace.Services.Posts.Infrastructure; namespace MiniSpace.Services.Posts.Api @@ -29,6 +30,12 @@ public static async Task Main(string[] args) .Build()) .Configure(app => app .UseInfrastructure() + .UseEndpoints(endpoints => endpoints + .Post("posts/search", async (cmd, ctx) => + { + var pagedResult = await ctx.RequestServices.GetService().BrowsePostsAsync(cmd); + await ctx.Response.WriteJsonAsync(pagedResult); + })) .UseDispatcherEndpoints(endpoints => endpoints .Get("", ctx => ctx.Response.WriteAsync(ctx.RequestServices.GetService().Name)) .Get("posts/{postId}") From 0dc5ab5171d3f15f05d552e84e9919b02f6bdacf Mon Sep 17 00:00:00 2001 From: eggwhat Date: Mon, 20 May 2024 18:58:02 +0200 Subject: [PATCH 5/7] (#31) update ntrada files for new posts endpoints --- .../src/MiniSpace.APIGateway/ntrada-async.docker.yml | 6 ++++++ .../src/MiniSpace.APIGateway/ntrada-async.yml | 6 ++++++ .../src/MiniSpace.APIGateway/ntrada.docker.yml | 6 ++++++ MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada-async.docker.yml b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada-async.docker.yml index 0bacf7db2..2ec673547 100644 --- a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada-async.docker.yml +++ b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada-async.docker.yml @@ -580,6 +580,12 @@ modules: use: downstream downstream: posts-service/posts auth: true + + - upstream: /search + method: POST + use: downstream + downstream: posts-service/posts/search + auth: true - upstream: /{postId} method: PUT diff --git a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada-async.yml b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada-async.yml index 8db4a6da3..2323905eb 100644 --- a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada-async.yml +++ b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada-async.yml @@ -581,6 +581,12 @@ modules: downstream: posts-service/posts auth: true + - upstream: /search + method: POST + use: downstream + downstream: posts-service/posts/search + auth: true + - upstream: /{postId} method: PUT use: downstream diff --git a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.docker.yml b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.docker.yml index bf7d63347..8dfc7384e 100644 --- a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.docker.yml +++ b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.docker.yml @@ -558,6 +558,12 @@ modules: downstream: posts-service/posts auth: true + - upstream: /search + method: POST + use: downstream + downstream: posts-service/posts/search + auth: true + - upstream: /{postId} method: PUT use: downstream diff --git a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml index 731257a35..0170714a5 100644 --- a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml +++ b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml @@ -560,6 +560,12 @@ modules: downstream: posts-service/posts auth: true + - upstream: /search + method: POST + use: downstream + downstream: posts-service/posts/search + auth: true + - upstream: /{postId} method: PUT use: downstream From 86e8b25dd729654a215f3f5d815f6779524f2264 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Mon, 20 May 2024 22:28:07 +0200 Subject: [PATCH 6/7] (#32) fix publish date to change when post is published --- .../src/MiniSpace.Services.Posts.Core/Entities/Post.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs index ab2769461..ced44e44f 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs @@ -38,7 +38,7 @@ public void SetToBePublished(DateTime publishDate, DateTime now) public void SetPublished(DateTime now) { State = State.Published; - PublishDate = null; + PublishDate = now; UpdatedAt = now; } @@ -72,7 +72,8 @@ public static Post Create(AggregateId id, Guid eventId, Guid studentId, string t { CheckTextContent(id, textContent); - return new Post(id, eventId, studentId, textContent, mediaFiles, createdAt, state, publishDate); + return new Post(id, eventId, studentId, textContent, mediaFiles, createdAt, state, + publishDate ?? createdAt); } public void Update(string textContent, IEnumerable mediaFiles, DateTime now) From f4622edea0f867b97d04acabe0a179764c40eeb2 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Mon, 20 May 2024 22:41:31 +0200 Subject: [PATCH 7/7] (#32) add state filter --- .../Mongo/Repositories/Extensions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs index cc3baed57..c201f56a4 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/Extensions.cs @@ -59,6 +59,7 @@ public static FilterDefinition ToFilterDefinition(IEnumerable p.EventId, eventsIds); + filterDefinition &= FilterDefinitionBuilder.Eq(p => p.State, State.Published); return filterDefinition; }