using Azaion.Common; using Azaion.Common.Database; using Azaion.Common.Entities; using Azaion.Common.Extensions; using Azaion.Common.Requests; using LinqToDB; using Newtonsoft.Json; namespace Azaion.Services; public interface IUserService { Task RegisterUser(RegisterUserRequest request, CancellationToken cancellationToken = default); Task ValidateUser(LoginRequest request, CancellationToken cancellationToken = default); Task GetById(Guid? id, CancellationToken cancellationToken = default); Task GetByEmail(string email, CancellationToken cancellationToken = default); Task UpdateHardware(string email, HardwareInfo hardwareInfo, CancellationToken cancellationToken = default); Task> GetUsers(string? searchEmail, RoleEnum? searchRole, CancellationToken cancellationToken); Task CheckHardware(User user, GetResourceRequest request); } public class UserService(IDbFactory dbFactory, ICache cache) : IUserService { public async Task RegisterUser(RegisterUserRequest request, CancellationToken cancellationToken = default) { await dbFactory.RunAdmin(async db => { var existingUser = await db.Users.FirstOrDefaultAsync(u => u.Email == request.Email, token: cancellationToken); if (existingUser != null) throw new BusinessException(ExceptionEnum.EmailExists); await db.InsertAsync(new User { Id = Guid.NewGuid(), Email = request.Email, PasswordHash = request.Password.ToHash(), Role = request.Role }, token: cancellationToken); }); } public async Task GetById(Guid? id, CancellationToken cancellationToken = default) => await cache.GetFromCacheAsync($"{nameof(User)}.{id}", async () => await dbFactory.Run(async db => await db.Users.FirstOrDefaultAsync(x => x.Id == id, cancellationToken)), TimeSpan.FromHours(2)); public async Task GetByEmail(string email, CancellationToken cancellationToken = default) => await dbFactory.Run(async db => await db.Users.FirstOrDefaultAsync(x => x.Email == email, cancellationToken)); public async Task ValidateUser(LoginRequest request, CancellationToken cancellationToken = default) => await dbFactory.Run(async db => { var user = await db.Users.FirstOrDefaultAsync(x => x.Email == request.Email, token: cancellationToken); if (user == null) throw new BusinessException(ExceptionEnum.NoEmailFound); if (request.Password.ToHash() != user.PasswordHash) throw new BusinessException(ExceptionEnum.WrongPassword); return user; }); public async Task UpdateHardware(string email, HardwareInfo hardware, CancellationToken cancellationToken = default) => await dbFactory.RunAdmin(async db => { var hardwareStr = JsonConvert.SerializeObject(hardware); await db.Users.UpdateAsync(x => x.Email == email, u => new User { Hardware = hardwareStr, HardwareHash = hardware.Hash }, token: cancellationToken); }); public async Task> GetUsers(string? searchEmail, RoleEnum? searchRole, CancellationToken cancellationToken) => await dbFactory.Run(async db => await db.Users .WhereIf(!string.IsNullOrEmpty(searchEmail), u => u.Email.ToLower().Contains(searchEmail!.ToLower())) .WhereIf(searchRole != null, u => u.Role == searchRole) .ToListAsync(token: cancellationToken)); public async Task CheckHardware(User user, GetResourceRequest request) { if (string.IsNullOrEmpty(user.HardwareHash)) { await UpdateHardware(user.Email, request.Hardware); user.HardwareHash = request.Hardware.Hash; } var hwHash = await dbFactory.Run(async db => await db.Users .Where(x => x.Email == user.Email) .Select(x => x.HardwareHash) .FirstOrDefaultAsync()); if (hwHash != user.HardwareHash) user.HardwareHash = hwHash; if (user.HardwareHash != request.Hardware.Hash) throw new BusinessException(ExceptionEnum.HardwareIdMismatch); } }