From 72bb2b24efb45a762e92d71baf92840754749203 Mon Sep 17 00:00:00 2001 From: Cucumberrbob <128094686+Cucumberrbob@users.noreply.github.com> Date: Thu, 6 Mar 2025 21:16:25 +0000 Subject: [PATCH] Add openapi compatible xmldoc to `AuthController` # Conflicts: # server/RdtClient.Web/Controllers/AuthController.cs --- .../Controllers/AuthController.cs | 153 +++++++++++++++--- 1 file changed, 135 insertions(+), 18 deletions(-) diff --git a/server/RdtClient.Web/Controllers/AuthController.cs b/server/RdtClient.Web/Controllers/AuthController.cs index 9a3f6ee..2fd4aeb 100644 --- a/server/RdtClient.Web/Controllers/AuthController.cs +++ b/server/RdtClient.Web/Controllers/AuthController.cs @@ -2,15 +2,28 @@ using Microsoft.AspNetCore.Mvc; using RdtClient.Data.Enums; using RdtClient.Service.Services; +using System.ComponentModel.DataAnnotations; namespace RdtClient.Web.Controllers; +/// +/// Handles authentication and user management operations +/// [Route("Api/Authentication")] public class AuthController(Authentication authentication, Settings settings) : Controller { + /// + /// Checks if the current session is authenticated + /// + /// Session is valid and authenticated, or authentication is disabled + /// System requires initial setup - no users exist in the database + /// Session is not authenticated [AllowAnonymous] [Route("IsLoggedIn")] [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status402PaymentRequired, Type = typeof(ProblemDetails))] + [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(ProblemDetails))] public async Task IsLoggedIn() { if (Settings.Get.General.AuthenticationType == AuthenticationType.None) @@ -24,18 +37,33 @@ public class AuthController(Authentication authentication, Settings settings) : if (user == null) { - return StatusCode(402, "Setup required"); + return Problem(detail: "Setup required", statusCode: StatusCodes.Status402PaymentRequired); } - - return StatusCode(403); + + return Problem(detail: "Login required", statusCode: StatusCodes.Status403Forbidden); } - + return Ok(); } + /// + /// Creates the initial account for the system + /// + /// + /// This endpoint can only be used when no account exists. + /// It creates the account and automatically logs in. + /// + /// Registration details for the new account + /// Account created successfully and user is logged in + /// Invalid request - username/password missing or validation failed + /// Cannot create account - a user already exists in system [AllowAnonymous] [Route("Create")] [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(ProblemDetails))] public async Task Create([FromBody] AuthControllerLoginRequest? request) { if (request == null) @@ -47,29 +75,43 @@ public class AuthController(Authentication authentication, Settings settings) : if (user != null) { - return StatusCode(401); + return Problem(detail: "User already exists - only one user allowed", statusCode: StatusCodes.Status401Unauthorized); } - + if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password)) { - return BadRequest("Invalid UserName or Password"); + return Problem(detail: "Empty UserName or Password", statusCode: StatusCodes.Status400BadRequest); } var registerResult = await authentication.Register(request.UserName, request.Password); if (!registerResult.Succeeded) { - return BadRequest(registerResult.Errors.First().Description); + return Problem(detail: registerResult.Errors.First().Description, statusCode: StatusCodes.Status400BadRequest); } - + await authentication.Login(request.UserName, request.Password); return Ok(); } + /// + /// Configures the provider settings for the application + /// + /// + /// This endpoint can only be used when no provider is configured. + /// It sets up the initial provider configuration including the API key. + /// + /// Provider configuration details including provider type and API token + /// Provider configured successfully + /// Invalid request - missing required fields + /// Provider already configured [AllowAnonymous] [Route("SetupProvider")] [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] public async Task SetupProvider([FromBody] AuthControllerSetupProviderRequest? request) { if (request == null) @@ -95,10 +137,24 @@ public class AuthController(Authentication authentication, Settings settings) : return Ok(); } + /// + /// Authenticates a user and creates a new session + /// + /// + /// Validates the provided credentials and creates an authenticated session if valid. + /// + /// Login credentials + /// Authentication successful + /// Invalid credentials or missing required fields + /// System requires initial setup - no users exist [AllowAnonymous] [Route("Login")] [HttpPost] - public async Task Login([FromBody] AuthControllerLoginRequest? request) + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + [ProducesResponseType(StatusCodes.Status402PaymentRequired, Type = typeof(ProblemDetails))] + public async Task> Login([FromBody] AuthControllerLoginRequest? request) { if (request == null) { @@ -109,36 +165,55 @@ public class AuthController(Authentication authentication, Settings settings) : if (user == null) { - return StatusCode(402); + return Problem(detail: "Setup required", statusCode: StatusCodes.Status402PaymentRequired); } if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password)) { - return BadRequest("Invalid credentials"); + return Problem(detail: "Invalid credentials", statusCode: StatusCodes.Status400BadRequest); } var result = await authentication.Login(request.UserName, request.Password); if (!result.Succeeded) { - return BadRequest("Invalid credentials"); + return Problem(detail: "Invalid credentials", statusCode: StatusCodes.Status400BadRequest); } return Ok(); } - + + /// + /// Ends the current authenticated session + /// + /// Session terminated successfully [Route("Logout")] [HttpPost] + [ProducesResponseType(StatusCodes.Status200OK)] public async Task Logout() { await authentication.Logout(); + return Ok(); } - + + /// + /// Updates the authenticated user's password + /// + /// + /// Requires authentication. Updates the password for the currently logged in user. + /// + /// Password update request containing the new password + /// Password updated successfully + /// Invalid request or password validation failed + /// Unauthorized - user must be authenticated [Route("Update")] [HttpPost] [Authorize(Policy = "AuthSetting")] - public async Task Update([FromBody] AuthControllerUpdateRequest? request) + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task> Update([FromBody] AuthControllerUpdateRequest? request) { if (request == null) { @@ -147,34 +222,76 @@ public class AuthController(Authentication authentication, Settings settings) : if (String.IsNullOrEmpty(request.UserName) || String.IsNullOrEmpty(request.Password)) { - return BadRequest("Invalid UserName or Password"); + return Problem(detail: "Invalid UserName or Password", statusCode: StatusCodes.Status400BadRequest); } var updateResult = await authentication.Update(request.UserName, request.Password); if (!updateResult.Succeeded) { - return BadRequest(updateResult.Errors.First().Description); + return Problem(detail: updateResult.Errors.First().Description, statusCode: StatusCodes.Status400BadRequest); } return Ok(); } } +/// +/// Request model for login and user creation operations +/// public class AuthControllerLoginRequest { + /// + /// Username for authentication + /// + /// admin + [Required] public String? UserName { get; set; } + + /// + /// Password for authentication + /// + /// MySecurePassword123! + [Required] public String? Password { get; set; } } +/// +/// Request model for configuring the provider settings +/// public class AuthControllerSetupProviderRequest { + /// + /// Provider type identifier + /// + /// 1 + [Required] public Int32 Provider { get; set; } + + /// + /// API token or key for the provider + /// + /// sk-1234567890abcdef + [Required] public String? Token { get; set; } } +/// +/// Request model for updating user password +/// public class AuthControllerUpdateRequest { + /// + /// Username for the account + /// + /// myusername + [Required] public String? UserName { get; set; } + + /// + /// New password for the user account + /// + /// NewSecurePassword123! + [Required] public String? Password { get; set; } } \ No newline at end of file