150 lines
4.4 KiB
C#
150 lines
4.4 KiB
C#
using Omika.Diagnostics.Users;
|
|
|
|
namespace Omika.Diagnostics.Tests.Fakes;
|
|
|
|
/// <summary>
|
|
/// Fake en mémoire de <see cref="IDiagnosticUserRepository"/> pour les tests sans PostgreSQL.
|
|
/// Reproduit la sémantique du repository Npgsql : unicité insensible à la casse, tri par
|
|
/// username, hash stocké (jamais de mot de passe en clair).
|
|
/// </summary>
|
|
public sealed class FakeDiagnosticUserRepository : IDiagnosticUserRepository
|
|
{
|
|
private readonly List<DiagnosticUserRecord> _users = [];
|
|
private long _nextId = 1;
|
|
|
|
public IReadOnlyList<DiagnosticUserRecord> Seed(params DiagnosticUserRecord[] users)
|
|
{
|
|
foreach (DiagnosticUserRecord u in users)
|
|
{
|
|
if (u.Id == 0)
|
|
{
|
|
u.Id = _nextId++;
|
|
}
|
|
else
|
|
{
|
|
_nextId = Math.Max(_nextId, u.Id + 1);
|
|
}
|
|
|
|
_users.Add(u);
|
|
}
|
|
|
|
return _users;
|
|
}
|
|
|
|
public Task<DiagnosticUserRecord?> GetByUsernameAsync(
|
|
string username,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
string? normalized = username?.Trim();
|
|
DiagnosticUserRecord? found = _users.FirstOrDefault(u =>
|
|
string.Equals(u.Username, normalized, StringComparison.OrdinalIgnoreCase));
|
|
return Task.FromResult(found);
|
|
}
|
|
|
|
public Task<IReadOnlyList<DiagnosticUserRecord>> ListAsync(
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
IReadOnlyList<DiagnosticUserRecord> ordered = _users
|
|
.OrderBy(u => u.Username, StringComparer.OrdinalIgnoreCase)
|
|
.ToList();
|
|
return Task.FromResult(ordered);
|
|
}
|
|
|
|
public Task<DiagnosticUserRecord?> CreateAsync(
|
|
string username,
|
|
string passwordHash,
|
|
string role,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
string? normalized = username?.Trim();
|
|
if (string.IsNullOrWhiteSpace(normalized))
|
|
{
|
|
return Task.FromResult<DiagnosticUserRecord?>(null);
|
|
}
|
|
|
|
if (_users.Any(u => string.Equals(u.Username, normalized, StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
return Task.FromResult<DiagnosticUserRecord?>(null); // doublon.
|
|
}
|
|
|
|
DateTimeOffset now = DateTimeOffset.UtcNow;
|
|
var record = new DiagnosticUserRecord
|
|
{
|
|
Id = _nextId++,
|
|
Username = normalized,
|
|
PasswordHash = passwordHash,
|
|
Role = role,
|
|
Enabled = true,
|
|
CreatedAtUtc = now,
|
|
UpdatedAtUtc = now,
|
|
PasswordChangedAtUtc = now,
|
|
LastLoginAtUtc = null
|
|
};
|
|
_users.Add(record);
|
|
return Task.FromResult<DiagnosticUserRecord?>(record);
|
|
}
|
|
|
|
public Task<bool> SetEnabledAsync(
|
|
long id,
|
|
bool enabled,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
DiagnosticUserRecord? user = _users.FirstOrDefault(u => u.Id == id);
|
|
if (user is null)
|
|
{
|
|
return Task.FromResult(false);
|
|
}
|
|
|
|
user.Enabled = enabled;
|
|
user.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
|
return Task.FromResult(true);
|
|
}
|
|
|
|
public Task<bool> SetRoleAsync(
|
|
long id,
|
|
string role,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
DiagnosticUserRecord? user = _users.FirstOrDefault(u => u.Id == id);
|
|
if (user is null)
|
|
{
|
|
return Task.FromResult(false);
|
|
}
|
|
|
|
user.Role = role;
|
|
user.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
|
return Task.FromResult(true);
|
|
}
|
|
|
|
public Task<bool> UpdatePasswordHashAsync(
|
|
long id,
|
|
string passwordHash,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
DiagnosticUserRecord? user = _users.FirstOrDefault(u => u.Id == id);
|
|
if (user is null)
|
|
{
|
|
return Task.FromResult(false);
|
|
}
|
|
|
|
user.PasswordHash = passwordHash;
|
|
user.PasswordChangedAtUtc = DateTimeOffset.UtcNow;
|
|
user.UpdatedAtUtc = DateTimeOffset.UtcNow;
|
|
return Task.FromResult(true);
|
|
}
|
|
|
|
public Task UpdateLastLoginAsync(
|
|
string username,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
DiagnosticUserRecord? user = _users.FirstOrDefault(u =>
|
|
string.Equals(u.Username, username?.Trim(), StringComparison.OrdinalIgnoreCase));
|
|
if (user is not null)
|
|
{
|
|
user.LastLoginAtUtc = DateTimeOffset.UtcNow;
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|