119 lines
4.2 KiB
C#
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);
|
||
|
}
|
||
|
}
|