Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added GraphQL Api and Configured MassTransit between microservices #12

Merged
merged 18 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions FitnessApp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -66,6 +59,23 @@ 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
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
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -128,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}
Expand All @@ -149,5 +163,9 @@ 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}
{334DF17C-BD69-47B9-B4D0-ACB5AD6223CF} = {112E9C63-BF62-49C1-AD19-03855535225B}
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion backend/src/AuthService/AuthService.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
builder.Services
.AddPersistenceServices(connectionString)
.AddInfrastructureServices(builder.Configuration)
.AddApplicationServices();
.AddApplicationServices(builder.Configuration);

builder.Services
.AddGraphQLServer()
Expand Down
5 changes: 5 additions & 0 deletions backend/src/AuthService/AuthService.Api/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "localhost",
"Username": "guest",
"Password": "guest"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@

<ItemGroup>
<ProjectReference Include="..\..\Shared\Shared.Application\Shared.Application.csproj" />
<ProjectReference Include="..\..\Shared\Shared.DTO\Shared.DTO.csproj" />
<ProjectReference Include="..\AuthService.Domain\AuthService.Domain.csproj" />
<ProjectReference Include="..\AuthService.Infrastructure\AuthService.Infrastructure.csproj" />
<ProjectReference Include="..\AuthService.Persistence\AuthService.Persistence.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="MassTransit.RabbitMQ" Version="8.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
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;

public class RegisterCommandHandler : ICommandHandler<RegisterCommand, KeycloakTokenResponse>
{
private readonly AuthDbContext _context;
private readonly IAuthService _authService;
private readonly IPublishEndpoint _publishEndpoint;

public RegisterCommandHandler(AuthDbContext context, IAuthService authService)
public RegisterCommandHandler(AuthDbContext context, IAuthService authService, IPublishEndpoint publishEndpoint)
{
_context = context;
_authService = authService;
_publishEndpoint = publishEndpoint;
}

public async Task<IResult<KeycloakTokenResponse, Error>> HandleAsync(RegisterCommand command)
Expand All @@ -30,6 +34,15 @@ public async Task<IResult<KeycloakTokenResponse, Error>> 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<KeycloakTokenResponse>.Success(token);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
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;

public class UpdateUserCommandHandler : ICommandHandler<UpdateUserCommand, string>
{
private readonly IUserService _userService;
private readonly AuthDbContext _context;
private readonly IPublishEndpoint _publishEndpoint;

public UpdateUserCommandHandler(IUserService userService, AuthDbContext context)
public UpdateUserCommandHandler(IUserService userService, AuthDbContext context, IPublishEndpoint publishEndpoint)
{
_userService = userService;
_context = context;
_publishEndpoint = publishEndpoint;
}

public async Task<IResult<string, Error>> HandleAsync(UpdateUserCommand command)
Expand Down Expand Up @@ -48,6 +52,14 @@ public async Task<IResult<string, Error>> HandleAsync(UpdateUserCommand command)
);

await _context.SaveChangesAsync();

await _publishEndpoint.Publish(new UserUpdatedEvent(
user.Id,
user.FirstName,
user.LastName,
user.Username.Value,
user.ImageUrl
));

return Result<string>.Success(ResponseMessages.UserUpdatedSuccessfully);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<LoginCommandHandler>();
services.AddScoped<LogoutCommandHandler>();
Expand All @@ -24,6 +27,24 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection
services.AddScoped<VerifyEmailCommandHandler>();
services.AddScoped<GetUserByIdQueryHandler>();
services.AddScoped<GetUserByUsernameQueryHandler>();

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(rabbitMqHost, host =>
{
host.Username(rabbitMqUsername);
host.Password(rabbitMqPassword);
});

configurator.ConfigureEndpoints(context);
});
});

return services;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
1 change: 1 addition & 0 deletions backend/src/AuthService/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions backend/src/PostService/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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<CommentDto> 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<string> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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<LikeDto> 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<string> 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;
}
}

This file was deleted.

Loading
Loading