using Isopoh.Cryptography.Argon2;
using Microsoft.EntityFrameworkCore;
using Mizuki.Database;
using Mizuki.Database.Models;
namespace Mizuki.Services;
///
/// The user service.
///
/// The Mizuki database context.
public class UserService(
MizukiDbContext dbContext)
{
///
/// Check if a user with the given username exists.
///
/// The username.
/// Whether they exist.
public async Task UsernameTaken(
string username)
{
return await dbContext.Users
.AnyAsync(u => u.Username == username);
}
///
/// Gets a user with the given username.
///
/// The username.
/// The user model.
public async Task GetUserForUsername(
string username)
{
return await dbContext.Users
.FirstAsync(u => u.Username == username);
}
///
/// Check if the password is valid for the given user.
///
/// The user's name.
/// The password.
/// Whether it's valid.
public async Task CheckPasswordForUser(
string username,
string password)
{
var user = await dbContext.Users
.FirstOrDefaultAsync(u => u.Username == username);
if (user is null)
return false;
return Argon2.Verify(user.PasswordHash, password);
}
///
/// Creates a user with the given username and password.
///
/// The username.
/// The password.
/// Whether the user was created.
public async Task CreateUser(
string username,
string password)
{
if (await UsernameTaken(username))
return null;
var hash = Argon2.Hash(password);
var userModel = new User
{
Id = Guid.NewGuid(),
Username = username,
PasswordHash = hash
};
await dbContext.Users.AddAsync(userModel);
await dbContext.SaveChangesAsync();
return userModel;
}
///
/// Updates the password for a given user.
///
/// The user.
/// The new password.
public async Task UpdatePasswordFor(
User user,
string newPassword)
{
user.PasswordHash = Argon2.Hash(newPassword);
dbContext.Users.Update(user);
await dbContext.SaveChangesAsync();
}
}