feat: add application package generation and grouped readiness workflows
This commit is contained in:
@@ -32,7 +32,7 @@ public sealed class AuthController : ControllerBase
|
||||
public IActionResult Config()
|
||||
{
|
||||
var requireAuth = _cfg.GetValue("Auth:Require", false);
|
||||
var googleEnabled = !string.IsNullOrWhiteSpace((_cfg["Auth:GoogleClientId"] ?? "").Trim());
|
||||
var googleEnabled = !string.IsNullOrWhiteSpace((_cfg["Auth:GoogleClientId"] ?? string.Empty).Trim());
|
||||
var allowRegistration = _cfg.GetValue("Auth:AllowRegistration", false);
|
||||
|
||||
return Ok(new
|
||||
@@ -40,7 +40,7 @@ public sealed class AuthController : ControllerBase
|
||||
requireAuth,
|
||||
googleEnabled,
|
||||
localEnabled = true,
|
||||
allowRegistration
|
||||
allowRegistration,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -56,17 +56,18 @@ public sealed class AuthController : ControllerBase
|
||||
string? FirstName,
|
||||
string? LastName,
|
||||
string? DisplayName,
|
||||
string? ProfileCvText,
|
||||
IList<string> Roles,
|
||||
GoogleLinkDto? GoogleLink);
|
||||
public sealed record UpdateProfileRequest(string? Email, string? UserName, string? FirstName, string? LastName, string? DisplayName);
|
||||
public sealed record UpdateProfileRequest(string? Email, string? UserName, string? FirstName, string? LastName, string? DisplayName, string? ProfileCvText);
|
||||
public sealed record GoogleTokenRequest(string Token);
|
||||
|
||||
[HttpPost("login")]
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult<AuthResult>> Login([FromBody] LoginRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
var email = (request.Email ?? "").Trim();
|
||||
var password = request.Password ?? "";
|
||||
var email = (request.Email ?? string.Empty).Trim();
|
||||
var password = request.Password ?? string.Empty;
|
||||
|
||||
if (email.Length == 0) return BadRequest("Email is required.");
|
||||
if (password.Length == 0) return BadRequest("Password is required.");
|
||||
@@ -88,8 +89,8 @@ public sealed class AuthController : ControllerBase
|
||||
var allow = _cfg.GetValue("Auth:AllowRegistration", false);
|
||||
if (!allow) return StatusCode(403, "Registration is disabled.");
|
||||
|
||||
var email = (request.Email ?? "").Trim();
|
||||
var password = request.Password ?? "";
|
||||
var email = (request.Email ?? string.Empty).Trim();
|
||||
var password = request.Password ?? string.Empty;
|
||||
|
||||
if (email.Length == 0) return BadRequest("Email is required.");
|
||||
if (password.Length == 0) return BadRequest("Password is required.");
|
||||
@@ -112,7 +113,7 @@ public sealed class AuthController : ControllerBase
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult<AuthResult>> ExchangeGoogleToken([FromBody] GoogleTokenRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
var token = (request.Token ?? "").Trim();
|
||||
var token = (request.Token ?? string.Empty).Trim();
|
||||
if (token.Length == 0) return BadRequest("Google token is required.");
|
||||
|
||||
GoogleTokenPrincipal google;
|
||||
@@ -150,16 +151,16 @@ public sealed class AuthController : ControllerBase
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Me(CancellationToken cancellationToken)
|
||||
{
|
||||
var u = await _users.GetUserAsync(User);
|
||||
if (u is not null)
|
||||
var user = await _users.GetUserAsync(User);
|
||||
if (user is not null)
|
||||
{
|
||||
var roles = await _users.GetRolesAsync(u);
|
||||
return Ok(ToMeResult(u, roles));
|
||||
var roles = await _users.GetRolesAsync(user);
|
||||
return Ok(ToMeResult(user, roles));
|
||||
}
|
||||
|
||||
var email = User.FindFirstValue(ClaimTypes.Email) ?? User.FindFirstValue("email");
|
||||
var sub = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub");
|
||||
var iss = User.FindFirstValue("iss") ?? "";
|
||||
var iss = User.FindFirstValue("iss") ?? string.Empty;
|
||||
var provider = iss.Contains("accounts.google.com", StringComparison.OrdinalIgnoreCase) ? "google" : "external";
|
||||
|
||||
return Ok(new MeResult(
|
||||
@@ -170,6 +171,7 @@ public sealed class AuthController : ControllerBase
|
||||
FirstName: User.FindFirstValue("given_name"),
|
||||
LastName: User.FindFirstValue("family_name"),
|
||||
DisplayName: User.FindFirstValue("name"),
|
||||
ProfileCvText: null,
|
||||
Roles: Array.Empty<string>(),
|
||||
GoogleLink: provider == "google" ? new GoogleLinkDto(false, email, null) : null));
|
||||
}
|
||||
@@ -178,8 +180,8 @@ public sealed class AuthController : ControllerBase
|
||||
[Authorize(AuthenticationSchemes = "local")]
|
||||
public async Task<IActionResult> UpdateProfile([FromBody] UpdateProfileRequest request)
|
||||
{
|
||||
var u = await _users.GetUserAsync(User);
|
||||
if (u is null)
|
||||
var user = await _users.GetUserAsync(User);
|
||||
if (user is null)
|
||||
{
|
||||
return StatusCode(501, "Profile updates are only supported for local username/password accounts.");
|
||||
}
|
||||
@@ -189,14 +191,16 @@ public sealed class AuthController : ControllerBase
|
||||
var firstName = TrimOrNull(request.FirstName);
|
||||
var lastName = TrimOrNull(request.LastName);
|
||||
var displayName = TrimOrNull(request.DisplayName);
|
||||
var profileCvText = TrimOrNull(request.ProfileCvText);
|
||||
|
||||
if (email is not null) u.Email = email;
|
||||
if (userName is not null) u.UserName = userName;
|
||||
u.FirstName = firstName;
|
||||
u.LastName = lastName;
|
||||
u.DisplayName = displayName;
|
||||
if (email is not null) user.Email = email;
|
||||
if (userName is not null) user.UserName = userName;
|
||||
user.FirstName = firstName;
|
||||
user.LastName = lastName;
|
||||
user.DisplayName = displayName;
|
||||
user.ProfileCvText = profileCvText;
|
||||
|
||||
var res = await _users.UpdateAsync(u);
|
||||
var res = await _users.UpdateAsync(user);
|
||||
if (!res.Succeeded)
|
||||
return BadRequest(string.Join("; ", res.Errors.Select(e => e.Description)));
|
||||
|
||||
@@ -213,7 +217,7 @@ public sealed class AuthController : ControllerBase
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
var token = (request.Token ?? "").Trim();
|
||||
var token = (request.Token ?? string.Empty).Trim();
|
||||
if (token.Length == 0) return BadRequest("Google token is required.");
|
||||
|
||||
GoogleTokenPrincipal google;
|
||||
@@ -279,8 +283,8 @@ public sealed class AuthController : ControllerBase
|
||||
[Authorize(AuthenticationSchemes = "local")]
|
||||
public async Task<IActionResult> ChangePassword([FromBody] ChangePasswordRequest request)
|
||||
{
|
||||
var u = await _users.GetUserAsync(User);
|
||||
if (u is null)
|
||||
var user = await _users.GetUserAsync(User);
|
||||
if (user is null)
|
||||
{
|
||||
return StatusCode(501, "Password changes are only supported for local username/password accounts.");
|
||||
}
|
||||
@@ -288,7 +292,7 @@ public sealed class AuthController : ControllerBase
|
||||
if (string.IsNullOrWhiteSpace(request.CurrentPassword)) return BadRequest("CurrentPassword is required.");
|
||||
if (string.IsNullOrWhiteSpace(request.NewPassword)) return BadRequest("NewPassword is required.");
|
||||
|
||||
var res = await _users.ChangePasswordAsync(u, request.CurrentPassword, request.NewPassword);
|
||||
var res = await _users.ChangePasswordAsync(user, request.CurrentPassword, request.NewPassword);
|
||||
if (!res.Succeeded)
|
||||
return BadRequest(string.Join("; ", res.Errors.Select(e => e.Description)));
|
||||
|
||||
@@ -301,7 +305,7 @@ public sealed class AuthController : ControllerBase
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> RequestPasswordReset([FromBody] RequestPasswordResetRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
var email = (request.Email ?? "").Trim();
|
||||
var email = (request.Email ?? string.Empty).Trim();
|
||||
if (email.Length == 0) return NoContent();
|
||||
|
||||
var user = await _users.FindByEmailAsync(email);
|
||||
@@ -312,7 +316,7 @@ public sealed class AuthController : ControllerBase
|
||||
|
||||
var token = await _users.GeneratePasswordResetTokenAsync(user);
|
||||
|
||||
var baseUrl = (_cfg["App:PublicBaseUrl"] ?? "").Trim().TrimEnd('/');
|
||||
var baseUrl = (_cfg["App:PublicBaseUrl"] ?? string.Empty).Trim().TrimEnd('/');
|
||||
if (string.IsNullOrWhiteSpace(baseUrl))
|
||||
{
|
||||
baseUrl = $"{Request.Scheme}://{Request.Host}";
|
||||
@@ -336,9 +340,9 @@ public sealed class AuthController : ControllerBase
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> ResetPassword([FromBody] ResetPasswordRequest request)
|
||||
{
|
||||
var email = (request.Email ?? "").Trim();
|
||||
var token = request.Token ?? "";
|
||||
var newPassword = request.NewPassword ?? "";
|
||||
var email = (request.Email ?? string.Empty).Trim();
|
||||
var token = request.Token ?? string.Empty;
|
||||
var newPassword = request.NewPassword ?? string.Empty;
|
||||
|
||||
if (email.Length == 0) return BadRequest("Email is required.");
|
||||
if (token.Length == 0) return BadRequest("Token is required.");
|
||||
@@ -369,6 +373,7 @@ public sealed class AuthController : ControllerBase
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
DisplayName: user.DisplayName,
|
||||
ProfileCvText: user.ProfileCvText,
|
||||
Roles: roles,
|
||||
GoogleLink: new GoogleLinkDto(
|
||||
Linked: !string.IsNullOrWhiteSpace(user.GoogleSubject),
|
||||
@@ -376,5 +381,3 @@ public sealed class AuthController : ControllerBase
|
||||
LinkedAt: user.GoogleLinkedAt));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user