Add SUPER simulation review sample

This commit is contained in:
hz
2026-07-14 21:46:29 -05:00
parent 3b946c2bc5
commit 27c48411f1
6 changed files with 66 additions and 7 deletions
@@ -33,6 +33,14 @@ public class ExamSimulationsController(ExamSimulationStore simulations) : Contro
catch (InvalidOperationException exception) { return Conflict(exception.Message); }
}
[HttpPost("sample-completed")]
[Authorize(Roles = "SUPER")]
public async Task<IActionResult> CreateSampleCompleted()
{
try { return Ok(ExamSimulationStore.ToHistorySummary(await simulations.CreateSampleCompletedAsync(UserId()))); }
catch (InvalidOperationException exception) { return Conflict(exception.Message); }
}
[HttpGet("active")]
public async Task<IActionResult> Active()
{
@@ -20,6 +20,7 @@ public class ExamSimulation
public string UserId { get; set; } = "";
public string State { get; set; } = ExamSimulationStates.BetweenBlocks;
public string ModelVersion { get; set; } = ExamSimulationScoring.ModelVersion;
public bool IsSample { get; set; }
public List<ExamSimulationItem> Items { get; set; } = [];
public List<ExamSimulationResponse> Responses { get; set; } = [];
public int CurrentBlock { get; set; } = -1;
@@ -141,6 +142,7 @@ public class ExamSimulationHistorySummary
{
public string Id { get; set; } = "";
public string State { get; set; } = "";
public bool IsSample { get; set; }
public DateTime CreatedUtc { get; set; }
public DateTime UpdatedUtc { get; set; }
public DateTime? CompletedUtc { get; set; }
@@ -97,7 +97,12 @@ public class ExamSimulationStore
return simulation;
}
public async Task<ExamSimulationStateResponse> BuildResultsPreviewAsync(string userId)
public async Task<ExamSimulationStateResponse> BuildResultsPreviewAsync(string userId) =>
await ToResponseAsync(await BuildSampleAsync(userId, false));
public Task<ExamSimulation> CreateSampleCompletedAsync(string userId) => BuildSampleAsync(userId, true);
private async Task<ExamSimulation> BuildSampleAsync(string userId, bool persist)
{
var bank = (await _questions.GetPublishedAsync()).Where(question => question.Choices.Count >= 5).ToList();
if (bank.Count < RequiredQuestions)
@@ -130,19 +135,25 @@ public class ExamSimulationStore
};
}).ToList();
var responseMap = responses.ToDictionary(item => item.QuestionExternalId, StringComparer.Ordinal);
return new ExamSimulationStateResponse
var now = DateTime.UtcNow;
var simulation = new ExamSimulation
{
Id = "preview",
UserId = userId,
State = ExamSimulationStates.Completed,
IsSample = true,
CurrentBlock = BlockSizes.Length - 1,
BreakSecondsRemaining = 3300,
Items = items,
Responses = responses,
Score = ExamSimulationScoring.Calculate(items, responseMap, questionMap),
CreatedUtc = now,
UpdatedUtc = now,
CompletedUtc = now,
BlueprintTargets = targets,
BlueprintActual = items.GroupBy(item => item.BlueprintCategory).ToDictionary(group => group.Key, group => group.Count()),
ReviewQuestions = items.Select(item => QuestionResponse.FromModelWithChoices(
questionMap[item.QuestionExternalId], item.PresentedChoiceIds, item.QuestionElo)).ToList()
BlueprintActual = items.GroupBy(item => item.BlueprintCategory).ToDictionary(group => group.Key, group => group.Count())
};
if (persist) await _simulations.InsertOneAsync(simulation);
return simulation;
}
public async Task<ExamSimulation?> FindActiveAsync(string userId) =>
@@ -205,6 +216,7 @@ public class ExamSimulationStore
{
Id = item.Id ?? "",
State = item.State,
IsSample = item.IsSample,
CreatedUtc = item.CreatedUtc,
UpdatedUtc = item.UpdatedUtc,
CompletedUtc = item.CompletedUtc,