Register endpoint finished
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
namespace TimetableDesigner.Backend.Services.Authentication.DTO.API;
|
||||
|
||||
public class RegisterRequest
|
||||
{
|
||||
public string Email { get; set; } = null!;
|
||||
public string Password { get; set; } = null!;
|
||||
public string PasswordConfirmation { get; set; } = null!;
|
||||
}
|
||||
public record RegisterRequest(
|
||||
string Email,
|
||||
string Password,
|
||||
string PasswordConfirmation
|
||||
);
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace TimetableDesigner.Backend.Services.Authentication.DTO.API;
|
||||
|
||||
public class RegisterResponse
|
||||
{
|
||||
|
||||
}
|
||||
public record RegisterResponse(
|
||||
long Id,
|
||||
string Email
|
||||
);
|
||||
@@ -1,5 +1,8 @@
|
||||
using MediatR;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register;
|
||||
using TimetableDesigner.Backend.Services.Authentication.DTO.API;
|
||||
|
||||
@@ -10,6 +13,10 @@ public static class Endpoints
|
||||
public static IEndpointRouteBuilder MapEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
app.MapPost("/register", Register)
|
||||
.AllowAnonymous()
|
||||
.Produces<RegisterResponse>(201)
|
||||
.Produces<HttpValidationProblemDetails>(400)
|
||||
.Produces(500)
|
||||
.WithName("Register");
|
||||
app.MapPost("/authenticate_password", AuthenticatePassword)
|
||||
.WithName("AuthenticatePassword");
|
||||
@@ -19,19 +26,27 @@ public static class Endpoints
|
||||
return app;
|
||||
}
|
||||
|
||||
public static async Task<Results<Created<RegisterResponse>, InternalServerError>> Register(RegisterRequest request, CancellationToken cancellationToken, IMediator mediator)
|
||||
private static async Task<Results<Created<RegisterResponse>, ValidationProblem>> Register(IMediator mediator, IValidator<RegisterRequest> validator, RegisterRequest request)
|
||||
{
|
||||
RegisterCommand registerCommand = request.ToCommand();
|
||||
RegisterData data = await mediator.Send(registerCommand, cancellationToken);
|
||||
return Results.Created<RegisterResponse>($"accounts/0", null);
|
||||
ValidationResult validationResult = await validator.ValidateAsync(request);
|
||||
if (!validationResult.IsValid)
|
||||
{
|
||||
return TypedResults.ValidationProblem(validationResult.ToDictionary());
|
||||
}
|
||||
|
||||
public static async Task<Results<Ok<AuthenticateResponse>, ProblemHttpResult>> AuthenticatePassword(AuthenticatePasswordRequest request, CancellationToken cancellationToken)
|
||||
RegisterCommand registerCommand = request.ToCommand();
|
||||
RegisterResult result = await mediator.Send(registerCommand);
|
||||
RegisterResponse response = result.ToResponse();
|
||||
|
||||
return TypedResults.Created($"accounts/{response.Id}", response);
|
||||
}
|
||||
|
||||
public static async Task<Results<Ok<AuthenticateResponse>, ProblemHttpResult>> AuthenticatePassword(AuthenticatePasswordRequest request)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<Results<Ok<AuthenticateResponse>, ProblemHttpResult>> AuthenticateToken(AuthenticateTokenRequest request, CancellationToken cancellationToken)
|
||||
public static async Task<Results<Ok<AuthenticateResponse>, ProblemHttpResult>> AuthenticateToken(AuthenticateTokenRequest request)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -2,4 +2,7 @@
|
||||
|
||||
namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register;
|
||||
|
||||
public record RegisterCommand(string Email, string Password) : IRequest<RegisterData>;
|
||||
public record RegisterCommand(
|
||||
string Email,
|
||||
string Password
|
||||
) : IRequest<RegisterResult>;
|
||||
@@ -1,10 +1,11 @@
|
||||
using MediatR;
|
||||
using TimetableDesigner.Backend.Services.Authentication.Application.Helpers;
|
||||
using TimetableDesigner.Backend.Services.Authentication.Database;
|
||||
using TimetableDesigner.Backend.Services.Authentication.Database.Model;
|
||||
|
||||
namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register;
|
||||
|
||||
public class RegisterHandler : IRequestHandler<RegisterCommand, RegisterData>
|
||||
public class RegisterHandler : IRequestHandler<RegisterCommand, RegisterResult>
|
||||
{
|
||||
private readonly DatabaseContext _databaseContext;
|
||||
private readonly IPasswordHasher _passwordHasher;
|
||||
@@ -15,9 +16,22 @@ public class RegisterHandler : IRequestHandler<RegisterCommand, RegisterData>
|
||||
_passwordHasher = passwordHasher;
|
||||
}
|
||||
|
||||
public async Task<RegisterData> Handle(RegisterCommand command, CancellationToken cancellationToken)
|
||||
public async Task<RegisterResult> Handle(RegisterCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
PasswordHashData hash = _passwordHasher.CreateHash(command.Password);
|
||||
|
||||
Account account = new Account
|
||||
{
|
||||
Email = command.Email,
|
||||
Password = hash.Hash,
|
||||
PasswordSalt = hash.Salt,
|
||||
};
|
||||
await _databaseContext.Accounts.AddAsync(account, cancellationToken);
|
||||
await _databaseContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Publish event (probably in transaction)
|
||||
|
||||
RegisterResult result = account.ToResult();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using TimetableDesigner.Backend.Services.Authentication.DTO.API;
|
||||
using TimetableDesigner.Backend.Services.Authentication.Database.Model;
|
||||
using TimetableDesigner.Backend.Services.Authentication.DTO.API;
|
||||
|
||||
namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register;
|
||||
|
||||
@@ -6,4 +7,10 @@ public static class RegisterMappers
|
||||
{
|
||||
public static RegisterCommand ToCommand(this RegisterRequest request) =>
|
||||
new RegisterCommand(request.Email, request.Password);
|
||||
|
||||
public static RegisterResult ToResult(this Account account) =>
|
||||
new RegisterResult(account.Id, account.Email);
|
||||
|
||||
public static RegisterResponse ToResponse(this RegisterResult result) =>
|
||||
new RegisterResponse(result.Id, result.Email);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register;
|
||||
|
||||
public class RegisterData
|
||||
{
|
||||
|
||||
}
|
||||
public record RegisterResult(
|
||||
long Id,
|
||||
string Email
|
||||
);
|
||||
@@ -23,11 +23,7 @@ public class AccountConfiguration : IEntityTypeConfiguration<Account>
|
||||
.HasMaxLength(1000)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(x => x.PasswordSaltLeft)
|
||||
.HasMaxLength(20)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(x => x.PasswordSaltRight)
|
||||
builder.Property(x => x.PasswordSalt)
|
||||
.HasMaxLength(20)
|
||||
.IsRequired();
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@ public class Account
|
||||
public long Id { get; set; }
|
||||
public string Email { get; set; } = null!;
|
||||
public byte[] Password { get; set; } = null!;
|
||||
public string PasswordSaltLeft { get; set; } = null!;
|
||||
public string PasswordSaltRight { get; set; } = null!;
|
||||
public string PasswordSalt { get; set; } = null!;
|
||||
public uint Version { get; set; }
|
||||
|
||||
public virtual IEnumerable<RefreshToken> RefreshTokens { get; set; } = new List<RefreshToken>();
|
||||
|
||||
Reference in New Issue
Block a user