137 lines
5.1 KiB
C#
137 lines
5.1 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using QuestionsApi.Models;
|
|
using QuestionsApi.Services;
|
|
using System.Security.Claims;
|
|
|
|
namespace QuestionsApi.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/exam-simulations")]
|
|
[Authorize(Roles = "USER,SUPER")]
|
|
public class ExamSimulationsController(ExamSimulationStore simulations) : ControllerBase
|
|
{
|
|
[HttpGet("readiness")]
|
|
public async Task<IActionResult> Readiness() => Ok(await simulations.GetReadinessAsync(UserId()));
|
|
|
|
[HttpPost]
|
|
public async Task<IActionResult> Create()
|
|
{
|
|
try
|
|
{
|
|
var simulation = await simulations.CreateAsync(UserId());
|
|
return Ok(await simulations.ToResponseAsync(simulation));
|
|
}
|
|
catch (InvalidOperationException exception) { return Conflict(exception.Message); }
|
|
}
|
|
|
|
[HttpGet("preview-results")]
|
|
[Authorize(Roles = "SUPER")]
|
|
public async Task<IActionResult> PreviewResults()
|
|
{
|
|
try { return Ok(await simulations.BuildResultsPreviewAsync(UserId())); }
|
|
catch (InvalidOperationException exception) { return Conflict(exception.Message); }
|
|
}
|
|
|
|
[HttpGet("active")]
|
|
public async Task<IActionResult> Active()
|
|
{
|
|
var simulation = await simulations.FindActiveAsync(UserId());
|
|
return simulation is null ? NoContent() : Ok(await simulations.ToResponseAsync(simulation));
|
|
}
|
|
|
|
[HttpGet("completed")]
|
|
public async Task<IActionResult> Completed([FromQuery] int limit = 20, [FromQuery] string? before = null)
|
|
{
|
|
DateTime? cursor = null;
|
|
if (!string.IsNullOrWhiteSpace(before))
|
|
{
|
|
if (!DateTime.TryParse(before, null, System.Globalization.DateTimeStyles.RoundtripKind, out var parsed))
|
|
return BadRequest("The completed-simulation cursor is invalid.");
|
|
cursor = parsed;
|
|
}
|
|
return Ok(await simulations.GetCompletedAsync(UserId(), limit, cursor));
|
|
}
|
|
|
|
[HttpGet("{id}")]
|
|
public async Task<IActionResult> Get(string id)
|
|
{
|
|
var simulation = await simulations.GetOwnedAsync(id, UserId());
|
|
return simulation is null ? NotFound() : Ok(await simulations.ToResponseAsync(simulation));
|
|
}
|
|
|
|
[HttpPost("{id}/blocks/start")]
|
|
public async Task<IActionResult> StartBlock(string id)
|
|
{
|
|
var simulation = await simulations.GetOwnedAsync(id, UserId());
|
|
if (simulation is null) return NotFound();
|
|
try { return Ok(await simulations.ToResponseAsync(await simulations.StartNextBlockAsync(simulation))); }
|
|
catch (InvalidOperationException exception) { return Conflict(exception.Message); }
|
|
}
|
|
|
|
[HttpPut("{id}/responses")]
|
|
public async Task<IActionResult> SaveResponse(string id, SaveSimulationResponseRequest request)
|
|
{
|
|
var simulation = await simulations.GetOwnedAsync(id, UserId());
|
|
if (simulation is null) return NotFound();
|
|
try { return Ok(await simulations.ToResponseAsync(await simulations.SaveResponseAsync(simulation, request))); }
|
|
catch (ArgumentException exception) { return BadRequest(exception.Message); }
|
|
catch (InvalidOperationException exception) { return Conflict(exception.Message); }
|
|
}
|
|
|
|
[HttpPost("{id}/blocks/submit")]
|
|
public async Task<IActionResult> SubmitBlock(string id)
|
|
{
|
|
var simulation = await simulations.GetOwnedAsync(id, UserId());
|
|
if (simulation is null) return NotFound();
|
|
try { return Ok(await simulations.ToResponseAsync(await simulations.SubmitBlockAsync(simulation))); }
|
|
catch (InvalidOperationException exception) { return Conflict(exception.Message); }
|
|
}
|
|
|
|
[HttpPost("{id}/abandon")]
|
|
public async Task<IActionResult> Abandon(string id)
|
|
{
|
|
var simulation = await simulations.GetOwnedAsync(id, UserId());
|
|
if (simulation is null) return NotFound();
|
|
await simulations.AbandonAsync(simulation);
|
|
return NoContent();
|
|
}
|
|
|
|
private string UserId() => User.FindFirstValue(ClaimTypes.NameIdentifier)
|
|
?? User.FindFirstValue(ClaimTypes.Name)
|
|
?? User.Identity?.Name
|
|
?? throw new UnauthorizedAccessException();
|
|
}
|
|
|
|
[ApiController]
|
|
[Route("api/step3-outcomes")]
|
|
[Authorize(Roles = "USER,SUPER")]
|
|
public class Step3OutcomesController(ExamSimulationStore simulations) : ControllerBase
|
|
{
|
|
[HttpGet("me")]
|
|
public async Task<IActionResult> Get()
|
|
{
|
|
var outcome = await simulations.GetOutcomeAsync(UserId());
|
|
return outcome is null ? NoContent() : Ok(outcome);
|
|
}
|
|
|
|
[HttpPut("me")]
|
|
public async Task<IActionResult> Put(UpsertStep3OutcomeRequest request)
|
|
{
|
|
try { return Ok(await simulations.UpsertOutcomeAsync(UserId(), request)); }
|
|
catch (ArgumentException exception) { return BadRequest(exception.Message); }
|
|
}
|
|
|
|
[HttpDelete("me")]
|
|
public async Task<IActionResult> Delete()
|
|
{
|
|
await simulations.DeleteOutcomeAsync(UserId());
|
|
return NoContent();
|
|
}
|
|
|
|
private string UserId() => User.FindFirstValue(ClaimTypes.NameIdentifier)
|
|
?? User.FindFirstValue(ClaimTypes.Name)
|
|
?? User.Identity?.Name
|
|
?? throw new UnauthorizedAccessException();
|
|
}
|