96 lines
3.2 KiB
C#
96 lines
3.2 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
|
|
public class UserDirectoryService : IUserDirectoryService
|
|
{
|
|
private readonly AppDbContext _db;
|
|
|
|
public UserDirectoryService(AppDbContext db) => _db = db;
|
|
|
|
public async Task<IReadOnlyList<UserSummaryResponse>> ListByRoleAsync(UserRole? role)
|
|
{
|
|
var query = _db.Users.AsNoTracking().Where(u => u.IsActive);
|
|
|
|
if (role.HasValue)
|
|
query = query.Where(u => u.Role == role.Value);
|
|
|
|
return await query
|
|
.OrderBy(u => u.FullName)
|
|
.Select(u => new UserSummaryResponse(
|
|
u.Id,
|
|
u.Username,
|
|
u.FullName,
|
|
u.Role.ToDbString()))
|
|
.ToListAsync();
|
|
}
|
|
|
|
public async Task<UserSummaryResponse> CreateAsync(CreateUserRequest request)
|
|
{
|
|
var exists = await _db.Users.AnyAsync(u => u.Username == request.Username);
|
|
if (exists)
|
|
throw new ConflictException(
|
|
$"Username '{request.Username}' is already taken.",
|
|
"USERNAME_TAKEN");
|
|
|
|
var user = new User
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Username = request.Username,
|
|
PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.Password),
|
|
FullName = request.FullName,
|
|
Role = UserRoleExtensions.FromDbString(request.Role),
|
|
IsActive = true,
|
|
CreatedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
_db.Users.Add(user);
|
|
await _db.SaveChangesAsync();
|
|
|
|
return new UserSummaryResponse(user.Id, user.Username, user.FullName, user.Role.ToDbString());
|
|
}
|
|
|
|
public async Task<UserSummaryResponse> UpdateAsync(Guid userId, UpdateUserRequest request)
|
|
{
|
|
var user = await _db.Users.FindAsync(userId);
|
|
if (user is null)
|
|
throw new NotFoundException("User not found.", "USER_NOT_FOUND");
|
|
|
|
if (request.FullName is not null)
|
|
user.FullName = request.FullName;
|
|
|
|
if (request.Role is not null)
|
|
user.Role = UserRoleExtensions.FromDbString(request.Role);
|
|
|
|
if (request.IsActive.HasValue)
|
|
user.IsActive = request.IsActive.Value;
|
|
|
|
await _db.SaveChangesAsync();
|
|
|
|
return new UserSummaryResponse(user.Id, user.Username, user.FullName, user.Role.ToDbString());
|
|
}
|
|
|
|
public async Task ResetPasswordAsync(Guid userId, string newPassword)
|
|
{
|
|
var user = await _db.Users.FindAsync(userId);
|
|
if (user is null)
|
|
throw new NotFoundException("User not found.", "USER_NOT_FOUND");
|
|
|
|
user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(newPassword);
|
|
await _db.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task ChangePasswordAsync(Guid userId, string currentPassword, string newPassword)
|
|
{
|
|
var user = await _db.Users.FindAsync(userId);
|
|
if (user is null)
|
|
throw new NotFoundException("User not found.", "USER_NOT_FOUND");
|
|
|
|
if (!BCrypt.Net.BCrypt.Verify(currentPassword, user.PasswordHash))
|
|
throw new ValidationException(
|
|
"Current password is incorrect.",
|
|
"INVALID_PASSWORD");
|
|
|
|
user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(newPassword);
|
|
await _db.SaveChangesAsync();
|
|
}
|
|
}
|