Skip to content

Commit 819abb9

Browse files
authored
Merge pull request #20 from InvisibleSafe/authservice-add-application-and-infrastructure-layers
AuthService: Add Application and Infrastructure layers
2 parents 8cdbf6f + af00c56 commit 819abb9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1043
-412
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
namespace AuthService.Api.Middleware;
2+
3+
public class ExceptionHandlingMiddleware
4+
{
5+
private readonly RequestDelegate _next;
6+
7+
public ExceptionHandlingMiddleware(RequestDelegate next)
8+
{
9+
_next = next;
10+
}
11+
12+
public async Task InvokeAsync(HttpContext httpContext)
13+
{
14+
try
15+
{
16+
await _next(httpContext);
17+
}
18+
catch (HttpRequestException ex)
19+
{
20+
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
21+
await httpContext.Response.WriteAsync($"HTTP Error: {ex.Message}");
22+
}
23+
catch (TaskCanceledException ex)
24+
{
25+
httpContext.Response.StatusCode = StatusCodes.Status408RequestTimeout;
26+
await httpContext.Response.WriteAsync($"Request Timeout: {ex.Message}");
27+
}
28+
catch (Exception ex)
29+
{
30+
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
31+
await httpContext.Response.WriteAsync($"Unexpected error: {ex.Message}");
32+
}
33+
}
34+
}

backend/src/AuthService/AuthService.Api/Program.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,35 @@
22
using AuthService.Domain.Constants;
33
using AuthService.Infrastructure;
44
using AuthService.Persistence;
5+
using Microsoft.AspNetCore.Diagnostics;
56
using Microsoft.EntityFrameworkCore;
67

78
var builder = WebApplication.CreateBuilder(args);
89

910
var hostingUrl = builder.Configuration[AppSettingsConstants.WebHostUrl];
10-
1111
var connectionString = builder.Configuration[AppSettingsConstants.DatabaseConnectionString];
12+
var allowedOrigins = builder.Configuration.GetSection(AppSettingsConstants.AllowedOrigins).Get<string[]>();
1213

1314
builder.WebHost.UseUrls(hostingUrl ?? throw new ArgumentNullException(nameof(hostingUrl), "Hosting URL is not configured."));
1415

16+
// ToDo: move to extension method
17+
builder.Services
18+
.AddCors(options =>
19+
{
20+
options.AddPolicy("CorsPolicy", policyBuilder =>
21+
{
22+
policyBuilder
23+
.WithOrigins(allowedOrigins ?? throw new ArgumentNullException(nameof(allowedOrigins),
24+
"Allowed Origin URLs are not configured."))
25+
.AllowCredentials()
26+
.AllowAnyHeader()
27+
.AllowAnyMethod();
28+
});
29+
});
30+
1531
builder.Services
1632
.AddPersistenceServices(connectionString)
17-
.AddInfrastructureServices()
33+
.AddInfrastructureServices(builder.Configuration)
1834
.AddApplicationServices();
1935

2036
var app = builder.Build();
@@ -25,6 +41,13 @@
2541
dbContext.Database.Migrate();
2642
}
2743

28-
app.UseHttpsRedirection();
44+
app.UseMiddleware<ExceptionHandlerMiddleware>();
45+
46+
// app.UseHttpsRedirection();
47+
48+
app.UseCors("CorsPolicy");
49+
50+
app.UseAuthentication();
51+
app.UseAuthorization();
2952

3053
app.Run();

backend/src/AuthService/AuthService.Api/appsettings.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66
}
77
},
88
"AllowedHosts": "*",
9+
"AllowedOrigins": [ "http://localhost:4000", "http://localhost:4200", "http://localhost:8080" ],
910
"DatabaseConnectionString": "Host=localhost;Port=5432;Username=postgres;Password=mysecretpasswordfordevelopment;Database=AuthDb",
10-
"WebHostUrl": "http://0.0.0.0:8082"
11+
"WebHostUrl": "http://0.0.0.0:8082",
12+
"Keycloak": {
13+
"Url": "http://localhost:8080",
14+
"Realm": "fitness-app-realm",
15+
"ClientId": "fitness-app-client",
16+
"ClientSecret": "4mTuelQIWNfLw3HGfE3xAD3Bmyb5OHWN",
17+
"AdminUsername": "admin",
18+
"AdminPassword": "admin"
19+
}
1120
}

