Ajoute une zone d'administration des utilisateurs

This commit is contained in:
2026-04-15 21:21:26 +02:00
parent 106786a638
commit 1d18a070e5
12 changed files with 1595 additions and 5 deletions

View File

@@ -106,6 +106,23 @@ public sealed class MySqlUserProfileStore(
LIMIT 1;
""";
private const string SelectAllProfilesSql = """
SELECT
subject,
username,
email,
display_name,
club,
city,
preferred_format,
favorite_cube,
bio,
created_utc,
updated_utc
FROM site_users
ORDER BY updated_utc DESC, created_utc DESC, username ASC;
""";
private readonly SiteDataOptions _options = options.Value;
private readonly ILogger<MySqlUserProfileStore> _logger = logger;
@@ -198,9 +215,82 @@ public sealed class MySqlUserProfileStore(
return await ReadProfileAsync(connection, user.Subject, cancellationToken);
}
private static UserProfileInput NormalizeInput(AuthenticatedSiteUser user, UpdateUserProfileRequest request)
public void ValidateAdminUpdate(string fallbackDisplayName, UpdateUserProfileRequest request)
=> _ = NormalizeInput(fallbackDisplayName, request);
public async Task<IReadOnlyList<UserProfileResponse>> ListAsync(CancellationToken cancellationToken)
{
var displayName = NormalizeOptionalValue(request.DisplayName, "nom affiche", 120) ?? user.DisplayName;
await using var connection = new MySqlConnection(_options.BuildConnectionString());
await connection.OpenAsync(cancellationToken);
await using var command = connection.CreateCommand();
command.CommandText = SelectAllProfilesSql;
var profiles = new List<UserProfileResponse>();
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
while (await reader.ReadAsync(cancellationToken))
{
profiles.Add(MapProfile(reader));
}
return profiles;
}
public async Task<UserProfileResponse?> FindBySubjectAsync(string subject, CancellationToken cancellationToken)
{
await using var connection = new MySqlConnection(_options.BuildConnectionString());
await connection.OpenAsync(cancellationToken);
await using var command = connection.CreateCommand();
command.CommandText = SelectProfileSql;
command.Parameters.AddWithValue("@subject", subject);
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
return await reader.ReadAsync(cancellationToken)
? MapProfile(reader)
: null;
}
public async Task<UserProfileResponse> AdminUpsertAsync(
string subject,
string username,
string? email,
string fallbackDisplayName,
UpdateUserProfileRequest request,
CancellationToken cancellationToken)
{
var input = NormalizeInput(fallbackDisplayName, request);
await using var connection = new MySqlConnection(_options.BuildConnectionString());
await connection.OpenAsync(cancellationToken);
var nowUtc = DateTime.UtcNow;
await using (var command = connection.CreateCommand())
{
command.CommandText = UpsertProfileSql;
command.Parameters.AddWithValue("@subject", subject);
command.Parameters.AddWithValue("@username", username);
command.Parameters.AddWithValue("@email", (object?)email ?? DBNull.Value);
command.Parameters.AddWithValue("@displayName", input.DisplayName);
command.Parameters.AddWithValue("@club", (object?)input.Club ?? DBNull.Value);
command.Parameters.AddWithValue("@city", (object?)input.City ?? DBNull.Value);
command.Parameters.AddWithValue("@preferredFormat", (object?)input.PreferredFormat ?? DBNull.Value);
command.Parameters.AddWithValue("@favoriteCube", (object?)input.FavoriteCube ?? DBNull.Value);
command.Parameters.AddWithValue("@bio", (object?)input.Bio ?? DBNull.Value);
command.Parameters.AddWithValue("@createdUtc", nowUtc);
command.Parameters.AddWithValue("@updatedUtc", nowUtc);
await command.ExecuteNonQueryAsync(cancellationToken);
}
return await ReadProfileAsync(connection, subject, cancellationToken);
}
private static UserProfileInput NormalizeInput(AuthenticatedSiteUser user, UpdateUserProfileRequest request)
=> NormalizeInput(user.DisplayName, request);
private static UserProfileInput NormalizeInput(string fallbackDisplayName, UpdateUserProfileRequest request)
{
var displayName = NormalizeOptionalValue(request.DisplayName, "nom affiche", 120) ?? fallbackDisplayName;
var club = NormalizeOptionalValue(request.Club, "club", 120);
var city = NormalizeOptionalValue(request.City, "ville", 120);
var favoriteCube = NormalizeOptionalValue(request.FavoriteCube, "cube favori", 120);
@@ -258,6 +348,11 @@ public sealed class MySqlUserProfileStore(
throw new InvalidOperationException("Le profil utilisateur n'a pas pu etre charge.");
}
return MapProfile(reader);
}
private static UserProfileResponse MapProfile(MySqlDataReader reader)
{
var subjectOrdinal = reader.GetOrdinal("subject");
var usernameOrdinal = reader.GetOrdinal("username");
var emailOrdinal = reader.GetOrdinal("email");