namespace Application.Students.Commands; using System.Security.Cryptography; using Application.Auth; using Application.Students.DTOs; using Domain.Entities; using Domain.Ports.Repositories; using Domain.ValueObjects; using MediatR; using Microsoft.Extensions.Configuration; public record CreateStudentCommand(string Name, string Email, string? BaseUrl = null) : IRequest; public class CreateStudentHandler( IStudentRepository studentRepository, IPasswordService passwordService, IUnitOfWork unitOfWork, IConfiguration configuration) : IRequestHandler { private static readonly TimeSpan ActivationExpiration = TimeSpan.FromHours(48); public async Task Handle(CreateStudentCommand request, CancellationToken ct) { var email = Email.Create(request.Email); var student = new Student(request.Name, email); // Generate activation code var activationCode = GenerateActivationCode(); var codeHash = passwordService.HashPassword(activationCode); student.SetActivationCode(codeHash, ActivationExpiration); studentRepository.Add(student); await unitOfWork.SaveChangesAsync(ct); var baseUrl = request.BaseUrl ?? configuration["App:BaseUrl"] ?? "http://localhost:4200"; var activationUrl = $"{baseUrl}/activate?code={activationCode}"; var studentDto = new StudentDto(student.Id, student.Name, student.Email.Value, 0, []); return new CreateStudentResult( studentDto, activationCode, activationUrl, student.ActivationExpiresAt!.Value); } private static string GenerateActivationCode() { const string chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; var bytes = RandomNumberGenerator.GetBytes(12); return new string(bytes.Select(b => chars[b % chars.Length]).ToArray()); } }