backend/src/AuthService/AuthService.Application/AuthService.Application.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10+
<ProjectReference Include="..\..\Shared\Shared.Application\Shared.Application.csproj" />
1011
<ProjectReference Include="..\AuthService.Domain\AuthService.Domain.csproj" />
1112
<ProjectReference Include="..\AuthService.Infrastructure\AuthService.Infrastructure.csproj" />
1213
<ProjectReference Include="..\AuthService.Persistence\AuthService.Persistence.csproj" />
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
using AuthService.Application.DTOs;
2+
using Shared.Application.Abstractions;
3+
4+
namespace AuthService.Application.Commands.Login;
5+
6+
public record LoginCommand(LoginDto LoginDto) : ICommand;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using AuthService.Infrastructure.Interfaces;
2+
using Shared.Application.Abstractions;
3+
using Shared.Application.Common;
4+
5+
namespace AuthService.Application.Commands.Login;
6+
7+
public class LoginCommandHandler : ICommandHandler<LoginCommand, string>
8+
{
9+
private readonly IAuthService _authService;
10+
11+
public LoginCommandHandler(IAuthService authService)
12+
{
13+
_authService = authService;
14+
}
15+
16+
public async Task<IResult<string, Error>> HandleAsync(LoginCommand command)
17+
{
18+
var token = await _authService.LoginAsync(command.LoginDto.Username, command.LoginDto.Password);
19+
20+
return Result<string>.Success(token.AccessToken);
21+
}
22+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
using Shared.Application.Abstractions;
2+
3+
namespace AuthService.Application.Commands.Logout;
4+
5+
public record LogoutCommand(string RefreshToken) : ICommand;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using AuthService.Domain.Constants;
2+
using AuthService.Infrastructure.Interfaces;
3+
using Shared.Application.Abstractions;
4+
using Shared.Application.Common;
5+
6+
namespace AuthService.Application.Commands.Logout;
7+
8+
public class LogoutCommandHandler : ICommandHandler<LogoutCommand, string>
9+
{
10+
private readonly IAuthService _authService;
11+
12+
public LogoutCommandHandler(IAuthService authService)
13+
{
14+
_authService = authService;
15+
}
16+
17+
public async Task<IResult<string, Error>> HandleAsync(LogoutCommand command)
18+
{
19+
var result = await _authService.LogoutAsync(command.RefreshToken);
20+
21+
if (!result)
22+
{
23+
return Result<string>.Failure(new Error(ResponseMessages.ErrorDuringLogout));
24+
}
25+
26+
return Result<string>.Success(ResponseMessages.LoggedOutSuccessfully);
27+
}
28+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
using AuthService.Application.DTOs;
2+
using Shared.Application.Abstractions;
3+
4+
namespace AuthService.Application.Commands.Register;
5+
6+
public record RegisterCommand(RegisterDto RegisterDto) : ICommand;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using AuthService.Infrastructure.Interfaces;
2+
using AuthService.Persistence;
3+
using Shared.Application.Abstractions;
4+
using Shared.Application.Common;
5+
6+
namespace AuthService.Application.Commands.Register;
7+
8+
public class RegisterCommandHandler : ICommandHandler<RegisterCommand, string>
9+
{
10+
private readonly AuthDbContext _context;
11+
private readonly IAuthService _authService;
12+
13+
public RegisterCommandHandler(AuthDbContext context, IAuthService authService)
14+
{
15+
_context = context;
16+
_authService = authService;
17+
}
18+
19+
public async Task<IResult<string, Error>> HandleAsync(RegisterCommand command)
20+
{
21+
var user = await _authService.RegisterAsync(
22+
command.RegisterDto.FirstName,
23+
command.RegisterDto.LastName,
24+
command.RegisterDto.Username,
25+
command.RegisterDto.Email,
26+
command.RegisterDto.Password);
27+
28+
_context.Users.Add(user);
29+
await _context.SaveChangesAsync();
30+
31+
var token = await _authService.LoginAsync(command.RegisterDto.Username, command.RegisterDto.Password);
32+
33+
return Result<string>.Success(token.AccessToken);
34+
}
35+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
using Shared.Application.Abstractions;
2+
3+
namespace AuthService.Application.Commands.ResetPassword;
4+
5+
public record ResetPasswordCommand(string UserId, string NewPassword) : ICommand;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using AuthService.Domain.Constants;
2+
using AuthService.Infrastructure.Interfaces;
3+
using Shared.Application.Abstractions;
4+
using Shared.Application.Common;
5+
6+
namespace AuthService.Application.Commands.ResetPassword;
7+
8+
public class ResetPasswordCommandHandler : ICommandHandler<ResetPasswordCommand, string>
9+
{
10+
private readonly IUserService _userService;
11+
12+
public ResetPasswordCommandHandler(IUserService userService)
13+
{
14+
_userService = userService;
15+
}
16+
17+
public async Task<IResult<string, Error>> HandleAsync(ResetPasswordCommand command)
18+
{
19+
var result = await _userService.ResetPasswordAsync(command.UserId, command.NewPassword);
20+
21+
if (!result)
22+
{
23+
return Result<string>.Failure(new Error(ResponseMessages.ErrorDuringResetPassword));
24+
}
25+
26+
return Result<string>.Success(ResponseMessages.PasswordUpdatedSuccessfully);
27+
}
28+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
using Shared.Application.Abstractions;
2+
3+
namespace AuthService.Application.Commands.SendVerifyEmail;
4+
5+
public record SendVerifyEmailCommand(string UserId) : ICommand;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using AuthService.Application.Commands.VerifyEmail;
2+
using AuthService.Domain.Constants;
3+
using AuthService.Infrastructure.Interfaces;
4+
using AuthService.Persistence;
5+
using Microsoft.EntityFrameworkCore;
6+
using Shared.Application.Abstractions;
7+
using Shared.Application.Common;
8+
9+
namespace AuthService.Application.Commands.SendVerifyEmail;
10+
11+
public class SendVerifyEmailCommandHandler : ICommandHandler<VerifyEmailCommand, string>
12+
{
13+
private readonly AuthDbContext _context;
14+
private readonly IAuthService _authService;
15+
16+
public SendVerifyEmailCommandHandler(AuthDbContext context, IAuthService authService)
17+
{
18+
_context = context;
19+
_authService = authService;
20+
}
21+
22+
public async Task<IResult<string, Error>> HandleAsync(VerifyEmailCommand command)
23+
{
24+
var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == command.UserId);
25+
26+
if (user == null)
27+
{
28+
return Result<string>.Failure(new Error(ResponseMessages.UserNotFound));
29+
}
30+
31+
var result = await _authService.SendVerifyEmailAsync(command.UserId);
32+
33+
if (!result)
34+
{
35+
return Result<string>.Failure(new Error(ResponseMessages.ErrorDuringSendVerifyEmail));
36+
}
37+
38+
return Result<string>.Success(ResponseMessages.EmailVerificationSentSuccessfully);
39+
}
40+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
using AuthService.Application.DTOs;
2+
using Shared.Application.Abstractions;
3+
4+
namespace AuthService.Application.Commands.UpdateUser;
5+
6+
public record UpdateUserCommand(UpdateUserDto UpdateUserDto, string Id) : ICommand;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using AuthService.Domain.Constants;
2+
using AuthService.Infrastructure.Interfaces;
3+
using AuthService.Persistence;
4+
using Microsoft.EntityFrameworkCore;
5+
using Shared.Application.Abstractions;
6+
using Shared.Application.Common;
7+
8+
namespace AuthService.Application.Commands.UpdateUser;
9+
10+
public class UpdateUserCommandHandler : ICommandHandler<UpdateUserCommand, string>
11+
{
12+
private readonly IUserService _userService;
13+
private readonly AuthDbContext _context;
14+
15+
public UpdateUserCommandHandler(IUserService userService, AuthDbContext context)
16+
{
17+
_userService = userService;
18+
_context = context;
19+
}
20+
21+
public async Task<IResult<string, Error>> HandleAsync(UpdateUserCommand command)
22+
{
23+
var updatedUser = await _userService.UpdateAsync(
24+
command.Id,
25+
command.UpdateUserDto.FirstName,
26+
command.UpdateUserDto.LastName,
27+
command.UpdateUserDto.Username,
28+
command.UpdateUserDto.Email
29+
);
30+
31+
var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == updatedUser.Id);
32+
33+
if (user == null)
34+
{
35+
return Result<string>.Failure(new Error(ResponseMessages.UserNotFound));
36+
}
37+
38+
user.Update(
39+
command.UpdateUserDto.FirstName,
40+
command.UpdateUserDto.LastName,
41+
command.UpdateUserDto.Username,
42+
command.UpdateUserDto.Email
43+
);
44+
45+
await _context.SaveChangesAsync();
46+
47+
return Result<string>.Success(ResponseMessages.UserUpdatedSuccessfully);
48+
}
49+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
using Shared.Application.Abstractions;
2+
3+
namespace AuthService.Application.Commands.VerifyEmail;
4+
5+
public record VerifyEmailCommand(string UserId) : ICommand;

0 commit comments

Comments
 (0)