2025-03-04 17:13:02 +01:00
|
|
|
using Insight.Database;
|
2025-03-10 15:56:22 +01:00
|
|
|
using Npgsql;
|
2026-01-09 22:14:46 +01:00
|
|
|
using PlanTempus.Components.Accounts.Exceptions;
|
2025-03-04 17:13:02 +01:00
|
|
|
using PlanTempus.Core;
|
2025-03-12 00:13:53 +01:00
|
|
|
using PlanTempus.Core.CommandQueries;
|
2025-03-10 15:56:22 +01:00
|
|
|
using PlanTempus.Core.Database;
|
2026-01-10 11:13:33 +01:00
|
|
|
using PlanTempus.Core.Outbox;
|
2025-03-04 17:13:02 +01:00
|
|
|
|
2026-01-09 22:14:46 +01:00
|
|
|
namespace PlanTempus.Components.Accounts.Create
|
2025-03-04 17:13:02 +01:00
|
|
|
{
|
2026-01-09 22:14:46 +01:00
|
|
|
public class CreateAccountHandler(
|
2025-03-06 00:05:58 +01:00
|
|
|
IDatabaseOperations databaseOperations,
|
2026-01-10 11:13:33 +01:00
|
|
|
ISecureTokenizer secureTokenizer,
|
|
|
|
|
IOutboxService outboxService) : ICommandHandler<CreateAccountCommand>
|
2025-03-04 23:54:55 +01:00
|
|
|
{
|
2026-01-09 22:14:46 +01:00
|
|
|
public async Task<CommandResponse> Handle(CreateAccountCommand command)
|
2025-03-04 23:54:55 +01:00
|
|
|
{
|
2026-01-09 22:14:46 +01:00
|
|
|
using var db = databaseOperations.CreateScope(nameof(CreateAccountHandler));
|
2026-01-10 11:13:33 +01:00
|
|
|
using var transaction = db.Connection.BeginTransaction();
|
|
|
|
|
|
2025-03-04 23:54:55 +01:00
|
|
|
try
|
|
|
|
|
{
|
2026-01-10 11:13:33 +01:00
|
|
|
var securityStamp = Guid.NewGuid().ToString("N");
|
|
|
|
|
|
2025-03-04 23:54:55 +01:00
|
|
|
var sql = @"
|
2026-01-10 11:13:33 +01:00
|
|
|
INSERT INTO system.accounts(email, password_hash, security_stamp, email_confirmed,
|
|
|
|
|
access_failed_count, lockout_enabled, is_active)
|
2025-03-04 17:13:02 +01:00
|
|
|
VALUES(@Email, @PasswordHash, @SecurityStamp, @EmailConfirmed,
|
2025-03-04 23:54:55 +01:00
|
|
|
@AccessFailedCount, @LockoutEnabled, @IsActive)
|
|
|
|
|
RETURNING id, created_at, email, is_active";
|
2025-03-04 17:13:02 +01:00
|
|
|
|
2025-06-26 21:30:32 +02:00
|
|
|
await db.Connection.QuerySqlAsync(sql, new
|
2025-03-04 23:54:55 +01:00
|
|
|
{
|
2025-03-12 00:13:53 +01:00
|
|
|
command.Email,
|
2025-03-04 23:54:55 +01:00
|
|
|
PasswordHash = secureTokenizer.TokenizeText(command.Password),
|
2026-01-10 11:13:33 +01:00
|
|
|
SecurityStamp = securityStamp,
|
2025-03-04 23:54:55 +01:00
|
|
|
EmailConfirmed = false,
|
|
|
|
|
AccessFailedCount = 0,
|
|
|
|
|
LockoutEnabled = false,
|
2025-03-12 00:13:53 +01:00
|
|
|
command.IsActive,
|
2025-03-04 23:54:55 +01:00
|
|
|
});
|
2026-01-09 22:14:46 +01:00
|
|
|
|
2026-01-10 11:13:33 +01:00
|
|
|
await outboxService.EnqueueAsync(
|
|
|
|
|
OutboxMessageTypes.VerificationEmail,
|
|
|
|
|
new VerificationEmailPayload
|
|
|
|
|
{
|
|
|
|
|
Email = command.Email,
|
|
|
|
|
UserName = command.Email,
|
|
|
|
|
Token = securityStamp
|
|
|
|
|
},
|
|
|
|
|
db.Connection,
|
|
|
|
|
transaction);
|
|
|
|
|
|
|
|
|
|
transaction.Commit();
|
2025-03-12 18:30:40 +01:00
|
|
|
return new CommandResponse(command.CorrelationId, command.GetType().Name, command.TransactionId);
|
2025-03-04 23:54:55 +01:00
|
|
|
}
|
2026-01-09 22:14:46 +01:00
|
|
|
catch (PostgresException ex) when (ex.SqlState == "23505" && ex.ConstraintName.Equals("accounts_email_key", StringComparison.InvariantCultureIgnoreCase))
|
2025-03-10 15:56:22 +01:00
|
|
|
{
|
2026-01-10 11:13:33 +01:00
|
|
|
transaction.Rollback();
|
2025-03-10 15:56:22 +01:00
|
|
|
db.Error(ex);
|
|
|
|
|
throw new EmailAlreadyRegistreredException();
|
|
|
|
|
}
|
2025-03-04 23:54:55 +01:00
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2026-01-10 11:13:33 +01:00
|
|
|
transaction.Rollback();
|
2025-03-04 23:54:55 +01:00
|
|
|
db.Error(ex);
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-09 22:14:46 +01:00
|
|
|
}
|