fix(developers): distinguish API errors from taken usernames in availability check
All checks were successful
Build and Deploy / deploy (push) Successful in 40s
All checks were successful
Build and Deploy / deploy (push) Successful in 40s
CheckUsernameAsync returned false (taken) on any API failure, making every username appear taken when SilverDESK was unreachable. Now returns nullable bool so errors show a warning instead of blocking submission. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -107,6 +107,10 @@
|
|||||||
{
|
{
|
||||||
<span class="username-status username-taken">✗ Username is already taken</span>
|
<span class="username-status username-taken">✗ Username is already taken</span>
|
||||||
}
|
}
|
||||||
|
else if (_usernameCheckState == UsernameCheckState.Error)
|
||||||
|
{
|
||||||
|
<span class="username-status username-error">⚠ Could not check availability — you can still submit</span>
|
||||||
|
}
|
||||||
<ValidationMessage For="() => _application.DesiredUsername" />
|
<ValidationMessage For="() => _application.DesiredUsername" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -209,7 +213,7 @@
|
|||||||
{
|
{
|
||||||
<div class="dev-error">@_errorMessage</div>
|
<div class="dev-error">@_errorMessage</div>
|
||||||
}
|
}
|
||||||
<button type="submit" class="dev-btn dev-btn-primary" disabled="@_submitting">
|
<button type="submit" class="dev-btn dev-btn-primary" disabled="@(_submitting || _usernameCheckState == UsernameCheckState.Taken)">
|
||||||
@if (_submitting)
|
@if (_submitting)
|
||||||
{
|
{
|
||||||
<span class="btn-spinner"></span>
|
<span class="btn-spinner"></span>
|
||||||
@@ -240,7 +244,7 @@
|
|||||||
|
|
||||||
private readonly string[] _availablePlatforms = { "Windows", "macOS", "Linux", "Android", "iOS", "Other" };
|
private readonly string[] _availablePlatforms = { "Windows", "macOS", "Linux", "Android", "iOS", "Other" };
|
||||||
|
|
||||||
private enum UsernameCheckState { None, Checking, Available, Taken }
|
private enum UsernameCheckState { None, Checking, Available, Taken, Error }
|
||||||
|
|
||||||
private void SelectRole(ApplicationRole role)
|
private void SelectRole(ApplicationRole role)
|
||||||
{
|
{
|
||||||
@@ -279,7 +283,12 @@
|
|||||||
|
|
||||||
if (!token.IsCancellationRequested)
|
if (!token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
_usernameCheckState = available ? UsernameCheckState.Available : UsernameCheckState.Taken;
|
_usernameCheckState = available switch
|
||||||
|
{
|
||||||
|
true => UsernameCheckState.Available,
|
||||||
|
false => UsernameCheckState.Taken,
|
||||||
|
null => UsernameCheckState.Error
|
||||||
|
};
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ public static class DeveloperEndpoints
|
|||||||
group.MapGet("/check-username/{username}", async (string username, DeveloperApplicationService service) =>
|
group.MapGet("/check-username/{username}", async (string username, DeveloperApplicationService service) =>
|
||||||
{
|
{
|
||||||
var available = await service.CheckUsernameAsync(username);
|
var available = await service.CheckUsernameAsync(username);
|
||||||
return Results.Ok(new { available });
|
if (available is null)
|
||||||
|
return Results.Problem("Unable to verify username availability", statusCode: 503);
|
||||||
|
return Results.Ok(new { available = available.Value });
|
||||||
});
|
});
|
||||||
|
|
||||||
group.MapPost("/apply", async (DeveloperApplication application, DeveloperApplicationService service) =>
|
group.MapPost("/apply", async (DeveloperApplication application, DeveloperApplicationService service) =>
|
||||||
|
|||||||
@@ -17,21 +17,30 @@ public class DeveloperApplicationService
|
|||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> CheckUsernameAsync(string username)
|
/// <summary>
|
||||||
|
/// Checks username availability. Returns: true = available, false = taken, null = error/unknown.
|
||||||
|
/// </summary>
|
||||||
|
public async Task<bool?> CheckUsernameAsync(string username)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = await _httpClient.GetAsync($"/api/auth/check-username/{Uri.EscapeDataString(username)}");
|
var response = await _httpClient.GetAsync($"/api/auth/check-username/{Uri.EscapeDataString(username)}");
|
||||||
if (!response.IsSuccessStatusCode)
|
if (!response.IsSuccessStatusCode)
|
||||||
return false;
|
{
|
||||||
|
_logger.LogWarning("Username check returned {StatusCode} for {Username}", response.StatusCode, username);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
|
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
|
||||||
return result.TryGetProperty("available", out var available) && available.GetBoolean();
|
if (result.TryGetProperty("available", out var available))
|
||||||
|
return available.GetBoolean();
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error checking username availability for {Username}", username);
|
_logger.LogError(ex, "Error checking username availability for {Username}", username);
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -186,6 +186,29 @@
|
|||||||
margin-top: 0.3rem;
|
margin-top: 0.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Username status */
|
||||||
|
.username-status {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
margin-top: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username-checking {
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.username-available {
|
||||||
|
color: #34d399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username-taken {
|
||||||
|
color: #f87171;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username-error {
|
||||||
|
color: #fbbf24;
|
||||||
|
}
|
||||||
|
|
||||||
/* Validation messages */
|
/* Validation messages */
|
||||||
.validation-message {
|
.validation-message {
|
||||||
color: #f87171;
|
color: #f87171;
|
||||||
|
|||||||
Reference in New Issue
Block a user