142 lines
4.3 KiB
C#
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);
|
|
}
|
|
} |