From 287ab5b2bb63ae85e70341d1bc02f336870a1a99 Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Mon, 30 Dec 2024 00:45:38 +0100 Subject: [PATCH 01/18] Refactor UserId type from Guid to string --- .../Commands/AddComment/AddCommentCommand.cs | 2 +- .../Commands/AddLike/AddLikeCommand.cs | 2 +- .../Commands/AddPost/AddPostCommand.cs | 2 +- .../DeleteComment/DeleteCommentCommand.cs | 2 +- .../Commands/DeleteLike/DeleteLikeCommand.cs | 2 +- .../Commands/DeletePost/DeletePostCommand.cs | 2 +- .../Commands/UpdatePost/UpdatePostCommand.cs | 2 +- .../DTOs/CommentDto.cs | 2 +- .../PostService.Application/DTOs/LikeDto.cs | 2 +- .../PostService.Domain/Entities/Comment.cs | 6 +-- .../PostService.Domain/Entities/Like.cs | 6 +-- .../PostService.Domain/Entities/Post.cs | 12 +++--- .../PostService.Domain/Entities/User.cs | 4 +- .../CommentTests/DeleteCommentTests.cs | 2 +- .../LikeTests/DeleteLikeTests.cs | 2 +- .../PostTests/DeletePostTests.cs | 2 +- .../PostTests/UpdatePostTests.cs | 2 +- .../LikeTests/GetAllLikesTests.cs | 6 +-- .../TestFixture.cs | 2 +- .../PostService.Domain.Tests/CommentTests.cs | 10 ++--- .../PostService.Domain.Tests/LikeTests.cs | 6 +-- .../PostService.Domain.Tests/PostTests.cs | 41 +++++++++++-------- 22 files changed, 62 insertions(+), 57 deletions(-) diff --git a/backend/src/PostService/PostService.Application/Commands/AddComment/AddCommentCommand.cs b/backend/src/PostService/PostService.Application/Commands/AddComment/AddCommentCommand.cs index c5c5ffd..f9aea13 100644 --- a/backend/src/PostService/PostService.Application/Commands/AddComment/AddCommentCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/AddComment/AddCommentCommand.cs @@ -3,4 +3,4 @@ namespace PostService.Application.Commands.AddComment; -public record AddCommentCommand(CreateCommentDto CreateComment, Guid UserId) : ICommand; \ No newline at end of file +public record AddCommentCommand(CreateCommentDto CreateComment, string UserId) : ICommand; \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/AddLike/AddLikeCommand.cs b/backend/src/PostService/PostService.Application/Commands/AddLike/AddLikeCommand.cs index bd55583..fac0310 100644 --- a/backend/src/PostService/PostService.Application/Commands/AddLike/AddLikeCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/AddLike/AddLikeCommand.cs @@ -2,4 +2,4 @@ namespace PostService.Application.Commands.AddLike; -public record AddLikeCommand(Guid PostId, Guid UserId) : ICommand; \ No newline at end of file +public record AddLikeCommand(Guid PostId, string UserId) : ICommand; \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/AddPost/AddPostCommand.cs b/backend/src/PostService/PostService.Application/Commands/AddPost/AddPostCommand.cs index f292ccb..1c0d5a7 100644 --- a/backend/src/PostService/PostService.Application/Commands/AddPost/AddPostCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/AddPost/AddPostCommand.cs @@ -3,4 +3,4 @@ namespace PostService.Application.Commands.AddPost; -public record AddPostCommand(CreatePostDto CreatePost, Guid UserId) : ICommand; \ No newline at end of file +public record AddPostCommand(CreatePostDto CreatePost, string UserId) : ICommand; \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/DeleteComment/DeleteCommentCommand.cs b/backend/src/PostService/PostService.Application/Commands/DeleteComment/DeleteCommentCommand.cs index 4eac14d..c4bb0f9 100644 --- a/backend/src/PostService/PostService.Application/Commands/DeleteComment/DeleteCommentCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/DeleteComment/DeleteCommentCommand.cs @@ -2,4 +2,4 @@ namespace PostService.Application.Commands.DeleteComment; -public record DeleteCommentCommand(Guid Id, Guid PostId, Guid UserId) : ICommand; \ No newline at end of file +public record DeleteCommentCommand(Guid Id, Guid PostId, string UserId) : ICommand; \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/DeleteLike/DeleteLikeCommand.cs b/backend/src/PostService/PostService.Application/Commands/DeleteLike/DeleteLikeCommand.cs index c46d278..624fc0a 100644 --- a/backend/src/PostService/PostService.Application/Commands/DeleteLike/DeleteLikeCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/DeleteLike/DeleteLikeCommand.cs @@ -2,4 +2,4 @@ namespace PostService.Application.Commands.DeleteLike; -public record DeleteLikeCommand(Guid Id, Guid PostId, Guid UserId) : ICommand; \ No newline at end of file +public record DeleteLikeCommand(Guid Id, Guid PostId, string UserId) : ICommand; \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/DeletePost/DeletePostCommand.cs b/backend/src/PostService/PostService.Application/Commands/DeletePost/DeletePostCommand.cs index c1cf1cd..40da827 100644 --- a/backend/src/PostService/PostService.Application/Commands/DeletePost/DeletePostCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/DeletePost/DeletePostCommand.cs @@ -2,4 +2,4 @@ namespace PostService.Application.Commands.DeletePost; -public record DeletePostCommand(Guid Id, Guid UserId) : ICommand; \ No newline at end of file +public record DeletePostCommand(Guid Id, string UserId) : ICommand; \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/UpdatePost/UpdatePostCommand.cs b/backend/src/PostService/PostService.Application/Commands/UpdatePost/UpdatePostCommand.cs index e12d200..b16ecd8 100644 --- a/backend/src/PostService/PostService.Application/Commands/UpdatePost/UpdatePostCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/UpdatePost/UpdatePostCommand.cs @@ -3,4 +3,4 @@ namespace PostService.Application.Commands.UpdatePost; -public record UpdatePostCommand(UpdatePostDto UpdatePost, Guid UserId) : ICommand; \ No newline at end of file +public record UpdatePostCommand(UpdatePostDto UpdatePost, string UserId) : ICommand; \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/DTOs/CommentDto.cs b/backend/src/PostService/PostService.Application/DTOs/CommentDto.cs index 5ed9fae..4928173 100644 --- a/backend/src/PostService/PostService.Application/DTOs/CommentDto.cs +++ b/backend/src/PostService/PostService.Application/DTOs/CommentDto.cs @@ -3,7 +3,7 @@ namespace PostService.Application.DTOs; public record CommentDto( Guid Id, Guid PostId, - Guid UserId, + string UserId, string Username, string Content, DateTime CreatedAt diff --git a/backend/src/PostService/PostService.Application/DTOs/LikeDto.cs b/backend/src/PostService/PostService.Application/DTOs/LikeDto.cs index 010189f..ffca698 100644 --- a/backend/src/PostService/PostService.Application/DTOs/LikeDto.cs +++ b/backend/src/PostService/PostService.Application/DTOs/LikeDto.cs @@ -3,6 +3,6 @@ namespace PostService.Application.DTOs; public record LikeDto( Guid Id, Guid PostId, - Guid UserId, + string UserId, DateTime CreatedAt ); \ No newline at end of file diff --git a/backend/src/PostService/PostService.Domain/Entities/Comment.cs b/backend/src/PostService/PostService.Domain/Entities/Comment.cs index a3d69a4..76cfbbb 100644 --- a/backend/src/PostService/PostService.Domain/Entities/Comment.cs +++ b/backend/src/PostService/PostService.Domain/Entities/Comment.cs @@ -4,19 +4,19 @@ public class Comment { public Guid Id { get; private set; } public Guid PostId { get; private set; } - public Guid UserId { get; private set; } + public string UserId { get; private set; } public string Username { get; private set; } public string Content { get; private set; } public DateTime CreatedAt { get; private set; } - public Comment(Guid postId, Guid userId, string username, string content) + public Comment(Guid postId, string userId, string username, string content) { if (postId == Guid.Empty) { throw new ArgumentException("PostId cannot be empty.", nameof(postId)); } - if (userId == Guid.Empty) + if (string.IsNullOrEmpty(userId)) { throw new ArgumentException("UserId cannot be empty.", nameof(userId)); } diff --git a/backend/src/PostService/PostService.Domain/Entities/Like.cs b/backend/src/PostService/PostService.Domain/Entities/Like.cs index d2bea09..b5fb5ba 100644 --- a/backend/src/PostService/PostService.Domain/Entities/Like.cs +++ b/backend/src/PostService/PostService.Domain/Entities/Like.cs @@ -4,17 +4,17 @@ public class Like { public Guid Id { get; private set; } public Guid PostId { get; private set; } - public Guid UserId { get; private set; } + public string UserId { get; private set; } public DateTime CreatedAt { get; private set; } - public Like(Guid postId, Guid userId) + public Like(Guid postId, string userId) { if (postId == Guid.Empty) { throw new ArgumentException("PostId cannot be empty.", nameof(postId)); } - if (userId == Guid.Empty) + if (string.IsNullOrEmpty(userId)) { throw new ArgumentException("UserId cannot be empty.", nameof(userId)); } diff --git a/backend/src/PostService/PostService.Domain/Entities/Post.cs b/backend/src/PostService/PostService.Domain/Entities/Post.cs index eee1160..81857cd 100644 --- a/backend/src/PostService/PostService.Domain/Entities/Post.cs +++ b/backend/src/PostService/PostService.Domain/Entities/Post.cs @@ -5,7 +5,7 @@ namespace PostService.Domain.Entities; public class Post { public Guid Id { get; private set; } - public Guid UserId { get; private set; } + public string UserId { get; private set; } public string Title { get; private set; } public string Description { get; private set; } public string ContentUrl { get; private set; } @@ -14,9 +14,9 @@ public class Post public uint CommentCount { get; private set; } public DateTime CreatedAt { get; private set; } - private Post(Guid userId, string title, string description, string contentUrl, ContentType contentType) + private Post(string userId, string title, string description, string contentUrl, ContentType contentType) { - if (userId == Guid.Empty) + if (string.IsNullOrEmpty(userId)) { throw new ArgumentException("UserId cannot be empty.", nameof(userId)); } @@ -33,17 +33,17 @@ private Post(Guid userId, string title, string description, string contentUrl, C CreatedAt = DateTime.UtcNow; } - public static Post CreateTextPost(Guid userId, string title, string description) + public static Post CreateTextPost(string userId, string title, string description) { return new Post(userId, title, description, string.Empty, ContentType.Text); } - public static Post CreateImagePost(Guid userId, string contentUrl, string title = "", string description = "") + public static Post CreateImagePost(string userId, string contentUrl, string title = "", string description = "") { return new Post(userId, title, description, contentUrl, ContentType.Image); } - public static Post CreateVideoPost(Guid userId, string contentUrl, string title = "", string description = "") + public static Post CreateVideoPost(string userId, string contentUrl, string title = "", string description = "") { return new Post(userId, title, description, contentUrl, ContentType.Video); } diff --git a/backend/src/PostService/PostService.Domain/Entities/User.cs b/backend/src/PostService/PostService.Domain/Entities/User.cs index 07b2b15..2d52a03 100644 --- a/backend/src/PostService/PostService.Domain/Entities/User.cs +++ b/backend/src/PostService/PostService.Domain/Entities/User.cs @@ -2,14 +2,14 @@ namespace PostService.Domain.Entities; public class User { - public Guid Id { get; private set; } + public string Id { get; private set; } public string FirstName { get; private set; } public string LastName { get; private set; } public string Username { get; private set; } public string ImageUrl { get; private set; } public DateTime CreatedAt { get; private set; } - public User(Guid id, string firstName, string lastName, string username, string imageUrl) + public User(string id, string firstName, string lastName, string username, string imageUrl) { Id = id; FirstName = firstName; diff --git a/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/CommentTests/DeleteCommentTests.cs b/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/CommentTests/DeleteCommentTests.cs index b997d73..b6e0b41 100644 --- a/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/CommentTests/DeleteCommentTests.cs +++ b/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/CommentTests/DeleteCommentTests.cs @@ -96,7 +96,7 @@ public async Task HandleAsync_ShouldFail_WhenUserDoesNotHavePermissionToDeleteCo var createPost = new CreatePostDto(title, description, contentUrl, contentType); var userId = Fixture.ExistingUser.Id; - var anotherUserId = Guid.NewGuid(); + var anotherUserId = Guid.NewGuid().ToString(); var commandPost = new AddPostCommand(createPost, userId); var post = await Fixture.AddPostCommandHandler.HandleAsync(commandPost); diff --git a/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/LikeTests/DeleteLikeTests.cs b/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/LikeTests/DeleteLikeTests.cs index 43e5041..2d03882 100644 --- a/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/LikeTests/DeleteLikeTests.cs +++ b/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/LikeTests/DeleteLikeTests.cs @@ -81,7 +81,7 @@ public async Task HandleAsync_ShouldFail_WhenUserHasNotLikedPost() var createPost = new CreatePostDto(title, description, contentUrl, contentType); var userId = Fixture.ExistingUser.Id; - var anotherUserId = Guid.NewGuid(); + var anotherUserId = Guid.NewGuid().ToString(); var commandPost = new AddPostCommand(createPost, userId); var post = await Fixture.AddPostCommandHandler.HandleAsync(commandPost); diff --git a/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/PostTests/DeletePostTests.cs b/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/PostTests/DeletePostTests.cs index 496bb1a..4658eac 100644 --- a/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/PostTests/DeletePostTests.cs +++ b/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/PostTests/DeletePostTests.cs @@ -71,7 +71,7 @@ public async Task HandleAsync_ShouldFail_WhenUserIdDoesNotMatch() var createPost = new CreatePostDto(title, description, contentUrl, contentType); var userId = Fixture.ExistingUser.Id; - var anotherUserId = Guid.NewGuid(); + var anotherUserId = Guid.NewGuid().ToString(); var postCommand = new AddPostCommand(createPost, userId); diff --git a/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/PostTests/UpdatePostTests.cs b/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/PostTests/UpdatePostTests.cs index 1c75a68..38ae5fc 100644 --- a/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/PostTests/UpdatePostTests.cs +++ b/backend/tests/PostService/PostService.Application.Tests/CommandHandlerTests/PostTests/UpdatePostTests.cs @@ -78,7 +78,7 @@ public async Task HandleAsync_ShouldFail_WhenUserIdDoesNotMatch() var createPost = new CreatePostDto(title, description, contentUrl, contentType); var userId = Fixture.ExistingUser.Id; - var anotherUserId = Guid.NewGuid(); + var anotherUserId = Guid.NewGuid().ToString(); var postCommand = new AddPostCommand(createPost, userId); diff --git a/backend/tests/PostService/PostService.Application.Tests/QueryHandlerTests/LikeTests/GetAllLikesTests.cs b/backend/tests/PostService/PostService.Application.Tests/QueryHandlerTests/LikeTests/GetAllLikesTests.cs index 6a80281..82e0a91 100644 --- a/backend/tests/PostService/PostService.Application.Tests/QueryHandlerTests/LikeTests/GetAllLikesTests.cs +++ b/backend/tests/PostService/PostService.Application.Tests/QueryHandlerTests/LikeTests/GetAllLikesTests.cs @@ -30,8 +30,8 @@ public async Task HandleAsync_ShouldReturnLikes_ForSpecifiedPost() var postId = post.Response.Id; - var commandLike1 = new AddLikeCommand(postId, Guid.NewGuid()); - var commandLike2 = new AddLikeCommand(postId, Guid.NewGuid()); + var commandLike1 = new AddLikeCommand(postId, Guid.NewGuid().ToString()); + var commandLike2 = new AddLikeCommand(postId, Guid.NewGuid().ToString()); var like1 = await Fixture.AddLikeCommandHandler.HandleAsync(commandLike1); var like2 = await Fixture.AddLikeCommandHandler.HandleAsync(commandLike2); @@ -84,7 +84,7 @@ public async Task HandleAsync_ShouldLimitResults_ToSpecifiedFirstParameter() var postId = post.Response.Id; - var likes = new List { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; + var likes = new List { Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), Guid.NewGuid().ToString() }; foreach (var likeUserId in likes) { var commandLike = new AddLikeCommand(postId, likeUserId); diff --git a/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs b/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs index a4b3c3b..204704c 100644 --- a/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs +++ b/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs @@ -88,7 +88,7 @@ private void ApplyMigrations() private User CreateExistingUser() { var user = new User( - Guid.NewGuid(), + Guid.NewGuid().ToString(), "First Name", "Last Name", "Username", diff --git a/backend/tests/PostService/PostService.Domain.Tests/CommentTests.cs b/backend/tests/PostService/PostService.Domain.Tests/CommentTests.cs index b21c9d5..e842202 100644 --- a/backend/tests/PostService/PostService.Domain.Tests/CommentTests.cs +++ b/backend/tests/PostService/PostService.Domain.Tests/CommentTests.cs @@ -11,7 +11,7 @@ public void Constructor_ShouldInitializeFieldsCorrectly() { // Arrange var postId = Guid.NewGuid(); - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var username = "example"; var content = "Content"; var createdAt = DateTime.UtcNow; @@ -32,7 +32,7 @@ public void Constructor_ShouldThrowArgumentException_WhenPostIdIsEmpty() { // Arrange var postId = Guid.Empty; - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var username = "example"; var content = "Content"; @@ -50,7 +50,7 @@ public void Constructor_ShouldThrowArgumentException_WhenUserIdIsEmpty() { // Arrange var postId = Guid.NewGuid(); - var userId = Guid.Empty; + var userId = string.Empty; var username = "example"; var content = "Content"; @@ -68,7 +68,7 @@ public void Constructor_ShouldThrowArgumentException_WhenUsernameIsEmpty() { // Arrange var postId = Guid.NewGuid(); - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var username = ""; var content = "Content"; @@ -86,7 +86,7 @@ public void Constructor_ShouldThrowArgumentException_WhenContentIsEmpty() { // Arrange var postId = Guid.NewGuid(); - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var username = "example"; var content = ""; diff --git a/backend/tests/PostService/PostService.Domain.Tests/LikeTests.cs b/backend/tests/PostService/PostService.Domain.Tests/LikeTests.cs index 55838dd..abc8771 100644 --- a/backend/tests/PostService/PostService.Domain.Tests/LikeTests.cs +++ b/backend/tests/PostService/PostService.Domain.Tests/LikeTests.cs @@ -11,7 +11,7 @@ public void Constructor_ShouldInitializeFieldsCorrectly() { // Arrange var postId = Guid.NewGuid(); - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var createdAt = DateTime.UtcNow; // Act @@ -28,7 +28,7 @@ public void Constructor_ShouldThrowArgumentException_WhenPostIdIsEmpty() { // Arrange var postId = Guid.Empty; - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); // Act var act = () => new Like(postId, userId); @@ -44,7 +44,7 @@ public void Constructor_ShouldThrowArgumentException_WhenUserIdIsEmpty() { // Arrange var postId = Guid.NewGuid(); - var userId = Guid.Empty; + var userId = string.Empty; // Act var act = () => new Like(postId, userId); diff --git a/backend/tests/PostService/PostService.Domain.Tests/PostTests.cs b/backend/tests/PostService/PostService.Domain.Tests/PostTests.cs index 617a111..93a3adf 100644 --- a/backend/tests/PostService/PostService.Domain.Tests/PostTests.cs +++ b/backend/tests/PostService/PostService.Domain.Tests/PostTests.cs @@ -11,7 +11,7 @@ public class PostTests public void CreateTextPost_ShouldInitializeFieldsCorrectly() { // Arrange - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var title = "Sample Title"; var description = "Sample Description"; @@ -33,7 +33,7 @@ public void CreateTextPost_ShouldInitializeFieldsCorrectly() public void CreateImagePost_ShouldInitializeFieldsCorrectly() { // Arrange - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var title = "Sample Title"; var description = "Sample Description"; var contentUrl = "https://example.com/image.jpg"; @@ -56,7 +56,7 @@ public void CreateImagePost_ShouldInitializeFieldsCorrectly() public void CreateVideoPost_ShouldInitializeFieldsCorrectly() { // Arrange - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var title = "Sample Title"; var description = "Sample Description"; var contentUrl = "https://example.com/video.mp4"; @@ -80,9 +80,10 @@ public void Update_ShouldModifyTitleAndDescription() { // Arrange var post = Post.CreateTextPost( - Guid.NewGuid(), + Guid.NewGuid().ToString(), "Old Title", - "Old Description"); + "Old Description" + ); var newTitle = "New Title"; var newDescription = "New Description"; @@ -100,9 +101,10 @@ public void IncrementLikeCount_ShouldIncreaseLikeCountByOne() { // Arrange var post = Post.CreateTextPost( - Guid.NewGuid(), + Guid.NewGuid().ToString(), "Title", - "Description"); + "Description" + ); // Act post.IncrementLikeCount(); @@ -116,9 +118,10 @@ public void DecrementLikeCount_ShouldDecreaseLikeCountByOne() { // Arrange var post = Post.CreateTextPost( - Guid.NewGuid(), + Guid.NewGuid().ToString(), "Title", - "Description"); + "Description" + ); post.IncrementLikeCount(); // Initial increment to avoid negative count @@ -134,9 +137,10 @@ public void IncrementCommentCount_ShouldIncreaseCommentCountByOne() { // Arrange var post = Post.CreateTextPost( - Guid.NewGuid(), + Guid.NewGuid().ToString(), "Title", - "Description"); + "Description" + ); // Act post.IncrementCommentCount(); @@ -150,9 +154,10 @@ public void DecrementCommentCount_ShouldDecreaseCommentCountByOne() { // Arrange var post = Post.CreateTextPost( - Guid.NewGuid(), + Guid.NewGuid().ToString(), "Title", - "Description"); + "Description" + ); post.IncrementCommentCount(); // Initial increment to avoid negative count @@ -167,7 +172,7 @@ public void DecrementCommentCount_ShouldDecreaseCommentCountByOne() public void CreateTextPost_ShouldThrowArgumentException_WhenUserIdIsEmpty() { // Arrange - var userId = Guid.Empty; + var userId = string.Empty; var title = "Title"; var description = "Description"; @@ -184,7 +189,7 @@ public void CreateTextPost_ShouldThrowArgumentException_WhenUserIdIsEmpty() public void CreateTextPost_ShouldThrowArgumentException_WhenTitleIsEmpty_ForTextContent() { // Arrange - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var title = ""; var description = "Description"; @@ -201,7 +206,7 @@ public void CreateTextPost_ShouldThrowArgumentException_WhenTitleIsEmpty_ForText public void CreateTextPost_ShouldThrowArgumentException_WhenDescriptionIsEmpty_ForTextContent() { // Arrange - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var title = "Title"; var description = ""; @@ -218,7 +223,7 @@ public void CreateTextPost_ShouldThrowArgumentException_WhenDescriptionIsEmpty_F public void CreateImagePost_ShouldThrowArgumentException_WhenContentUrlIsEmpty_ForImageContent() { // Arrange - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var title = "Title"; var description = "Description"; var contentUrl = ""; @@ -236,7 +241,7 @@ public void CreateImagePost_ShouldThrowArgumentException_WhenContentUrlIsEmpty_F public void CreateVideoPost_ShouldThrowArgumentException_WhenContentUrlIsEmpty_ForVideoContent() { // Arrange - var userId = Guid.NewGuid(); + var userId = Guid.NewGuid().ToString(); var title = "Title"; var description = "Description"; var contentUrl = ""; From 8b7cfd1501deee53733655d57c6c559ef21dffc9 Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Mon, 30 Dec 2024 00:53:33 +0100 Subject: [PATCH 02/18] Add creating post mutation --- .../GraphQL/Mutations/PostMutation.cs | 30 +++++++++++++++++++ .../Commands/AddPost/AddPostCommand.cs | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 backend/src/PostService/PostService.Api/GraphQL/Mutations/PostMutation.cs diff --git a/backend/src/PostService/PostService.Api/GraphQL/Mutations/PostMutation.cs b/backend/src/PostService/PostService.Api/GraphQL/Mutations/PostMutation.cs new file mode 100644 index 0000000..8d5d9b3 --- /dev/null +++ b/backend/src/PostService/PostService.Api/GraphQL/Mutations/PostMutation.cs @@ -0,0 +1,30 @@ +using System.Security.Claims; +using PostService.Application.Commands.AddPost; +using PostService.Application.DTOs; + +namespace PostService.Api.GraphQL.Mutations; + +public class PostMutation +{ + private readonly IHttpContextAccessor _httpContextAccessor; + + public PostMutation(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public async Task CreatePost(CreatePostDto input, [Service] AddPostCommandHandler addPostCommandHandler) + { + var userId = _httpContextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + var command = new AddPostCommand(input, userId); + + var result = await addPostCommandHandler.HandleAsync(command); + + if (!result.IsSuccess) + { + throw new GraphQLException(new Error(result.Error.Message)); + } + + return result.Response; + } +} \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/AddPost/AddPostCommand.cs b/backend/src/PostService/PostService.Application/Commands/AddPost/AddPostCommand.cs index 1c0d5a7..da40a62 100644 --- a/backend/src/PostService/PostService.Application/Commands/AddPost/AddPostCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/AddPost/AddPostCommand.cs @@ -3,4 +3,4 @@ namespace PostService.Application.Commands.AddPost; -public record AddPostCommand(CreatePostDto CreatePost, string UserId) : ICommand; \ No newline at end of file +public record AddPostCommand(CreatePostDto CreatePost, string? UserId) : ICommand; \ No newline at end of file From 76a67e7668457f0723d52c8845f01a9153ff6adb Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Mon, 30 Dec 2024 01:55:37 +0100 Subject: [PATCH 03/18] Fix GraphQL and Database config --- .../PostService.Api/GraphQL/Queries/Query.cs | 5 +- .../PostService.Api/PostService.Api.csproj | 2 + .../PostService/PostService.Api/Program.cs | 33 +++- .../PostService.Api/appsettings.json | 1 + .../Constants/AppSettingsConstants.cs | 2 +- .../DependencyInjection.cs | 52 +++-- ...0241230005249_ChangeUserIdType.Designer.cs | 184 ++++++++++++++++++ .../20241230005249_ChangeUserIdType.cs | 83 ++++++++ .../Migrations/PostDbContextModelSnapshot.cs | 20 +- 9 files changed, 347 insertions(+), 35 deletions(-) create mode 100644 backend/src/PostService/PostService.Persistence/Migrations/20241230005249_ChangeUserIdType.Designer.cs create mode 100644 backend/src/PostService/PostService.Persistence/Migrations/20241230005249_ChangeUserIdType.cs diff --git a/backend/src/PostService/PostService.Api/GraphQL/Queries/Query.cs b/backend/src/PostService/PostService.Api/GraphQL/Queries/Query.cs index d4e0f3c..7f90df2 100644 --- a/backend/src/PostService/PostService.Api/GraphQL/Queries/Query.cs +++ b/backend/src/PostService/PostService.Api/GraphQL/Queries/Query.cs @@ -2,5 +2,8 @@ namespace PostService.Api.GraphQL.Queries; public class Query { - + public string HelloWorld() + { + return "Hello, from GraphQL!"; + } } \ No newline at end of file diff --git a/backend/src/PostService/PostService.Api/PostService.Api.csproj b/backend/src/PostService/PostService.Api/PostService.Api.csproj index dc3568c..2be19ba 100644 --- a/backend/src/PostService/PostService.Api/PostService.Api.csproj +++ b/backend/src/PostService/PostService.Api/PostService.Api.csproj @@ -8,6 +8,8 @@ + + all diff --git a/backend/src/PostService/PostService.Api/Program.cs b/backend/src/PostService/PostService.Api/Program.cs index c9e747c..860bd74 100644 --- a/backend/src/PostService/PostService.Api/Program.cs +++ b/backend/src/PostService/PostService.Api/Program.cs @@ -8,12 +8,28 @@ var builder = WebApplication.CreateBuilder(args); +var allowedOrigins = builder.Configuration.GetSection(AppSettingsConstants.AllowedOrigins).Get(); var hostingUrl = builder.Configuration[AppSettingsConstants.WebHostUrl]; - var connectionString = builder.Configuration[AppSettingsConstants.DatabaseConnectionString]; builder.WebHost.UseUrls(hostingUrl ?? throw new ArgumentNullException(nameof(hostingUrl), "Hosting URL is not configured.")); +builder.Services + .AddCors(options => + { + options.AddPolicy("CorsPolicy", policyBuilder => + { + policyBuilder + .WithOrigins(allowedOrigins ?? throw new ArgumentNullException(nameof(allowedOrigins), + "Allowed Origin URLs are not configured.")) + .AllowCredentials() + .AllowAnyHeader() + .AllowAnyMethod(); + }); + }); + +builder.Services.AddHttpContextAccessor(); + builder.Services .AddPersistenceServices(connectionString) .AddInfrastructureServices() @@ -22,8 +38,11 @@ builder.Services .AddGraphQLServer() .AddQueryType() - .AddMutationType() - .AddType(new UuidType()); + .AddMutationType() + .AddType(new UuidType()) + .AddType(); + +builder.Services.AddGraphQL(); var app = builder.Build(); @@ -36,10 +55,12 @@ if (!app.Environment.IsDevelopment()) { app.UseHttpsRedirection(); -} +} + +app.UseCors("CorsPolicy"); -// app.UseAuthentication(); -// app.UseAuthorization(); +app.UseAuthentication(); +app.UseAuthorization(); app.MapGet("/health", () => Results.Ok("Healthy")); diff --git a/backend/src/PostService/PostService.Api/appsettings.json b/backend/src/PostService/PostService.Api/appsettings.json index 76b4444..5479a8c 100644 --- a/backend/src/PostService/PostService.Api/appsettings.json +++ b/backend/src/PostService/PostService.Api/appsettings.json @@ -6,6 +6,7 @@ } }, "AllowedHosts": "*", + "AllowedOrigins": [ "http://localhost:4000", "http://localhost:4200", "http://localhost:8080" ], "DatabaseConnectionString": "Host=localhost;Port=5432;Username=postgres;Password=mysecretpasswordfordevelopment;Database=PostsDb", "WebHostUrl": "http://0.0.0.0:8081" } diff --git a/backend/src/PostService/PostService.Domain/Constants/AppSettingsConstants.cs b/backend/src/PostService/PostService.Domain/Constants/AppSettingsConstants.cs index b71b3a3..76be43b 100644 --- a/backend/src/PostService/PostService.Domain/Constants/AppSettingsConstants.cs +++ b/backend/src/PostService/PostService.Domain/Constants/AppSettingsConstants.cs @@ -2,7 +2,7 @@ namespace PostService.Domain.Constants; public static class AppSettingsConstants { + public const string AllowedOrigins = "AllowedOrigins"; public const string WebHostUrl = "WebHostUrl"; - public const string DatabaseConnectionString = "DatabaseConnectionString"; } \ No newline at end of file diff --git a/backend/src/PostService/PostService.Infrastructure/DependencyInjection.cs b/backend/src/PostService/PostService.Infrastructure/DependencyInjection.cs index 576db22..d2da91a 100644 --- a/backend/src/PostService/PostService.Infrastructure/DependencyInjection.cs +++ b/backend/src/PostService/PostService.Infrastructure/DependencyInjection.cs @@ -1,3 +1,4 @@ +using System.Security.Cryptography; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; @@ -8,24 +9,39 @@ public static class DependencyInjection { public static IServiceCollection AddInfrastructureServices(this IServiceCollection services) { - // ToDo: change hard code - // services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) - // .AddJwtBearer(options => - // { - // options.Authority = "http://localhost:8080/realms/fitness-app-realm/"; - // options.Audience = "fitness-app-client"; - // options.RequireHttpsMetadata = true; - // options.TokenValidationParameters = new TokenValidationParameters - // { - // ValidateIssuer = true, - // ValidateAudience = true, - // ValidateLifetime = true, - // ValidIssuer = "http://localhost:8080/realms/fitness-app-realm/", - // ValidAudience = "fitness-app-client" - // }; - // }); - // - // services.AddAuthorization(); + var rsaSecurityKey = new RsaSecurityKey( + new RSAParameters + { + Modulus = Convert.FromBase64String("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1Q/E+u/w56fl1C67jv2glu/wjy50re4UbVqJHX+T84hN8lGjiHRxqmEgdsyArhiXK0XBbbolPJ+jLTXY7KAKXXtsCjNOV/WLCKFi9Gdn2vgrmD+g2BatpRvO33nytwlDZSkZSnFpTY3io6ZcMCB+YQK5i+2QOz1gahJt5Dac+bwZ96d3x+dEP+0lZ3+3VTe0bKWRMDked2f8E4K9mvywyUEf3Ihe/2YVhXZyUnshMrRmn6ZZ4DvpQcrHMtGMCBiB5N6pllxBu5XAcxYPRxZtx+q4GSU1bCA9es4RNgLTBGP8GQXVVqlq80j8oxR1SSigqLNbA7qcGi4+rmWg/ohdkQIDAQAB"), + Exponent = Convert.FromBase64String("AQAB") + } + ); + + // ToDo: change hard code (move to shared) + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(options => + { + options.Authority = "http://localhost:8080/realms/fitness-app-realm"; + options.Audience = "account"; + + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidIssuer = "http://localhost:8080/realms/fitness-app-realm", + ValidateAudience = true, + ValidAudience = "account", + ValidateLifetime = true, + ValidateIssuerSigningKey = true, + IssuerSigningKey = rsaSecurityKey + }; + + options.RequireHttpsMetadata = false; + }); + services.AddAuthorization(); return services; } diff --git a/backend/src/PostService/PostService.Persistence/Migrations/20241230005249_ChangeUserIdType.Designer.cs b/backend/src/PostService/PostService.Persistence/Migrations/20241230005249_ChangeUserIdType.Designer.cs new file mode 100644 index 0000000..47ea814 --- /dev/null +++ b/backend/src/PostService/PostService.Persistence/Migrations/20241230005249_ChangeUserIdType.Designer.cs @@ -0,0 +1,184 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using PostService.Persistence; + +#nullable disable + +namespace PostService.Persistence.Migrations +{ + [DbContext(typeof(PostDbContext))] + [Migration("20241230005249_ChangeUserIdType")] + partial class ChangeUserIdType + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("PostService.Domain.Entities.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("PostService.Domain.Entities.Like", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("Likes"); + }); + + modelBuilder.Entity("PostService.Domain.Entities.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CommentCount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L); + + b.Property("ContentType") + .HasColumnType("integer"); + + b.Property("ContentUrl") + .IsRequired() + .HasMaxLength(2083) + .HasColumnType("character varying(2083)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LikeCount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L); + + b.Property("Title") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("PostService.Domain.Entities.User", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ImageUrl") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("PostService.Domain.Entities.Comment", b => + { + b.HasOne("PostService.Domain.Entities.Post", null) + .WithMany() + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PostService.Domain.Entities.Like", b => + { + b.HasOne("PostService.Domain.Entities.Post", null) + .WithMany() + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/src/PostService/PostService.Persistence/Migrations/20241230005249_ChangeUserIdType.cs b/backend/src/PostService/PostService.Persistence/Migrations/20241230005249_ChangeUserIdType.cs new file mode 100644 index 0000000..aca5752 --- /dev/null +++ b/backend/src/PostService/PostService.Persistence/Migrations/20241230005249_ChangeUserIdType.cs @@ -0,0 +1,83 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PostService.Persistence.Migrations +{ + /// + public partial class ChangeUserIdType : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Id", + table: "Users", + type: "text", + nullable: false, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AlterColumn( + name: "UserId", + table: "Posts", + type: "text", + nullable: false, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AlterColumn( + name: "UserId", + table: "Likes", + type: "text", + nullable: false, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AlterColumn( + name: "UserId", + table: "Comments", + type: "text", + nullable: false, + oldClrType: typeof(Guid), + oldType: "uuid"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Id", + table: "Users", + type: "uuid", + nullable: false, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AlterColumn( + name: "UserId", + table: "Posts", + type: "uuid", + nullable: false, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AlterColumn( + name: "UserId", + table: "Likes", + type: "uuid", + nullable: false, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AlterColumn( + name: "UserId", + table: "Comments", + type: "uuid", + nullable: false, + oldClrType: typeof(string), + oldType: "text"); + } + } +} diff --git a/backend/src/PostService/PostService.Persistence/Migrations/PostDbContextModelSnapshot.cs b/backend/src/PostService/PostService.Persistence/Migrations/PostDbContextModelSnapshot.cs index db6f9d7..e247f19 100644 --- a/backend/src/PostService/PostService.Persistence/Migrations/PostDbContextModelSnapshot.cs +++ b/backend/src/PostService/PostService.Persistence/Migrations/PostDbContextModelSnapshot.cs @@ -41,8 +41,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("PostId") .HasColumnType("uuid"); - b.Property("UserId") - .HasColumnType("uuid"); + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); b.Property("Username") .IsRequired() @@ -69,8 +70,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("PostId") .HasColumnType("uuid"); - b.Property("UserId") - .HasColumnType("uuid"); + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); b.HasKey("Id"); @@ -118,8 +120,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(32) .HasColumnType("character varying(32)"); - b.Property("UserId") - .HasColumnType("uuid"); + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); b.HasKey("Id"); @@ -128,9 +131,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("PostService.Domain.Entities.User", b => { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + b.Property("Id") + .HasColumnType("text"); b.Property("CreatedAt") .HasColumnType("timestamp with time zone"); From 7948be81026330db551c6ac4aea366ccacba6539 Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Mon, 30 Dec 2024 13:19:30 +0100 Subject: [PATCH 04/18] Refactor solution structure --- FitnessApp.sln | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/FitnessApp.sln b/FitnessApp.sln index 1fa26d6..71a929b 100644 --- a/FitnessApp.sln +++ b/FitnessApp.sln @@ -30,15 +30,8 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PostService.Application.Tests", "backend\tests\PostService\PostService.Application.Tests\PostService.Application.Tests.csproj", "{5325FC87-0538-4AE1-8979-F9597F3FF466}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{D5A12D19-86E3-4E83-8BF0-D9AF8C2477F3}" - ProjectSection(SolutionItems) = preProject - .github\actions\build-and-test\action.yml = .github\actions\build-and-test\action.yml - .github\workflows\auth.yml = .github\workflows\auth.yml - .github\workflows\post.yml = .github\workflows\post.yml - .github\workflows\frontend.yml = .github\workflows\frontend.yml - .github\workflows\compose-build.yml = .github\workflows\compose-build.yml - EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution-items", "solution-items", "{CE086396-E7FB-46F7-87A9-4570DBF43597}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "items", "items", "{CE086396-E7FB-46F7-87A9-4570DBF43597}" ProjectSection(SolutionItems) = preProject .dockerignore = .dockerignore .gitignore = .gitignore @@ -66,6 +59,21 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AuthService", "backend\test EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthService.Domain.Tests", "backend\tests\AuthService\AuthService.Domain.Tests\AuthService.Domain.Tests.csproj", "{528F427F-AFA0-409E-9ED1-AD630CA56BB8}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{6EFF3C2A-91CF-4511-A60C-D542F1A939CD}" + ProjectSection(SolutionItems) = preProject + .github\workflows\auth.yml = .github\workflows\auth.yml + .github\workflows\compose-build.yml = .github\workflows\compose-build.yml + .github\workflows\frontend.yml = .github\workflows\frontend.yml + .github\workflows\post.yml = .github\workflows\post.yml + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "actions", "actions", "{499BA3B4-A81F-4079-B256-CC04927BB06D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build-and-test", "build-and-test", "{BC8EDBE4-B8BD-4934-B096-0C2E1C1E84C7}" + ProjectSection(SolutionItems) = preProject + .github\actions\build-and-test\action.yml = .github\actions\build-and-test\action.yml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -149,5 +157,8 @@ Global {C494E5BB-0B0C-43D6-82AD-27D1FC26FA29} = {C7DC7946-2C31-4266-BF89-17E15C5B5A63} {CB2BFFE4-D7CD-47E0-B42A-150DF411B7E9} = {2B7719FF-D7B4-4EFA-B3C5-2240EC19A1A5} {528F427F-AFA0-409E-9ED1-AD630CA56BB8} = {CB2BFFE4-D7CD-47E0-B42A-150DF411B7E9} + {6EFF3C2A-91CF-4511-A60C-D542F1A939CD} = {D5A12D19-86E3-4E83-8BF0-D9AF8C2477F3} + {499BA3B4-A81F-4079-B256-CC04927BB06D} = {D5A12D19-86E3-4E83-8BF0-D9AF8C2477F3} + {BC8EDBE4-B8BD-4934-B096-0C2E1C1E84C7} = {499BA3B4-A81F-4079-B256-CC04927BB06D} EndGlobalSection EndGlobal From 653030627d3c77a9454587bb0b61fb81f69d1cbe Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Mon, 30 Dec 2024 13:33:30 +0100 Subject: [PATCH 05/18] Add RabbitMQ service to Docker Compose configuration --- docker-compose.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index a98862b..2ac700a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -90,6 +90,17 @@ services: restart: always networks: - microservices + + rabittmq: + image: rabbitmq:4-management + container_name: rabbitmq + environment: + RABBITMQ_DEFAULT_USER: guest + RABBITMQ_DEFAULT_PASS: guest + ports: + - 15672:15672 + networks: + - microservices volumes: postgres-data: From 50c700e53aea14c5cc48709a6a28f3932468d04e Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Mon, 30 Dec 2024 21:59:51 +0100 Subject: [PATCH 06/18] Configure MassTransit --- .../AuthService/AuthService.Api/Program.cs | 2 +- .../AuthService.Api/appsettings.json | 5 ++++ .../AuthService.Application.csproj | 4 ++++ .../DependencyInjection.cs | 23 ++++++++++++++++++- .../Constants/AppSettingsConstants.cs | 4 ++++ .../PostService/PostService.Api/Program.cs | 2 +- .../PostService.Api/appsettings.json | 7 +++++- .../DependencyInjection.cs | 23 ++++++++++++++++++- .../PostService.Application.csproj | 1 + .../Constants/AppSettingsConstants.cs | 4 ++++ 10 files changed, 70 insertions(+), 5 deletions(-) diff --git a/backend/src/AuthService/AuthService.Api/Program.cs b/backend/src/AuthService/AuthService.Api/Program.cs index 2991b29..a4664fe 100644 --- a/backend/src/AuthService/AuthService.Api/Program.cs +++ b/backend/src/AuthService/AuthService.Api/Program.cs @@ -33,7 +33,7 @@ builder.Services .AddPersistenceServices(connectionString) .AddInfrastructureServices(builder.Configuration) - .AddApplicationServices(); + .AddApplicationServices(builder.Configuration); builder.Services .AddGraphQLServer() diff --git a/backend/src/AuthService/AuthService.Api/appsettings.json b/backend/src/AuthService/AuthService.Api/appsettings.json index 064f3c5..26869dc 100644 --- a/backend/src/AuthService/AuthService.Api/appsettings.json +++ b/backend/src/AuthService/AuthService.Api/appsettings.json @@ -17,5 +17,10 @@ "AdminUsername": "admin", "AdminPassword": "admin", "PublicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1Q/E+u/w56fl1C67jv2glu/wjy50re4UbVqJHX+T84hN8lGjiHRxqmEgdsyArhiXK0XBbbolPJ+jLTXY7KAKXXtsCjNOV/WLCKFi9Gdn2vgrmD+g2BatpRvO33nytwlDZSkZSnFpTY3io6ZcMCB+YQK5i+2QOz1gahJt5Dac+bwZ96d3x+dEP+0lZ3+3VTe0bKWRMDked2f8E4K9mvywyUEf3Ihe/2YVhXZyUnshMrRmn6ZZ4DvpQcrHMtGMCBiB5N6pllxBu5XAcxYPRxZtx+q4GSU1bCA9es4RNgLTBGP8GQXVVqlq80j8oxR1SSigqLNbA7qcGi4+rmWg/ohdkQIDAQAB" + }, + "RabbitMq": { + "Host": "http://localhost:15672", + "Username": "guest", + "Password": "guest" } } diff --git a/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj b/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj index 37bf54a..b0e6a43 100644 --- a/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj +++ b/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj @@ -13,4 +13,8 @@ + + + + diff --git a/backend/src/AuthService/AuthService.Application/DependencyInjection.cs b/backend/src/AuthService/AuthService.Application/DependencyInjection.cs index b785eed..67b81b8 100644 --- a/backend/src/AuthService/AuthService.Application/DependencyInjection.cs +++ b/backend/src/AuthService/AuthService.Application/DependencyInjection.cs @@ -7,13 +7,16 @@ using AuthService.Application.Commands.VerifyEmail; using AuthService.Application.Queries.GetUserById; using AuthService.Application.Queries.GetUserByUsername; +using AuthService.Domain.Constants; +using MassTransit; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace AuthService.Application; public static class DependencyInjection { - public static IServiceCollection AddApplicationServices(this IServiceCollection services) + public static IServiceCollection AddApplicationServices(this IServiceCollection services, IConfiguration configuration) { services.AddScoped(); services.AddScoped(); @@ -24,6 +27,24 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection services.AddScoped(); services.AddScoped(); services.AddScoped(); + + var rabbitMqHost = configuration[AppSettingsConstants.RabbitMqHost] ?? throw new ArgumentException("RabbitMQ Host is not configured."); + var rabbitMqUsername = configuration[AppSettingsConstants.RabbitMqUsername] ?? throw new ArgumentException("RabbitMQ Username is not configured."); + var rabbitMqPassword = configuration[AppSettingsConstants.RabbitMqPassword] ?? throw new ArgumentException("RabbitMQ Password is not configured."); + + services.AddMassTransit(busConfigurator => + { + busConfigurator.UsingRabbitMq((context, configurator) => + { + configurator.Host(new Uri(rabbitMqHost), host => + { + host.Username(rabbitMqUsername); + host.Password(rabbitMqPassword); + }); + + configurator.ConfigureEndpoints(context); + }); + }); return services; } diff --git a/backend/src/AuthService/AuthService.Domain/Constants/AppSettingsConstants.cs b/backend/src/AuthService/AuthService.Domain/Constants/AppSettingsConstants.cs index 3f509c5..01572f4 100644 --- a/backend/src/AuthService/AuthService.Domain/Constants/AppSettingsConstants.cs +++ b/backend/src/AuthService/AuthService.Domain/Constants/AppSettingsConstants.cs @@ -16,4 +16,8 @@ public static class AppSettingsConstants public const string AdminUsername = "AdminUsername"; public const string AdminPassword = "AdminPassword"; public const string PublicKey = "PublicKey"; + + public const string RabbitMqHost = "RabbitMq:Host"; + public const string RabbitMqUsername = "RabbitMq:Username"; + public const string RabbitMqPassword = "RabbitMq:Password"; } \ No newline at end of file diff --git a/backend/src/PostService/PostService.Api/Program.cs b/backend/src/PostService/PostService.Api/Program.cs index 860bd74..359808a 100644 --- a/backend/src/PostService/PostService.Api/Program.cs +++ b/backend/src/PostService/PostService.Api/Program.cs @@ -33,7 +33,7 @@ builder.Services .AddPersistenceServices(connectionString) .AddInfrastructureServices() - .AddApplicationServices(); + .AddApplicationServices(builder.Configuration); builder.Services .AddGraphQLServer() diff --git a/backend/src/PostService/PostService.Api/appsettings.json b/backend/src/PostService/PostService.Api/appsettings.json index 5479a8c..d2f65e7 100644 --- a/backend/src/PostService/PostService.Api/appsettings.json +++ b/backend/src/PostService/PostService.Api/appsettings.json @@ -8,5 +8,10 @@ "AllowedHosts": "*", "AllowedOrigins": [ "http://localhost:4000", "http://localhost:4200", "http://localhost:8080" ], "DatabaseConnectionString": "Host=localhost;Port=5432;Username=postgres;Password=mysecretpasswordfordevelopment;Database=PostsDb", - "WebHostUrl": "http://0.0.0.0:8081" + "WebHostUrl": "http://0.0.0.0:8081", + "RabbitMq": { + "Host": "http://localhost:15672", + "Username": "guest", + "Password": "guest" + } } diff --git a/backend/src/PostService/PostService.Application/DependencyInjection.cs b/backend/src/PostService/PostService.Application/DependencyInjection.cs index 600f502..2dd5526 100644 --- a/backend/src/PostService/PostService.Application/DependencyInjection.cs +++ b/backend/src/PostService/PostService.Application/DependencyInjection.cs @@ -1,4 +1,6 @@ using FluentValidation; +using MassTransit; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using PostService.Application.Commands.AddComment; using PostService.Application.Commands.AddLike; @@ -10,12 +12,13 @@ using PostService.Application.Queries.GetAllLikes; using PostService.Application.Queries.GetAllPosts; using PostService.Application.Queries.GetPost; +using PostService.Domain.Constants; namespace PostService.Application; public static class DependencyInjection { - public static IServiceCollection AddApplicationServices(this IServiceCollection services) + public static IServiceCollection AddApplicationServices(this IServiceCollection services, IConfiguration configuration) { services.AddValidatorsFromAssembly(typeof(DependencyInjection).Assembly); @@ -30,6 +33,24 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection services.AddScoped(); services.AddScoped(); + var rabbitMqHost = configuration[AppSettingsConstants.RabbitMqHost] ?? throw new ArgumentException("RabbitMQ Host is not configured."); + var rabbitMqUsername = configuration[AppSettingsConstants.RabbitMqUsername] ?? throw new ArgumentException("RabbitMQ Username is not configured."); + var rabbitMqPassword = configuration[AppSettingsConstants.RabbitMqPassword] ?? throw new ArgumentException("RabbitMQ Password is not configured."); + + services.AddMassTransit(busConfigurator => + { + busConfigurator.UsingRabbitMq((context, configurator) => + { + configurator.Host(new Uri(rabbitMqHost), host => + { + host.Username(rabbitMqUsername); + host.Password(rabbitMqPassword); + }); + + configurator.ConfigureEndpoints(context); + }); + }); + return services; } } \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/PostService.Application.csproj b/backend/src/PostService/PostService.Application/PostService.Application.csproj index 23e515d..345e72e 100644 --- a/backend/src/PostService/PostService.Application/PostService.Application.csproj +++ b/backend/src/PostService/PostService.Application/PostService.Application.csproj @@ -8,6 +8,7 @@ + diff --git a/backend/src/PostService/PostService.Domain/Constants/AppSettingsConstants.cs b/backend/src/PostService/PostService.Domain/Constants/AppSettingsConstants.cs index 76be43b..9cfba0a 100644 --- a/backend/src/PostService/PostService.Domain/Constants/AppSettingsConstants.cs +++ b/backend/src/PostService/PostService.Domain/Constants/AppSettingsConstants.cs @@ -5,4 +5,8 @@ public static class AppSettingsConstants public const string AllowedOrigins = "AllowedOrigins"; public const string WebHostUrl = "WebHostUrl"; public const string DatabaseConnectionString = "DatabaseConnectionString"; + + public const string RabbitMqHost = "RabbitMq:Host"; + public const string RabbitMqUsername = "RabbitMq:Username"; + public const string RabbitMqPassword = "RabbitMq:Password"; } \ No newline at end of file From 5a787509cf09e82e43fed1d9223c23da8393edeb Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Mon, 30 Dec 2024 22:20:37 +0100 Subject: [PATCH 07/18] Add Shared.DTO project and implement UserCreatedEvent for user registration --- FitnessApp.sln | 7 ++++ .../AuthService.Application.csproj | 1 + .../Register/RegisterCommandHandler.cs | 15 ++++++++- backend/src/AuthService/Dockerfile | 1 + backend/src/PostService/Dockerfile | 1 + .../DependencyInjection.cs | 3 ++ .../Events/UserCreatedEventConsumer.cs | 33 +++++++++++++++++++ .../PostService.Application.csproj | 1 + .../PostService.Domain/Entities/User.cs | 4 +-- backend/src/Shared.DTO/Shared.DTO.csproj | 9 +++++ backend/src/Shared.DTO/UserCreatedEvent.cs | 10 ++++++ .../TestFixture.cs | 4 ++- 12 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 backend/src/PostService/PostService.Application/Events/UserCreatedEventConsumer.cs create mode 100644 backend/src/Shared.DTO/Shared.DTO.csproj create mode 100644 backend/src/Shared.DTO/UserCreatedEvent.cs diff --git a/FitnessApp.sln b/FitnessApp.sln index 71a929b..de45803 100644 --- a/FitnessApp.sln +++ b/FitnessApp.sln @@ -74,6 +74,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build-and-test", "build-and .github\actions\build-and-test\action.yml = .github\actions\build-and-test\action.yml EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared.DTO", "backend\src\Shared.DTO\Shared.DTO.csproj", "{334DF17C-BD69-47B9-B4D0-ACB5AD6223CF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -136,6 +138,10 @@ Global {528F427F-AFA0-409E-9ED1-AD630CA56BB8}.Debug|Any CPU.Build.0 = Debug|Any CPU {528F427F-AFA0-409E-9ED1-AD630CA56BB8}.Release|Any CPU.ActiveCfg = Release|Any CPU {528F427F-AFA0-409E-9ED1-AD630CA56BB8}.Release|Any CPU.Build.0 = Release|Any CPU + {334DF17C-BD69-47B9-B4D0-ACB5AD6223CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {334DF17C-BD69-47B9-B4D0-ACB5AD6223CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {334DF17C-BD69-47B9-B4D0-ACB5AD6223CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {334DF17C-BD69-47B9-B4D0-ACB5AD6223CF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {2E44C019-ED30-4671-A878-D2F7B6071024} = {84AE3F00-9A59-4A8D-A737-67AB74E5D1FD} @@ -160,5 +166,6 @@ Global {6EFF3C2A-91CF-4511-A60C-D542F1A939CD} = {D5A12D19-86E3-4E83-8BF0-D9AF8C2477F3} {499BA3B4-A81F-4079-B256-CC04927BB06D} = {D5A12D19-86E3-4E83-8BF0-D9AF8C2477F3} {BC8EDBE4-B8BD-4934-B096-0C2E1C1E84C7} = {499BA3B4-A81F-4079-B256-CC04927BB06D} + {334DF17C-BD69-47B9-B4D0-ACB5AD6223CF} = {112E9C63-BF62-49C1-AD19-03855535225B} EndGlobalSection EndGlobal diff --git a/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj b/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj index b0e6a43..688eeee 100644 --- a/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj +++ b/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj @@ -7,6 +7,7 @@ + diff --git a/backend/src/AuthService/AuthService.Application/Commands/Register/RegisterCommandHandler.cs b/backend/src/AuthService/AuthService.Application/Commands/Register/RegisterCommandHandler.cs index 8a2387f..8894bfd 100644 --- a/backend/src/AuthService/AuthService.Application/Commands/Register/RegisterCommandHandler.cs +++ b/backend/src/AuthService/AuthService.Application/Commands/Register/RegisterCommandHandler.cs @@ -1,8 +1,10 @@ using AuthService.Infrastructure.Interfaces; using AuthService.Infrastructure.Models; using AuthService.Persistence; +using MassTransit; using Shared.Application.Abstractions; using Shared.Application.Common; +using Shared.DTO; namespace AuthService.Application.Commands.Register; @@ -10,11 +12,13 @@ public class RegisterCommandHandler : ICommandHandler> HandleAsync(RegisterCommand command) @@ -30,6 +34,15 @@ public async Task> HandleAsync(RegisterCom _context.Users.Add(user); await _context.SaveChangesAsync(); + await _publishEndpoint.Publish(new UserCreatedEvent( + user.Id, + user.FirstName, + user.LastName, + user.Username.Value, + user.ImageUrl, + user.CreatedAt + )); + var token = await _authService.LoginAsync(command.RegisterDto.Username, command.RegisterDto.Password); return Result.Success(token); diff --git a/backend/src/AuthService/Dockerfile b/backend/src/AuthService/Dockerfile index d87be2b..89ad510 100644 --- a/backend/src/AuthService/Dockerfile +++ b/backend/src/AuthService/Dockerfile @@ -14,6 +14,7 @@ COPY AuthService/AuthService.Domain/AuthService.Domain.csproj AuthService/AuthSe COPY AuthService/AuthService.Infrastructure/AuthService.Infrastructure.csproj AuthService/AuthService.Infrastructure/ COPY AuthService/AuthService.Persistence/AuthService.Persistence.csproj AuthService/AuthService.Persistence/ COPY Shared/Shared.Application/Shared.Application.csproj Shared/Shared.Application/ +COPY Shared/Shared.DTO/Shared.DTO.csproj Shared/Shared.DTO/ RUN dotnet restore AuthService/AuthService.Api/AuthService.Api.csproj diff --git a/backend/src/PostService/Dockerfile b/backend/src/PostService/Dockerfile index 1ce2ad6..b5de60d 100644 --- a/backend/src/PostService/Dockerfile +++ b/backend/src/PostService/Dockerfile @@ -14,6 +14,7 @@ COPY PostService/PostService.Domain/PostService.Domain.csproj PostService/PostSe COPY PostService/PostService.Infrastructure/PostService.Infrastructure.csproj PostService/PostService.Infrastructure/ COPY PostService/PostService.Persistence/PostService.Persistence.csproj PostService/PostService.Persistence/ COPY Shared/Shared.Application/Shared.Application.csproj Shared/Shared.Application/ +COPY Shared/Shared.DTO/Shared.DTO.csproj Shared/Shared.DTO/ RUN dotnet restore PostService/PostService.Api/PostService.Api.csproj diff --git a/backend/src/PostService/PostService.Application/DependencyInjection.cs b/backend/src/PostService/PostService.Application/DependencyInjection.cs index 2dd5526..7cedf1e 100644 --- a/backend/src/PostService/PostService.Application/DependencyInjection.cs +++ b/backend/src/PostService/PostService.Application/DependencyInjection.cs @@ -8,6 +8,7 @@ using PostService.Application.Commands.DeleteComment; using PostService.Application.Commands.DeleteLike; using PostService.Application.Commands.UpdatePost; +using PostService.Application.Events; using PostService.Application.Queries.GetAllComments; using PostService.Application.Queries.GetAllLikes; using PostService.Application.Queries.GetAllPosts; @@ -39,6 +40,8 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection services.AddMassTransit(busConfigurator => { + busConfigurator.AddConsumer(); + busConfigurator.UsingRabbitMq((context, configurator) => { configurator.Host(new Uri(rabbitMqHost), host => diff --git a/backend/src/PostService/PostService.Application/Events/UserCreatedEventConsumer.cs b/backend/src/PostService/PostService.Application/Events/UserCreatedEventConsumer.cs new file mode 100644 index 0000000..c477b95 --- /dev/null +++ b/backend/src/PostService/PostService.Application/Events/UserCreatedEventConsumer.cs @@ -0,0 +1,33 @@ +using MassTransit; +using PostService.Domain.Entities; +using PostService.Persistence; +using Shared.DTO; + +namespace PostService.Application.Events; + +public class UserCreatedEventConsumer : IConsumer +{ + private readonly PostDbContext _dbContext; + + public UserCreatedEventConsumer(PostDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task Consume(ConsumeContext context) + { + var @event = context.Message; + + var user = new User( + @event.Id, + @event.FirstName, + @event.LastName, + @event.Username, + @event.ImageUrl, + @event.CreatedAt + ); + + _dbContext.Add(user); + await _dbContext.SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/PostService.Application.csproj b/backend/src/PostService/PostService.Application/PostService.Application.csproj index 345e72e..35cb986 100644 --- a/backend/src/PostService/PostService.Application/PostService.Application.csproj +++ b/backend/src/PostService/PostService.Application/PostService.Application.csproj @@ -13,6 +13,7 @@ + diff --git a/backend/src/PostService/PostService.Domain/Entities/User.cs b/backend/src/PostService/PostService.Domain/Entities/User.cs index 2d52a03..45d76b3 100644 --- a/backend/src/PostService/PostService.Domain/Entities/User.cs +++ b/backend/src/PostService/PostService.Domain/Entities/User.cs @@ -9,13 +9,13 @@ public class User public string ImageUrl { get; private set; } public DateTime CreatedAt { get; private set; } - public User(string id, string firstName, string lastName, string username, string imageUrl) + public User(string id, string firstName, string lastName, string username, string imageUrl, DateTime createdAt) { Id = id; FirstName = firstName; LastName = lastName; Username = username; ImageUrl = imageUrl; - CreatedAt = DateTime.UtcNow; + CreatedAt = createdAt; } } \ No newline at end of file diff --git a/backend/src/Shared.DTO/Shared.DTO.csproj b/backend/src/Shared.DTO/Shared.DTO.csproj new file mode 100644 index 0000000..3a63532 --- /dev/null +++ b/backend/src/Shared.DTO/Shared.DTO.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/backend/src/Shared.DTO/UserCreatedEvent.cs b/backend/src/Shared.DTO/UserCreatedEvent.cs new file mode 100644 index 0000000..f7d6731 --- /dev/null +++ b/backend/src/Shared.DTO/UserCreatedEvent.cs @@ -0,0 +1,10 @@ +namespace Shared.DTO; + +public record UserCreatedEvent( + string Id, + string FirstName, + string LastName, + string Username, + string ImageUrl, + DateTime CreatedAt +); \ No newline at end of file diff --git a/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs b/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs index 204704c..6ab3231 100644 --- a/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs +++ b/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs @@ -92,7 +92,9 @@ private User CreateExistingUser() "First Name", "Last Name", "Username", - ""); + string.Empty, + DateTime.Now + ); PostDbContextFixture.Users.Add(user); PostDbContextFixture.SaveChanges(); From ab27cb9df73ccf766266c53e82538beafe80a04a Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Mon, 30 Dec 2024 22:45:51 +0100 Subject: [PATCH 08/18] Fix RabbitMq configuration --- backend/src/AuthService/AuthService.Api/appsettings.json | 2 +- .../AuthService/AuthService.Application/DependencyInjection.cs | 2 +- backend/src/PostService/PostService.Api/appsettings.json | 2 +- .../PostService/PostService.Application/DependencyInjection.cs | 2 +- docker-compose.yml | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/backend/src/AuthService/AuthService.Api/appsettings.json b/backend/src/AuthService/AuthService.Api/appsettings.json index 26869dc..398010b 100644 --- a/backend/src/AuthService/AuthService.Api/appsettings.json +++ b/backend/src/AuthService/AuthService.Api/appsettings.json @@ -19,7 +19,7 @@ "PublicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1Q/E+u/w56fl1C67jv2glu/wjy50re4UbVqJHX+T84hN8lGjiHRxqmEgdsyArhiXK0XBbbolPJ+jLTXY7KAKXXtsCjNOV/WLCKFi9Gdn2vgrmD+g2BatpRvO33nytwlDZSkZSnFpTY3io6ZcMCB+YQK5i+2QOz1gahJt5Dac+bwZ96d3x+dEP+0lZ3+3VTe0bKWRMDked2f8E4K9mvywyUEf3Ihe/2YVhXZyUnshMrRmn6ZZ4DvpQcrHMtGMCBiB5N6pllxBu5XAcxYPRxZtx+q4GSU1bCA9es4RNgLTBGP8GQXVVqlq80j8oxR1SSigqLNbA7qcGi4+rmWg/ohdkQIDAQAB" }, "RabbitMq": { - "Host": "http://localhost:15672", + "Host": "localhost", "Username": "guest", "Password": "guest" } diff --git a/backend/src/AuthService/AuthService.Application/DependencyInjection.cs b/backend/src/AuthService/AuthService.Application/DependencyInjection.cs index 67b81b8..5a0702d 100644 --- a/backend/src/AuthService/AuthService.Application/DependencyInjection.cs +++ b/backend/src/AuthService/AuthService.Application/DependencyInjection.cs @@ -36,7 +36,7 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection { busConfigurator.UsingRabbitMq((context, configurator) => { - configurator.Host(new Uri(rabbitMqHost), host => + configurator.Host(rabbitMqHost, host => { host.Username(rabbitMqUsername); host.Password(rabbitMqPassword); diff --git a/backend/src/PostService/PostService.Api/appsettings.json b/backend/src/PostService/PostService.Api/appsettings.json index d2f65e7..78e7ac5 100644 --- a/backend/src/PostService/PostService.Api/appsettings.json +++ b/backend/src/PostService/PostService.Api/appsettings.json @@ -10,7 +10,7 @@ "DatabaseConnectionString": "Host=localhost;Port=5432;Username=postgres;Password=mysecretpasswordfordevelopment;Database=PostsDb", "WebHostUrl": "http://0.0.0.0:8081", "RabbitMq": { - "Host": "http://localhost:15672", + "Host": "localhost", "Username": "guest", "Password": "guest" } diff --git a/backend/src/PostService/PostService.Application/DependencyInjection.cs b/backend/src/PostService/PostService.Application/DependencyInjection.cs index 7cedf1e..6c85e76 100644 --- a/backend/src/PostService/PostService.Application/DependencyInjection.cs +++ b/backend/src/PostService/PostService.Application/DependencyInjection.cs @@ -44,7 +44,7 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection busConfigurator.UsingRabbitMq((context, configurator) => { - configurator.Host(new Uri(rabbitMqHost), host => + configurator.Host(rabbitMqHost, host => { host.Username(rabbitMqUsername); host.Password(rabbitMqPassword); diff --git a/docker-compose.yml b/docker-compose.yml index 2ac700a..ca227c9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -98,6 +98,7 @@ services: RABBITMQ_DEFAULT_USER: guest RABBITMQ_DEFAULT_PASS: guest ports: + - 5672:5672 - 15672:15672 networks: - microservices From a3e216c3dba2b23f1d08f15cd5cfc3adf2eb1b94 Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Tue, 31 Dec 2024 11:54:45 +0100 Subject: [PATCH 09/18] Implement UserUpdatedEvent and update user handling in PostService --- .../UpdateUser/UpdateUserCommandHandler.cs | 14 ++++++++- .../UserCreatedEventConsumer.cs | 2 +- .../Consumers/UserUpdatedEventConsumer.cs | 30 +++++++++++++++++++ .../DependencyInjection.cs | 5 +++- .../PostService.Domain/Entities/User.cs | 8 +++++ backend/src/Shared.DTO/UserUpdatedEvent.cs | 9 ++++++ 6 files changed, 65 insertions(+), 3 deletions(-) rename backend/src/PostService/PostService.Application/{Events => Consumers}/UserCreatedEventConsumer.cs (94%) create mode 100644 backend/src/PostService/PostService.Application/Consumers/UserUpdatedEventConsumer.cs create mode 100644 backend/src/Shared.DTO/UserUpdatedEvent.cs diff --git a/backend/src/AuthService/AuthService.Application/Commands/UpdateUser/UpdateUserCommandHandler.cs b/backend/src/AuthService/AuthService.Application/Commands/UpdateUser/UpdateUserCommandHandler.cs index 14efe5b..98b22c0 100644 --- a/backend/src/AuthService/AuthService.Application/Commands/UpdateUser/UpdateUserCommandHandler.cs +++ b/backend/src/AuthService/AuthService.Application/Commands/UpdateUser/UpdateUserCommandHandler.cs @@ -1,9 +1,11 @@ using AuthService.Domain.Constants; using AuthService.Infrastructure.Interfaces; using AuthService.Persistence; +using MassTransit; using Microsoft.EntityFrameworkCore; using Shared.Application.Abstractions; using Shared.Application.Common; +using Shared.DTO; namespace AuthService.Application.Commands.UpdateUser; @@ -11,11 +13,13 @@ public class UpdateUserCommandHandler : ICommandHandler> HandleAsync(UpdateUserCommand command) @@ -48,6 +52,14 @@ public async Task> HandleAsync(UpdateUserCommand command) ); await _context.SaveChangesAsync(); + + await _publishEndpoint.Publish(new UserUpdatedEvent( + user.Id, + user.FirstName, + user.LastName, + user.Username.Value, + user.ImageUrl + )); return Result.Success(ResponseMessages.UserUpdatedSuccessfully); } diff --git a/backend/src/PostService/PostService.Application/Events/UserCreatedEventConsumer.cs b/backend/src/PostService/PostService.Application/Consumers/UserCreatedEventConsumer.cs similarity index 94% rename from backend/src/PostService/PostService.Application/Events/UserCreatedEventConsumer.cs rename to backend/src/PostService/PostService.Application/Consumers/UserCreatedEventConsumer.cs index c477b95..4800daf 100644 --- a/backend/src/PostService/PostService.Application/Events/UserCreatedEventConsumer.cs +++ b/backend/src/PostService/PostService.Application/Consumers/UserCreatedEventConsumer.cs @@ -3,7 +3,7 @@ using PostService.Persistence; using Shared.DTO; -namespace PostService.Application.Events; +namespace PostService.Application.Consumers; public class UserCreatedEventConsumer : IConsumer { diff --git a/backend/src/PostService/PostService.Application/Consumers/UserUpdatedEventConsumer.cs b/backend/src/PostService/PostService.Application/Consumers/UserUpdatedEventConsumer.cs new file mode 100644 index 0000000..e60edbd --- /dev/null +++ b/backend/src/PostService/PostService.Application/Consumers/UserUpdatedEventConsumer.cs @@ -0,0 +1,30 @@ +using MassTransit; +using Microsoft.EntityFrameworkCore; +using PostService.Persistence; +using Shared.DTO; + +namespace PostService.Application.Consumers; + +public class UserUpdatedEventConsumer : IConsumer +{ + private readonly PostDbContext _dbContext; + + public UserUpdatedEventConsumer(PostDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task Consume(ConsumeContext context) + { + var @event = context.Message; + + var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == @event.Id); + + user?.Update( + @event.FirstName, + @event.LastName, + @event.Username, + @event.ImageUrl + ); + } +} \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/DependencyInjection.cs b/backend/src/PostService/PostService.Application/DependencyInjection.cs index 6c85e76..54ced68 100644 --- a/backend/src/PostService/PostService.Application/DependencyInjection.cs +++ b/backend/src/PostService/PostService.Application/DependencyInjection.cs @@ -8,7 +8,7 @@ using PostService.Application.Commands.DeleteComment; using PostService.Application.Commands.DeleteLike; using PostService.Application.Commands.UpdatePost; -using PostService.Application.Events; +using PostService.Application.Consumers; using PostService.Application.Queries.GetAllComments; using PostService.Application.Queries.GetAllLikes; using PostService.Application.Queries.GetAllPosts; @@ -41,6 +41,7 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection services.AddMassTransit(busConfigurator => { busConfigurator.AddConsumer(); + busConfigurator.AddConsumer(); busConfigurator.UsingRabbitMq((context, configurator) => { @@ -50,6 +51,8 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection host.Password(rabbitMqPassword); }); + configurator.UseMessageRetry(r => r.Immediate(5)); + configurator.ConfigureEndpoints(context); }); }); diff --git a/backend/src/PostService/PostService.Domain/Entities/User.cs b/backend/src/PostService/PostService.Domain/Entities/User.cs index 45d76b3..5e45206 100644 --- a/backend/src/PostService/PostService.Domain/Entities/User.cs +++ b/backend/src/PostService/PostService.Domain/Entities/User.cs @@ -18,4 +18,12 @@ public User(string id, string firstName, string lastName, string username, strin ImageUrl = imageUrl; CreatedAt = createdAt; } + + public void Update(string? firstName, string? lastName, string? username, string? imageUrl = null) + { + FirstName = firstName ?? FirstName; + LastName = lastName ?? LastName; + Username = username ?? Username; + ImageUrl = imageUrl ?? ImageUrl; + } } \ No newline at end of file diff --git a/backend/src/Shared.DTO/UserUpdatedEvent.cs b/backend/src/Shared.DTO/UserUpdatedEvent.cs new file mode 100644 index 0000000..7c2f65a --- /dev/null +++ b/backend/src/Shared.DTO/UserUpdatedEvent.cs @@ -0,0 +1,9 @@ +namespace Shared.DTO; + +public record UserUpdatedEvent( + string Id, + string FirstName, + string LastName, + string Username, + string ImageUrl +); \ No newline at end of file From ebd69c201636034e7c3ede12cf62c96ac298c758 Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Tue, 31 Dec 2024 12:02:00 +0100 Subject: [PATCH 10/18] Add update and delete post functionality to PostMutation --- .../GraphQL/Mutations/PostMutation.cs | 32 +++++++++++++++++++ .../Commands/DeletePost/DeletePostCommand.cs | 2 +- .../Commands/UpdatePost/UpdatePostCommand.cs | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/backend/src/PostService/PostService.Api/GraphQL/Mutations/PostMutation.cs b/backend/src/PostService/PostService.Api/GraphQL/Mutations/PostMutation.cs index 8d5d9b3..9617dec 100644 --- a/backend/src/PostService/PostService.Api/GraphQL/Mutations/PostMutation.cs +++ b/backend/src/PostService/PostService.Api/GraphQL/Mutations/PostMutation.cs @@ -1,5 +1,7 @@ using System.Security.Claims; using PostService.Application.Commands.AddPost; +using PostService.Application.Commands.DeletePost; +using PostService.Application.Commands.UpdatePost; using PostService.Application.DTOs; namespace PostService.Api.GraphQL.Mutations; @@ -27,4 +29,34 @@ public async Task CreatePost(CreatePostDto input, [Service] AddPostComm return result.Response; } + + public async Task UpdatePost(UpdatePostDto input, [Service] UpdatePostCommandHandler updatePostCommandHandler) + { + var userId = _httpContextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + var command = new UpdatePostCommand(input, userId); + + var result = await updatePostCommandHandler.HandleAsync(command); + + if (!result.IsSuccess) + { + throw new GraphQLException(new Error(result.Error.Message)); + } + + return result.Response; + } + + public async Task DeletePost(Guid id, [Service] DeletePostCommandHandler deletePostCommandHandler) + { + var userId = _httpContextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + var command = new DeletePostCommand(id, userId); + + var result = await deletePostCommandHandler.HandleAsync(command); + + if (!result.IsSuccess) + { + throw new GraphQLException(new Error(result.Error.Message)); + } + + return result.Response; + } } \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/DeletePost/DeletePostCommand.cs b/backend/src/PostService/PostService.Application/Commands/DeletePost/DeletePostCommand.cs index 40da827..0b8bcd8 100644 --- a/backend/src/PostService/PostService.Application/Commands/DeletePost/DeletePostCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/DeletePost/DeletePostCommand.cs @@ -2,4 +2,4 @@ namespace PostService.Application.Commands.DeletePost; -public record DeletePostCommand(Guid Id, string UserId) : ICommand; \ No newline at end of file +public record DeletePostCommand(Guid Id, string? UserId) : ICommand; \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/UpdatePost/UpdatePostCommand.cs b/backend/src/PostService/PostService.Application/Commands/UpdatePost/UpdatePostCommand.cs index b16ecd8..eea0581 100644 --- a/backend/src/PostService/PostService.Application/Commands/UpdatePost/UpdatePostCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/UpdatePost/UpdatePostCommand.cs @@ -3,4 +3,4 @@ namespace PostService.Application.Commands.UpdatePost; -public record UpdatePostCommand(UpdatePostDto UpdatePost, string UserId) : ICommand; \ No newline at end of file +public record UpdatePostCommand(UpdatePostDto UpdatePost, string? UserId) : ICommand; \ No newline at end of file From c162da55ddfaa60746286ccdc524536eb56da8cf Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Tue, 31 Dec 2024 12:11:12 +0100 Subject: [PATCH 11/18] Add CommentMutation for creating and deleting comments --- .../GraphQL/Mutations/CommentMutation.cs | 46 +++++++++++++++++++ .../GraphQL/Mutations/Mutation.cs | 6 --- .../Commands/AddComment/AddCommentCommand.cs | 2 +- .../DeleteComment/DeleteCommentCommand.cs | 2 +- 4 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 backend/src/PostService/PostService.Api/GraphQL/Mutations/CommentMutation.cs delete mode 100644 backend/src/PostService/PostService.Api/GraphQL/Mutations/Mutation.cs diff --git a/backend/src/PostService/PostService.Api/GraphQL/Mutations/CommentMutation.cs b/backend/src/PostService/PostService.Api/GraphQL/Mutations/CommentMutation.cs new file mode 100644 index 0000000..32f3e71 --- /dev/null +++ b/backend/src/PostService/PostService.Api/GraphQL/Mutations/CommentMutation.cs @@ -0,0 +1,46 @@ +using System.Security.Claims; +using PostService.Application.Commands.AddComment; +using PostService.Application.Commands.DeleteComment; +using PostService.Application.DTOs; + +namespace PostService.Api.GraphQL.Mutations; + +public class CommentMutation +{ + private readonly IHttpContextAccessor _httpContextAccessor; + + public CommentMutation(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public async Task CreateComment(CreateCommentDto input, [Service] AddCommentCommandHandler addCommentCommandHandler) + { + var userId = _httpContextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + var command = new AddCommentCommand(input, userId); + + var result = await addCommentCommandHandler.HandleAsync(command); + + if (!result.IsSuccess) + { + throw new GraphQLException(new Error(result.Error.Message)); + } + + return result.Response; + } + + public async Task DeleteComment(Guid id, Guid postId, [Service] DeleteCommentCommandHandler deleteCommentCommandHandler) + { + var userId = _httpContextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + var command = new DeleteCommentCommand(id, postId, userId); + + var result = await deleteCommentCommandHandler.HandleAsync(command); + + if (!result.IsSuccess) + { + throw new GraphQLException(new Error(result.Error.Message)); + } + + return result.Response; + } +} \ No newline at end of file diff --git a/backend/src/PostService/PostService.Api/GraphQL/Mutations/Mutation.cs b/backend/src/PostService/PostService.Api/GraphQL/Mutations/Mutation.cs deleted file mode 100644 index fd6a4d5..0000000 --- a/backend/src/PostService/PostService.Api/GraphQL/Mutations/Mutation.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace PostService.Api.GraphQL.Mutations; - -public class Mutation -{ - -} \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/AddComment/AddCommentCommand.cs b/backend/src/PostService/PostService.Application/Commands/AddComment/AddCommentCommand.cs index f9aea13..17b3686 100644 --- a/backend/src/PostService/PostService.Application/Commands/AddComment/AddCommentCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/AddComment/AddCommentCommand.cs @@ -3,4 +3,4 @@ namespace PostService.Application.Commands.AddComment; -public record AddCommentCommand(CreateCommentDto CreateComment, string UserId) : ICommand; \ No newline at end of file +public record AddCommentCommand(CreateCommentDto CreateComment, string? UserId) : ICommand; \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/DeleteComment/DeleteCommentCommand.cs b/backend/src/PostService/PostService.Application/Commands/DeleteComment/DeleteCommentCommand.cs index c4bb0f9..8605d8f 100644 --- a/backend/src/PostService/PostService.Application/Commands/DeleteComment/DeleteCommentCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/DeleteComment/DeleteCommentCommand.cs @@ -2,4 +2,4 @@ namespace PostService.Application.Commands.DeleteComment; -public record DeleteCommentCommand(Guid Id, Guid PostId, string UserId) : ICommand; \ No newline at end of file +public record DeleteCommentCommand(Guid Id, Guid PostId, string? UserId) : ICommand; \ No newline at end of file From b6ee43a528dded4e87ca0949c2730f6b63bc3ca5 Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Tue, 31 Dec 2024 12:15:07 +0100 Subject: [PATCH 12/18] Add LikeMutation for adding and deleting likes on posts --- .../GraphQL/Mutations/LikeMutation.cs | 46 +++++++++++++++++++ .../PostService/PostService.Api/Program.cs | 3 ++ .../Commands/AddLike/AddLikeCommand.cs | 2 +- .../Commands/DeleteLike/DeleteLikeCommand.cs | 2 +- 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 backend/src/PostService/PostService.Api/GraphQL/Mutations/LikeMutation.cs diff --git a/backend/src/PostService/PostService.Api/GraphQL/Mutations/LikeMutation.cs b/backend/src/PostService/PostService.Api/GraphQL/Mutations/LikeMutation.cs new file mode 100644 index 0000000..f1ca6b1 --- /dev/null +++ b/backend/src/PostService/PostService.Api/GraphQL/Mutations/LikeMutation.cs @@ -0,0 +1,46 @@ +using System.Security.Claims; +using PostService.Application.Commands.AddLike; +using PostService.Application.Commands.DeleteLike; +using PostService.Application.DTOs; + +namespace PostService.Api.GraphQL.Mutations; + +public class LikeMutation +{ + private readonly IHttpContextAccessor _httpContextAccessor; + + public LikeMutation(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public async Task AddLike(Guid postId, [Service] AddLikeCommandHandler addLikeCommandHandler) + { + var userId = _httpContextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + var command = new AddLikeCommand(postId, userId); + + var result = await addLikeCommandHandler.HandleAsync(command); + + if (!result.IsSuccess) + { + throw new GraphQLException(new Error(result.Error.Message)); + } + + return result.Response; + } + + public async Task DeleteLike(Guid id, Guid postId, [Service] DeleteLikeCommandHandler deleteLikeCommandHandler) + { + var userId = _httpContextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + var command = new DeleteLikeCommand(id, postId, userId); + + var result = await deleteLikeCommandHandler.HandleAsync(command); + + if (!result.IsSuccess) + { + throw new GraphQLException(new Error(result.Error.Message)); + } + + return result.Response; + } +} \ No newline at end of file diff --git a/backend/src/PostService/PostService.Api/Program.cs b/backend/src/PostService/PostService.Api/Program.cs index 359808a..fe0bd24 100644 --- a/backend/src/PostService/PostService.Api/Program.cs +++ b/backend/src/PostService/PostService.Api/Program.cs @@ -3,6 +3,7 @@ using PostService.Api.GraphQL.Queries; using PostService.Application; using PostService.Domain.Constants; +using PostService.Domain.Entities; using PostService.Infrastructure; using PostService.Persistence; @@ -39,6 +40,8 @@ .AddGraphQLServer() .AddQueryType() .AddMutationType() + .AddMutationType() + .AddMutationType() .AddType(new UuidType()) .AddType(); diff --git a/backend/src/PostService/PostService.Application/Commands/AddLike/AddLikeCommand.cs b/backend/src/PostService/PostService.Application/Commands/AddLike/AddLikeCommand.cs index fac0310..ad9f071 100644 --- a/backend/src/PostService/PostService.Application/Commands/AddLike/AddLikeCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/AddLike/AddLikeCommand.cs @@ -2,4 +2,4 @@ namespace PostService.Application.Commands.AddLike; -public record AddLikeCommand(Guid PostId, string UserId) : ICommand; \ No newline at end of file +public record AddLikeCommand(Guid PostId, string? UserId) : ICommand; \ No newline at end of file diff --git a/backend/src/PostService/PostService.Application/Commands/DeleteLike/DeleteLikeCommand.cs b/backend/src/PostService/PostService.Application/Commands/DeleteLike/DeleteLikeCommand.cs index 624fc0a..81d8718 100644 --- a/backend/src/PostService/PostService.Application/Commands/DeleteLike/DeleteLikeCommand.cs +++ b/backend/src/PostService/PostService.Application/Commands/DeleteLike/DeleteLikeCommand.cs @@ -2,4 +2,4 @@ namespace PostService.Application.Commands.DeleteLike; -public record DeleteLikeCommand(Guid Id, Guid PostId, string UserId) : ICommand; \ No newline at end of file +public record DeleteLikeCommand(Guid Id, Guid PostId, string? UserId) : ICommand; \ No newline at end of file From 8b1e854bd6cc088de134547f97dc336e65a5b994 Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Tue, 31 Dec 2024 15:51:21 +0100 Subject: [PATCH 13/18] Add PostQuery for retrieving single and multiple posts --- .../GraphQL/Queries/PostQuery.cs | 37 +++++++++++++++++++ .../PostService.Api/GraphQL/Queries/Query.cs | 9 ----- .../PostService/PostService.Api/Program.cs | 2 +- 3 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 backend/src/PostService/PostService.Api/GraphQL/Queries/PostQuery.cs delete mode 100644 backend/src/PostService/PostService.Api/GraphQL/Queries/Query.cs diff --git a/backend/src/PostService/PostService.Api/GraphQL/Queries/PostQuery.cs b/backend/src/PostService/PostService.Api/GraphQL/Queries/PostQuery.cs new file mode 100644 index 0000000..7c3f1d8 --- /dev/null +++ b/backend/src/PostService/PostService.Api/GraphQL/Queries/PostQuery.cs @@ -0,0 +1,37 @@ +using PostService.Application.DTOs; +using PostService.Application.Queries.GetAllPosts; +using PostService.Application.Queries.GetPost; +using PostService.Domain.Entities; + +namespace PostService.Api.GraphQL.Queries; + +public class PostQuery +{ + public async Task GetPost(Guid id, [Service] GetPostQueryHandler getPostQueryHandler) + { + var query = new GetPostQuery(id); + + var result = await getPostQueryHandler.HandleAsync(query); + + if (!result.IsSuccess) + { + throw new GraphQLException(new Error(result.Error.Message)); + } + + return result.Response; + } + + public async Task> GetAllPost(int first, Guid lastPostId, [Service] GetAllPostsQueryHandler getAllPostsQueryHandler) + { + var query = new GetAllPostsQuery(first, lastPostId); + + var result = await getAllPostsQueryHandler.HandleAsync(query); + + if (!result.IsSuccess) + { + throw new GraphQLException(new Error(result.Error.Message)); + } + + return result.Response; + } +} \ No newline at end of file diff --git a/backend/src/PostService/PostService.Api/GraphQL/Queries/Query.cs b/backend/src/PostService/PostService.Api/GraphQL/Queries/Query.cs deleted file mode 100644 index 7f90df2..0000000 --- a/backend/src/PostService/PostService.Api/GraphQL/Queries/Query.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace PostService.Api.GraphQL.Queries; - -public class Query -{ - public string HelloWorld() - { - return "Hello, from GraphQL!"; - } -} \ No newline at end of file diff --git a/backend/src/PostService/PostService.Api/Program.cs b/backend/src/PostService/PostService.Api/Program.cs index fe0bd24..5e7369e 100644 --- a/backend/src/PostService/PostService.Api/Program.cs +++ b/backend/src/PostService/PostService.Api/Program.cs @@ -38,7 +38,7 @@ builder.Services .AddGraphQLServer() - .AddQueryType() + .AddQueryType() .AddMutationType() .AddMutationType() .AddMutationType() From f946f60bbae5f32e44d10995943ad11050637227 Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Tue, 31 Dec 2024 15:58:03 +0100 Subject: [PATCH 14/18] Add CommentQuery and LikeQuery for retrieving comments and likes --- .../GraphQL/Queries/CommentQuery.cs | 21 +++++++++++++++++++ .../GraphQL/Queries/LikeQuery.cs | 21 +++++++++++++++++++ .../PostService/PostService.Api/Program.cs | 2 ++ 3 files changed, 44 insertions(+) create mode 100644 backend/src/PostService/PostService.Api/GraphQL/Queries/CommentQuery.cs create mode 100644 backend/src/PostService/PostService.Api/GraphQL/Queries/LikeQuery.cs diff --git a/backend/src/PostService/PostService.Api/GraphQL/Queries/CommentQuery.cs b/backend/src/PostService/PostService.Api/GraphQL/Queries/CommentQuery.cs new file mode 100644 index 0000000..e7fd0b0 --- /dev/null +++ b/backend/src/PostService/PostService.Api/GraphQL/Queries/CommentQuery.cs @@ -0,0 +1,21 @@ +using PostService.Application.Queries.GetAllComments; +using PostService.Domain.Entities; + +namespace PostService.Api.GraphQL.Queries; + +public class CommentQuery +{ + public async Task> GetAllComments(Guid postId, int first, [Service] GetAllCommentsQueryHandler getAllCommentsQueryHandler) + { + var query = new GetAllCommentsQuery(postId, first); + + var result = await getAllCommentsQueryHandler.HandleAsync(query); + + if (!result.IsSuccess) + { + throw new GraphQLException(new Error(result.Error.Message)); + } + + return result.Response; + } +} \ No newline at end of file diff --git a/backend/src/PostService/PostService.Api/GraphQL/Queries/LikeQuery.cs b/backend/src/PostService/PostService.Api/GraphQL/Queries/LikeQuery.cs new file mode 100644 index 0000000..3aeb908 --- /dev/null +++ b/backend/src/PostService/PostService.Api/GraphQL/Queries/LikeQuery.cs @@ -0,0 +1,21 @@ +using PostService.Application.Queries.GetAllLikes; +using PostService.Domain.Entities; + +namespace PostService.Api.GraphQL.Queries; + +public class LikeQuery +{ + public async Task> GetAllLikes(Guid postId, int first, [Service] GetAllLikesQueryHandler getAllLikesQueryHandler) + { + var query = new GetAllLikesQuery(postId, first); + + var result = await getAllLikesQueryHandler.HandleAsync(query); + + if (!result.IsSuccess) + { + throw new GraphQLException(new Error(result.Error.Message)); + } + + return result.Response; + } +} \ No newline at end of file diff --git a/backend/src/PostService/PostService.Api/Program.cs b/backend/src/PostService/PostService.Api/Program.cs index 5e7369e..0801cc7 100644 --- a/backend/src/PostService/PostService.Api/Program.cs +++ b/backend/src/PostService/PostService.Api/Program.cs @@ -39,6 +39,8 @@ builder.Services .AddGraphQLServer() .AddQueryType() + .AddQueryType() + .AddQueryType() .AddMutationType() .AddMutationType() .AddMutationType() From a29b37b4ab5938de8b710f8d5c1555478809540e Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Tue, 31 Dec 2024 16:12:24 +0100 Subject: [PATCH 15/18] Fix project path for Shared.DTO in solution file --- FitnessApp.sln | 2 +- backend/src/{ => Shared}/Shared.DTO/Shared.DTO.csproj | 0 backend/src/{ => Shared}/Shared.DTO/UserCreatedEvent.cs | 0 backend/src/{ => Shared}/Shared.DTO/UserUpdatedEvent.cs | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename backend/src/{ => Shared}/Shared.DTO/Shared.DTO.csproj (100%) rename backend/src/{ => Shared}/Shared.DTO/UserCreatedEvent.cs (100%) rename backend/src/{ => Shared}/Shared.DTO/UserUpdatedEvent.cs (100%) diff --git a/FitnessApp.sln b/FitnessApp.sln index de45803..d1498e5 100644 --- a/FitnessApp.sln +++ b/FitnessApp.sln @@ -74,7 +74,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build-and-test", "build-and .github\actions\build-and-test\action.yml = .github\actions\build-and-test\action.yml EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared.DTO", "backend\src\Shared.DTO\Shared.DTO.csproj", "{334DF17C-BD69-47B9-B4D0-ACB5AD6223CF}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared.DTO", "backend\src\Shared\Shared.DTO\Shared.DTO.csproj", "{334DF17C-BD69-47B9-B4D0-ACB5AD6223CF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/backend/src/Shared.DTO/Shared.DTO.csproj b/backend/src/Shared/Shared.DTO/Shared.DTO.csproj similarity index 100% rename from backend/src/Shared.DTO/Shared.DTO.csproj rename to backend/src/Shared/Shared.DTO/Shared.DTO.csproj diff --git a/backend/src/Shared.DTO/UserCreatedEvent.cs b/backend/src/Shared/Shared.DTO/UserCreatedEvent.cs similarity index 100% rename from backend/src/Shared.DTO/UserCreatedEvent.cs rename to backend/src/Shared/Shared.DTO/UserCreatedEvent.cs diff --git a/backend/src/Shared.DTO/UserUpdatedEvent.cs b/backend/src/Shared/Shared.DTO/UserUpdatedEvent.cs similarity index 100% rename from backend/src/Shared.DTO/UserUpdatedEvent.cs rename to backend/src/Shared/Shared.DTO/UserUpdatedEvent.cs From d29c30f7952f835db4d534a0f8241d1bb406bff8 Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Tue, 31 Dec 2024 16:17:39 +0100 Subject: [PATCH 16/18] Fix project path for Shared.DTO in AuthService and PostService project files --- .../AuthService.Application/AuthService.Application.csproj | 2 +- .../PostService.Application/PostService.Application.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj b/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj index 688eeee..d4ec4cf 100644 --- a/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj +++ b/backend/src/AuthService/AuthService.Application/AuthService.Application.csproj @@ -7,8 +7,8 @@ - + diff --git a/backend/src/PostService/PostService.Application/PostService.Application.csproj b/backend/src/PostService/PostService.Application/PostService.Application.csproj index 35cb986..bb0d7fc 100644 --- a/backend/src/PostService/PostService.Application/PostService.Application.csproj +++ b/backend/src/PostService/PostService.Application/PostService.Application.csproj @@ -13,8 +13,8 @@ - + From 8748f2bd9e3903a8e1e6ccd0bea176955cd82329 Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Tue, 31 Dec 2024 16:28:26 +0100 Subject: [PATCH 17/18] Update test fixture to use UtcNow --- backend/src/PostService/PostService.Domain/Entities/Comment.cs | 1 - backend/src/PostService/PostService.Domain/Entities/Like.cs | 1 - backend/src/PostService/PostService.Domain/Entities/Post.cs | 1 - .../PostService/PostService.Application.Tests/TestFixture.cs | 2 +- 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/backend/src/PostService/PostService.Domain/Entities/Comment.cs b/backend/src/PostService/PostService.Domain/Entities/Comment.cs index 76cfbbb..2f1fcc8 100644 --- a/backend/src/PostService/PostService.Domain/Entities/Comment.cs +++ b/backend/src/PostService/PostService.Domain/Entities/Comment.cs @@ -35,6 +35,5 @@ public Comment(Guid postId, string userId, string username, string content) UserId = userId; Username = username; Content = content; - CreatedAt = DateTime.UtcNow; } } \ No newline at end of file diff --git a/backend/src/PostService/PostService.Domain/Entities/Like.cs b/backend/src/PostService/PostService.Domain/Entities/Like.cs index b5fb5ba..8ca2599 100644 --- a/backend/src/PostService/PostService.Domain/Entities/Like.cs +++ b/backend/src/PostService/PostService.Domain/Entities/Like.cs @@ -21,6 +21,5 @@ public Like(Guid postId, string userId) PostId = postId; UserId = userId; - CreatedAt = DateTime.UtcNow; } } \ No newline at end of file diff --git a/backend/src/PostService/PostService.Domain/Entities/Post.cs b/backend/src/PostService/PostService.Domain/Entities/Post.cs index 81857cd..6c46312 100644 --- a/backend/src/PostService/PostService.Domain/Entities/Post.cs +++ b/backend/src/PostService/PostService.Domain/Entities/Post.cs @@ -30,7 +30,6 @@ private Post(string userId, string title, string description, string contentUrl, ContentType = contentType; LikeCount = 0; CommentCount = 0; - CreatedAt = DateTime.UtcNow; } public static Post CreateTextPost(string userId, string title, string description) diff --git a/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs b/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs index 6ab3231..ca9b585 100644 --- a/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs +++ b/backend/tests/PostService/PostService.Application.Tests/TestFixture.cs @@ -93,7 +93,7 @@ private User CreateExistingUser() "Last Name", "Username", string.Empty, - DateTime.Now + DateTime.UtcNow ); PostDbContextFixture.Users.Add(user); From b270fa06c70454f885675f78fdc09df04da25204 Mon Sep 17 00:00:00 2001 From: Ivan Sentemon Date: Tue, 31 Dec 2024 16:33:10 +0100 Subject: [PATCH 18/18] Remove unnecessary CreatedAt date assertions from comment, like, and post tests --- .../tests/PostService/PostService.Domain.Tests/CommentTests.cs | 2 -- .../tests/PostService/PostService.Domain.Tests/LikeTests.cs | 2 -- .../tests/PostService/PostService.Domain.Tests/PostTests.cs | 3 --- 3 files changed, 7 deletions(-) diff --git a/backend/tests/PostService/PostService.Domain.Tests/CommentTests.cs b/backend/tests/PostService/PostService.Domain.Tests/CommentTests.cs index e842202..dea52d2 100644 --- a/backend/tests/PostService/PostService.Domain.Tests/CommentTests.cs +++ b/backend/tests/PostService/PostService.Domain.Tests/CommentTests.cs @@ -14,7 +14,6 @@ public void Constructor_ShouldInitializeFieldsCorrectly() var userId = Guid.NewGuid().ToString(); var username = "example"; var content = "Content"; - var createdAt = DateTime.UtcNow; // Act var comment = new Comment(postId, userId, username, content); @@ -24,7 +23,6 @@ public void Constructor_ShouldInitializeFieldsCorrectly() comment.UserId.Should().Be(userId); comment.Username.Should().Be(username); comment.Content.Should().Be(content); - comment.CreatedAt.Date.Should().Be(createdAt.Date); } [Fact] diff --git a/backend/tests/PostService/PostService.Domain.Tests/LikeTests.cs b/backend/tests/PostService/PostService.Domain.Tests/LikeTests.cs index abc8771..873cfc7 100644 --- a/backend/tests/PostService/PostService.Domain.Tests/LikeTests.cs +++ b/backend/tests/PostService/PostService.Domain.Tests/LikeTests.cs @@ -12,7 +12,6 @@ public void Constructor_ShouldInitializeFieldsCorrectly() // Arrange var postId = Guid.NewGuid(); var userId = Guid.NewGuid().ToString(); - var createdAt = DateTime.UtcNow; // Act var like = new Like(postId, userId); @@ -20,7 +19,6 @@ public void Constructor_ShouldInitializeFieldsCorrectly() // Assert like.PostId.Should().Be(postId); like.UserId.Should().Be(userId); - like.CreatedAt.Date.Should().Be(createdAt.Date); } [Fact] diff --git a/backend/tests/PostService/PostService.Domain.Tests/PostTests.cs b/backend/tests/PostService/PostService.Domain.Tests/PostTests.cs index 93a3adf..1fe2514 100644 --- a/backend/tests/PostService/PostService.Domain.Tests/PostTests.cs +++ b/backend/tests/PostService/PostService.Domain.Tests/PostTests.cs @@ -26,7 +26,6 @@ public void CreateTextPost_ShouldInitializeFieldsCorrectly() post.ContentType.Should().Be(ContentType.Text); post.LikeCount.Should().Be(0); post.CommentCount.Should().Be(0); - post.CreatedAt.Date.Should().Be(DateTime.UtcNow.Date); } [Fact] @@ -49,7 +48,6 @@ public void CreateImagePost_ShouldInitializeFieldsCorrectly() post.ContentType.Should().Be(ContentType.Image); post.LikeCount.Should().Be(0); post.CommentCount.Should().Be(0); - post.CreatedAt.Date.Should().Be(DateTime.UtcNow.Date); } [Fact] @@ -72,7 +70,6 @@ public void CreateVideoPost_ShouldInitializeFieldsCorrectly() post.ContentType.Should().Be(ContentType.Video); post.LikeCount.Should().Be(0); post.CommentCount.Should().Be(0); - post.CreatedAt.Date.Should().Be(DateTime.UtcNow.Date); } [Fact]