using AutoMapper; using GamificationService.Exceptions.Services.Instruction; using GamificationService.Exceptions.Services.InstructionTest; using GamificationService.Models.BasicResponses; using GamificationService.Models.Database; using GamificationService.Models.DTO; using GamificationService.Services.InstructionTests; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; namespace GamificationService.Controllers; [ApiController] [Route("api/[controller]")] [Authorize(Policy = "User")] public class InstructionTestController : ControllerBase { private readonly IInstructionTestsService _instructionTestsService; private readonly UserManager _userManager; private readonly ILogger _logger; private readonly IMapper _mapper; public InstructionTestController(IInstructionTestsService instructionTestsService, UserManager userManager, ILogger logger, IMapper mapper) { _instructionTestsService = instructionTestsService; _userManager = userManager; _logger = logger; _mapper = mapper; } /// /// Gets an instruction test by its ID. /// /// The ID of the instruction test. /// An containing the instruction test DTO if found, or a 404 Not Found if not found. /// Returns the instruction test DTO /// If the instruction test is not found [HttpGet("{id}")] public IActionResult GetInstructionTestById(long id) { // TODO: verify admin access / user ownership try { var instructionTest = _instructionTestsService.GetInstructionTestById(id); return Ok(_mapper.Map(instructionTest)); } catch (InstructionTestNotFoundException) { return NotFound(); } } /// /// Gets an instruction test by its instruction ID. /// /// The ID of the instruction. /// An containing the instruction test DTO if found, or a 404 Not Found if not found. /// Returns the instruction test DTO /// If the instruction is not found [HttpGet("instruction/{id}")] public IActionResult GetInstructionTestsByInstructionId(long id) { // TODO: verify admin access / user ownership try { var instructionTest = _instructionTestsService.GetInstructionTestsByInstructionId(id); return Ok(_mapper.Map(instructionTest)); } catch (InstructionTestNotFoundException) { return Ok(new List()); } catch (InstructionNotFoundException) { return NotFound(new BasicResponse() { Code = 404, Message = "Instruction not found" }); } } /// /// Gets all instruction test questions by instruction test ID. /// /// The ID of the instruction test. /// A list of containing the instruction test questions if found, or a 404 Not Found if not found. /// Returns the instruction test questions /// If the instruction test questions are not found [HttpGet("{instructionTestId}/questions")] public IActionResult GetInstructionTestQuestionsByInstructionTestId(long instructionTestId) { // TODO: verify admin access / user ownership try { var instructionTestQuestions = _instructionTestsService.GetInstructionTestQuestionsByInstructionTestId(instructionTestId); return Ok(instructionTestQuestions); } catch (InstructionTestNotFoundException) { return NotFound(); } } /// /// Gets all instruction test results for authorized user by instruction ID. /// /// The ID of the instruction. /// A list of containing the instruction test results if found, or a 404 Not Found if not found. /// Returns the instruction test results /// If the instruction test results are not found [HttpGet("/{instructionTestId}/results")] public async Task GetUserInstructionTestResultsByInstructionTestId(long instructionTestId) { // TODO: verify user ownership string username = User.Claims.First(c => c.Type == "username").Value; long userId = (await _userManager.FindByNameAsync(username))!.Id; try { var instructionTestResults = _instructionTestsService.GetUserInstructionTestResultsByInstructionTestId(userId, instructionTestId); return Ok(instructionTestResults); } catch (InstructionTestNotFoundException) { return NotFound(); } } /// /// Gets all instruction test results for a specific user by instruction test ID (admin access). /// /// The ID of the user whose results are being requested. /// The ID of the instruction. /// A list of containing the instruction test results if found, or a 404 Not Found if not found. /// Returns the instruction test results /// If the instruction test results are not found /// If the user is not an admin [HttpGet("{instructionTestId}/user/{userId}/results")] [Authorize(Roles = "Admin")] public IActionResult GetInstructionTestResultsForUserByInstructionTestId(long userId, long instructionTestId) { try { var instructionTestResults = _instructionTestsService.GetUserInstructionTestResultsByInstructionTestId(userId, instructionTestId); return Ok(instructionTestResults); } catch (InstructionTestNotFoundException) { return NotFound(); } } /// /// Gets all instruction test results for a user by user ID. /// /// The ID of the user. /// A list of containing the instruction test results if found, or a 404 Not Found if not found. /// Returns the instruction test results /// If the instruction test results are not found [HttpGet("user/{id}/results")] public IActionResult GetInstructionTestResultsByUserId(long id) { // TODO: verify admin access / user ownership try { var instructionTestResults = _instructionTestsService.GetInstructionTestResultsByUserId(id); return Ok(instructionTestResults); } catch (InstructionTestNotFoundException) { return NotFound(); } } /// /// Gets all completed instruction test results for a user by user ID. /// /// The ID of the user. /// A list of containing the instruction test results if found, or a 404 Not Found if not found. /// Returns the instruction test results /// If the instruction test results are not found [HttpGet("user/{id}/completed")] public IActionResult GetCompletedInstructionTestsByUserId(long id) { // TODO: verify admin access / user ownership try { var instructionTestResults = _instructionTestsService.GetCompletedInstructionTestsByUserId(id); return Ok(instructionTestResults); } catch (InstructionTestNotFoundException) { return NotFound(); } } /// /// Creates a new instruction test. /// /// The instruction test model. /// A containing the created instruction test if successful, or a 500 Internal Server Error if not successful. /// Returns the created instruction test [HttpPost] public async Task CreateInstructionTest([FromBody] InstructionTestCreateDTO model) { try { var instructionTest = await _instructionTestsService.CreateInstructionTest(model); return Ok(instructionTest); } catch (Exception) { return StatusCode(500, "Failed to create instruction test"); } } /// /// Updates an existing instruction test. /// /// The instruction test model. /// A containing the updated instruction test if successful, or a 500 Internal Server Error if not successful. /// Returns the updated instruction test [HttpPut] [Authorize(Policy = "Admin")] public async Task UpdateInstructionTest([FromBody] InstructionTestCreateDTO model) { try { var instructionTest = await _instructionTestsService.UpdateInstructionTest(model); return Ok(instructionTest); } catch (Exception) { return StatusCode(500, "Failed to update instruction test"); } } /// /// Deletes an existing instruction test. /// /// The ID of the instruction test to delete. /// A /// Returns the deletion status. [HttpDelete("{id}")] [Authorize(Policy = "Admin")] public async Task DeleteInstructionTest(long id) { try { await _instructionTestsService.DeleteInstructionTestByIdAsync(id); return Ok(); } catch (Exception) { return StatusCode(500, "Failed to delete instruction test"); } } [HttpPost("submit")] public async Task SubmitInstructionTest([FromBody] InstructionTestSubmissionDTO model) { // TODO: verify user access string username = User.Claims.First(c => c.Type == "username").Value; long userId = (await _userManager.FindByNameAsync(username))!.Id; try { await _instructionTestsService.SubmitInstructionTestAsync(userId, model); return Ok(); } catch (Exception) { return StatusCode(500, "Failed to submit instruction test"); } } }