Scale unique answer tracking
This commit is contained in:
@@ -15,17 +15,23 @@ public class QuestionsController : ControllerBase
|
||||
private readonly QuestionAttemptStore _attempts;
|
||||
private readonly RatingStore _ratings;
|
||||
private readonly QuestionMediaStore _media;
|
||||
private readonly AnswerStatisticsStore _statistics;
|
||||
private readonly ServiceMetrics _metrics;
|
||||
|
||||
public QuestionsController(
|
||||
QuestionStore questions,
|
||||
QuestionAttemptStore attempts,
|
||||
RatingStore ratings,
|
||||
QuestionMediaStore media)
|
||||
QuestionMediaStore media,
|
||||
AnswerStatisticsStore statistics,
|
||||
ServiceMetrics metrics)
|
||||
{
|
||||
_questions = questions;
|
||||
_attempts = attempts;
|
||||
_ratings = ratings;
|
||||
_media = media;
|
||||
_statistics = statistics;
|
||||
_metrics = metrics;
|
||||
}
|
||||
|
||||
[HttpGet("systems")]
|
||||
@@ -41,7 +47,7 @@ public class QuestionsController : ControllerBase
|
||||
public async Task<IActionResult> Search([FromBody] QuestionSearchRequest req)
|
||||
{
|
||||
var questions = await _questions.SearchAsync(req, User.IsInRole("SUPER"));
|
||||
var percentages = await _attempts.GetPercentagesByQuestionAsync(questions.Select(q => q.ExternalId));
|
||||
var percentages = await _statistics.GetPercentagesByQuestionAsync(questions.Select(q => q.ExternalId));
|
||||
var questionElos = await _ratings.GetQuestionElosAsync(questions.Select(q => q.ExternalId));
|
||||
return Ok(questions.Select(q =>
|
||||
{
|
||||
@@ -58,7 +64,7 @@ public class QuestionsController : ControllerBase
|
||||
if (question is null || (!question.IsPublished && !User.IsInRole("SUPER")))
|
||||
return NotFound();
|
||||
|
||||
var percentages = await _attempts.GetPercentagesForQuestionAsync(question.ExternalId);
|
||||
var percentages = await _statistics.GetPercentagesForQuestionAsync(question.ExternalId);
|
||||
var questionElo = await _ratings.GetQuestionEloAsync(question.ExternalId);
|
||||
return Ok(QuestionResponse.FromModel(question, percentages, questionElo));
|
||||
}
|
||||
@@ -85,23 +91,58 @@ public class QuestionsController : ControllerBase
|
||||
if (string.IsNullOrWhiteSpace(userId))
|
||||
return Unauthorized();
|
||||
|
||||
var wasFirstAttempt = await _attempts.RecordFirstAttemptAsync(
|
||||
var record = await _attempts.RecordFirstAttemptAsync(
|
||||
question.ExternalId,
|
||||
userId,
|
||||
req.ChoiceId.Trim(),
|
||||
req.ChoiceId.Trim() == question.CorrectChoiceId);
|
||||
var rating = await _ratings.ApplyFirstResultAsync(
|
||||
userId,
|
||||
question,
|
||||
req.ChoiceId.Trim() == question.CorrectChoiceId,
|
||||
wasFirstAttempt);
|
||||
if (record.Inserted)
|
||||
{
|
||||
_metrics.AttemptCreated();
|
||||
try
|
||||
{
|
||||
await _statistics.IncrementAsync(record.Attempt);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_metrics.CounterFailure();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_metrics.AttemptDuplicate();
|
||||
}
|
||||
|
||||
var ratingOwner = Guid.NewGuid().ToString("N");
|
||||
var shouldRate = await _attempts.TryAcquireRatingLeaseAsync(
|
||||
record.Attempt.Id ?? "",
|
||||
ratingOwner,
|
||||
TimeSpan.FromSeconds(30));
|
||||
RatingChangeResponse rating;
|
||||
try
|
||||
{
|
||||
rating = await _ratings.ApplyFirstResultAsync(
|
||||
userId,
|
||||
question,
|
||||
record.Attempt.IsCorrect,
|
||||
shouldRate);
|
||||
if (shouldRate)
|
||||
await _attempts.MarkRatingAppliedAsync(record.Attempt.Id ?? "", ratingOwner);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_metrics.RatingFailure();
|
||||
if (shouldRate)
|
||||
await _attempts.ReleaseRatingLeaseAsync(record.Attempt.Id ?? "", ratingOwner);
|
||||
throw;
|
||||
}
|
||||
|
||||
return Ok(new FirstQuestionAttemptResponse
|
||||
{
|
||||
QuestionExternalId = question.ExternalId,
|
||||
ChoiceSelectionPercentages = QuestionResponse.BuildChoiceSelectionPercentages(
|
||||
question,
|
||||
await _attempts.GetPercentagesForQuestionAsync(question.ExternalId)),
|
||||
await _statistics.GetPercentagesForQuestionAsync(question.ExternalId)),
|
||||
QuestionElo = rating.QuestionElo,
|
||||
Rating = rating
|
||||
});
|
||||
@@ -164,13 +205,36 @@ public class QuestionsController : ControllerBase
|
||||
if (string.IsNullOrWhiteSpace(userId))
|
||||
return Unauthorized();
|
||||
|
||||
var wasFirstAttempt = await _attempts.RecordFirstAttemptAsync(
|
||||
var record = await _attempts.RecordFirstAttemptAsync(
|
||||
question.ExternalId,
|
||||
userId,
|
||||
"",
|
||||
false,
|
||||
true);
|
||||
var rating = await _ratings.ApplyFirstResultAsync(userId, question, false, wasFirstAttempt);
|
||||
if (record.Inserted)
|
||||
_metrics.AttemptCreated();
|
||||
else
|
||||
_metrics.AttemptDuplicate();
|
||||
|
||||
var ratingOwner = Guid.NewGuid().ToString("N");
|
||||
var shouldRate = await _attempts.TryAcquireRatingLeaseAsync(
|
||||
record.Attempt.Id ?? "",
|
||||
ratingOwner,
|
||||
TimeSpan.FromSeconds(30));
|
||||
RatingChangeResponse rating;
|
||||
try
|
||||
{
|
||||
rating = await _ratings.ApplyFirstResultAsync(userId, question, false, shouldRate);
|
||||
if (shouldRate)
|
||||
await _attempts.MarkRatingAppliedAsync(record.Attempt.Id ?? "", ratingOwner);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_metrics.RatingFailure();
|
||||
if (shouldRate)
|
||||
await _attempts.ReleaseRatingLeaseAsync(record.Attempt.Id ?? "", ratingOwner);
|
||||
throw;
|
||||
}
|
||||
|
||||
return Ok(new SkipQuestionResponse
|
||||
{
|
||||
@@ -178,7 +242,7 @@ public class QuestionsController : ControllerBase
|
||||
CorrectChoiceId = question.CorrectChoiceId,
|
||||
ChoiceSelectionPercentages = QuestionResponse.BuildChoiceSelectionPercentages(
|
||||
question,
|
||||
await _attempts.GetPercentagesForQuestionAsync(question.ExternalId)),
|
||||
await _statistics.GetPercentagesForQuestionAsync(question.ExternalId)),
|
||||
QuestionElo = rating.QuestionElo,
|
||||
Rating = rating
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user