galaeth-draft/Galaeth.Services/Services/UserService.cs
2024-11-17 09:31:01 +00:00

119 lines
4.2 KiB
C#

using AutoMapper;
using FluentValidation;
using Galaeth.Core.Constants;
using Galaeth.Core.Dtos;
using Galaeth.Core.Entities;
using Galaeth.Core.Extensions;
using Galaeth.Core.RepositoryInterfaces;
using Galaeth.Services.Configuration;
using Galaeth.Services.Dtos;
using Galaeth.Services.Exceptions;
using Galaeth.Services.Interfaces;
using Galaeth.Services.Validators;
using Injectio.Attributes;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Galaeth.Services.Services;
/// <inheritdoc/>
[RegisterScoped]
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
private readonly ICryptographyService _cryptographyService;
private readonly IMapper _mapper;
private readonly IValidator<CreateUserDto> _createUserValidator;
private readonly RegistrationConfiguration _registrationConfiguration;
private readonly ILogger<UserService> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="UserService"/> class.
/// </summary>
/// <param name="userRepository">Instance of <see cref="IUserRepository"/>.</param>
/// <param name="cryptographyService">Instance of <see cref="ICryptographyService"/>.</param>
/// <param name="mapper">Instance of <see cref="IMapper"/>.</param>
/// <param name="createUserValidator">Instance of <see cref="CreateUserValidator"/>.</param>
/// <param name="registrationConfig">Instance of <see cref="IOptions{RegistrationConfiguration}"/>.</param>
/// <param name="logger">Instance of <see cref="ILogger"/>.</param>
public UserService(
IUserRepository userRepository,
ICryptographyService cryptographyService,
IMapper mapper,
IValidator<CreateUserDto> createUserValidator,
IOptions<RegistrationConfiguration> registrationConfig,
ILogger<UserService> logger)
{
_userRepository = userRepository;
_cryptographyService = cryptographyService;
_mapper = mapper;
_createUserValidator = createUserValidator;
_registrationConfiguration = registrationConfig.Value;
_logger = logger;
}
/// <inheritdoc/>
public async Task<UserDto> CreateNewUser(CreateUserDto createUser)
{
createUser.Username = createUser.Username.ToLower();
createUser.Email = createUser.Email.ToLowerInvariant();
await _createUserValidator.ValidateAndThrowAsync(createUser);
// Check if username is already taken.
var existingUser = await _userRepository.FindByUsername(createUser.Username);
if (existingUser is not null)
{
throw new UsernameTakenException(createUser.Username);
}
// Check if email already registered.
existingUser = await _userRepository.FindByEmailAddress(createUser.Email);
if (existingUser is not null)
{
throw new EmailAlreadyRegisteredException();
}
var user = new User()
{
Id = Guid.NewGuid(),
Username = createUser.Username,
EmailAddress = createUser.Email,
CreatedAt = DateTime.Now,
CreatorIp = createUser.IpAddress.ToString(),
State = UserState.AwaitingEmailActivation,
Role = UserRole.Normal,
};
var salt = _cryptographyService.GenerateSalt();
var hash = _cryptographyService.HashPassword(createUser.Password, salt);
user.PasswordHash = Convert.ToBase64String(hash);
user.PasswordSalt = Convert.ToBase64String(salt);
_logger.LogInformation("Creating new user {username} ({email}) [{id}]", user.Username, user.EmailAddress.MaskEmailAddress(), user.Id);
if (!_registrationConfiguration.RequireEmailActivation || createUser.ActivateImmediately)
{
user.State = UserState.Normal;
}
await _userRepository.AddAsync(user);
return _mapper.Map<UserDto>(user);
}
/// <inheritdoc/>
public async Task<UserDto> FindById(string userId)
{
if (!Guid.TryParse(userId, out var userGuid))
{
return null;
}
var user = await _userRepository.FindByIdAsync(userGuid);
return _mapper.Map<UserDto>(user);
}
}