using GermanApp.Application.DTOs.Auth;
using GermanApp.Application.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Security.Claims;
namespace GermanApp.Presentation.Controllers;
///
/// Controller for authentication endpoints.
/// Part of the Presentation layer.
///
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
private readonly IAuthService _authService;
public AuthController(IAuthService authService)
{
_authService = authService;
}
///
/// Register a new user.
///
/// Registration data
/// Authentication response with JWT token
[HttpPost("register")]
[AllowAnonymous]
[ProducesResponseType(typeof(AuthResponse), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)]
public async Task Register([FromBody] RegisterDto registerDto)
{
try
{
var result = await _authService.RegisterAsync(registerDto);
return Ok(result);
}
catch (InvalidOperationException ex)
{
return BadRequest(ex.Message);
}
catch (Exception ex)
{
return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message);
}
}
///
/// Login an existing user.
///
/// Login data
/// Authentication response with JWT token
[HttpPost("login")]
[AllowAnonymous]
[ProducesResponseType(typeof(AuthResponse), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.Unauthorized)]
public async Task Login([FromBody] LoginDto loginDto)
{
try
{
var result = await _authService.LoginAsync(loginDto);
return Ok(result);
}
catch (UnauthorizedAccessException ex)
{
return Unauthorized(ex.Message);
}
catch (Exception ex)
{
return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message);
}
}
///
/// Get current authenticated user information.
///
/// Current user information
[HttpGet("me")]
[Authorize]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.Unauthorized)]
public async Task GetCurrentUser()
{
try
{
// Get user ID from JWT claim
// Note: JWT "sub" claim is mapped by ASP.NET Core JWT middleware to ClaimTypes.NameIdentifier
// (http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier)
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier) ?? User.FindFirst("sub");
if (userIdClaim == null || !int.TryParse(userIdClaim.Value, out var userId) || userId == 0)
return Unauthorized();
var user = await _authService.GetCurrentUserAsync(userId);
if (user == null)
return Unauthorized();
// Return full user profile including role, level, streak, and points
return Ok(new
{
userId = user.Id,
username = user.Username,
email = user.Email,
role = user.Role,
currentLevel = user.CurrentLevel,
streak = user.Streak,
totalPoints = user.TotalPoints
});
}
catch (Exception ex)
{
return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message);
}
}
///
/// Refresh the access token using a refresh token.
///
/// The refresh token
/// New access token and refresh token
[HttpPost("refresh")]
[ProducesResponseType(typeof(RefreshTokenResponse), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.Unauthorized)]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)]
public async Task Refresh([FromBody] string refreshToken)
{
try
{
var result = await _authService.RefreshTokenAsync(refreshToken);
return Ok(result);
}
catch (UnauthorizedAccessException ex)
{
return Unauthorized(ex.Message);
}
catch (Exception ex)
{
return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message);
}
}
///
/// Revoke a refresh token.
///
/// The refresh token to revoke
/// Success or error response
[HttpPost("revoke-refresh")]
[Authorize]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.Unauthorized)]
[ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)]
public async Task RevokeRefreshToken([FromBody] string refreshToken)
{
try
{
await _authService.RevokeRefreshTokenAsync(refreshToken);
return Ok(new { message = "Refresh token revoked successfully" });
}
catch (UnauthorizedAccessException ex)
{
return Unauthorized(ex.Message);
}
catch (Exception ex)
{
return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message);
}
}
}