Files
admin/Azaion.Services/UserService.cs
T
2025-02-26 16:02:09 +02:00

108 lines
4.5 KiB
C#

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<User> ValidateUser(LoginRequest request, CancellationToken cancellationToken = default);
Task<User?> GetById(Guid? id, CancellationToken cancellationToken = default);
Task<User?> GetByEmail(string email, CancellationToken cancellationToken = default);
Task UpdateHardware(string email, HardwareInfo hardwareInfo, CancellationToken cancellationToken = default);
Task<IEnumerable<User>> GetUsers(string? searchEmail, RoleEnum? searchRole, CancellationToken cancellationToken);
Task<string> CheckHardwareHash(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<User?> 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<User?> GetByEmail(string email, CancellationToken cancellationToken = default) =>
await dbFactory.Run(async db =>
await db.Users.FirstOrDefaultAsync(x => x.Email == email, cancellationToken));
public async Task<User> 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
}, token: cancellationToken);
});
cache.Invalidate(User.GetCacheKey(email));
}
public async Task<IEnumerable<User>> 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<string> CheckHardwareHash(User user, GetResourceRequest request)
{
var requestHWHash = Security.GetHWHash(request.Hardware);
//For the new users Hardware would be empty, fill it with actual hardware on the very first request
if (string.IsNullOrEmpty(user.Hardware))
{
await UpdateHardware(user.Email, request.Hardware);
cache.Invalidate(User.GetCacheKey(user.Email));
return requestHWHash;
}
var userHW = JsonConvert.DeserializeObject<HardwareInfo>(user.Hardware);
var userHWHash = Security.GetHWHash(userHW!);
if (userHWHash != requestHWHash)
throw new BusinessException(ExceptionEnum.HardwareIdMismatch);
return userHWHash;
}
}