Files
mmorales.photo/back/context/UserContext.cs
2025-08-15 20:03:07 +02:00

142 lines
4.3 KiB
C#

using back.DataModels;
using back.services.Crypto;
using Microsoft.EntityFrameworkCore;
using System.Net;
namespace back.context;
public class UserContext : DbContext
{
public record HttpErrorMap(HttpStatusCode Code, string Description);
public static class Errors
{
public static readonly HttpErrorMap Unauthorized =
new(HttpStatusCode.Unauthorized, "Invalid user data. Email or password are wrong.");
public static readonly HttpErrorMap BadRequest =
new(HttpStatusCode.BadRequest, "Missing user data.");
}
public DbSet<UserModel> Users { get; set; }
private readonly ICryptoService _cryptoService;
public UserContext(
DbContextOptions<UserContext> options,
ICryptoService cryptoService
) : base(options)
{
_cryptoService = cryptoService ?? throw new ArgumentNullException(nameof(cryptoService));
// Ensure database is created
Database.EnsureCreated();
}
public async Task<UserModel?> Create(string clientId, UserModel user)
{
ArgumentNullException.ThrowIfNull(user);
if (await Exists(user))
{
return await GetById(Guid.Parse(user.Id)) ?? null;
}
if (string.IsNullOrEmpty(user.Id))
{
user.Id = Guid.NewGuid().ToString();
}
if (string.IsNullOrEmpty(user.Salt))
{
user.Salt = _cryptoService.Salt();
}
user.Password = _cryptoService.Decrypt(clientId, user.Password) ?? string.Empty;
user.Password = _cryptoService.Hash(user.Password + user.Salt + _cryptoService.Pepper()) ?? string.Empty;
user.CreatedAt = DateTime.UtcNow;
Users.Add(user);
await SaveChangesAsync();
return user;
}
public async Task<UserModel?> Update(UserModel user)
{
ArgumentNullException.ThrowIfNull(user);
if (!await Exists(user))
{
return null;
}
var existingUser = await GetById(Guid.Parse(user.Id));
if (existingUser == null) return null;
existingUser.Name = user.Name;
existingUser.Email = user.Email;
existingUser.UpdatedAt = DateTime.UtcNow;
Users.Update(existingUser);
await SaveChangesAsync();
return existingUser;
}
public async Task<bool> Delete(Guid id)
{
var user = await GetById(id);
if (user == null) return false;
Users.Remove(user);
await SaveChangesAsync();
return true;
}
public async Task<UserModel?> GetByEmail(string email)
{
if (string.IsNullOrEmpty(email)) return null;
return await Users.FirstOrDefaultAsync(u => u.Email == email);
}
public async Task<string> GetUserSaltByEmail(string email)
{
if (string.IsNullOrEmpty(email)) return string.Empty;
var user = await Users.FirstOrDefaultAsync(u => u.Email == email);
return user?.Salt ?? string.Empty;
}
public async Task<UserModel?> Login(string email, string password, string clientId)
{
if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password)) return null;
var pass = _cryptoService.Decrypt(clientId, password) + await GetUserSaltByEmail(email) + _cryptoService.Pepper();
var hashedPassword = _cryptoService.Hash(pass);
var user = await Users
.FirstOrDefaultAsync(u => u.Email == email && u.Password == hashedPassword);
return user;
}
public async Task<UserModel?> GetById(Guid id)
{
return await Users.FindAsync(id);
}
public async Task<int> GetTotalItems()
{
return await Users.CountAsync();
}
public async Task<IEnumerable<UserModel>> GetPage(int page = 1, int pageSize = 20)
{
if (page < 1) page = 1;
if (pageSize < 1) pageSize = 20;
return await Users
.OrderByDescending(p => p.CreatedAt)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
}
public async Task<bool> Exists(UserModel? photo)
{
if (photo == null) return false;
if (string.IsNullOrEmpty(photo.Id)) return false;
return await Users.AnyAsync(p => p.Id == photo.Id);
}
public async Task<bool> Exists(string id)
{
return await Users.AnyAsync(p => p.Id == id);
}
}