Add server-authoritative RZ Coin rewards

This commit is contained in:
hz
2026-08-01 01:28:38 -05:00
parent 8c439c6294
commit ddc36a8048
24 changed files with 670 additions and 104 deletions
@@ -14,7 +14,9 @@ public sealed class ReviewQueueController(
QuestionStore questions,
AnswerStatisticsStore statistics,
RatingStore ratings,
QuestionBookmarkStore bookmarks) : ControllerBase
QuestionBookmarkStore bookmarks,
CreditStore credits,
MasteryAwardService masteryAwards) : ControllerBase
{
[HttpPost("next")]
public async Task<IActionResult> Next([FromBody] ReviewQueueNextRequest req)
@@ -71,6 +73,7 @@ public sealed class ReviewQueueController(
return BadRequest("presentedChoiceIds must include valid selected and correct choices");
}
await masteryAwards.PrepareAsync(userId);
var result = await queue.RecordReviewAsync(
userId,
req.ClientAttemptId,
@@ -81,12 +84,27 @@ public sealed class ReviewQueueController(
choiceId == question.CorrectChoiceId,
req.DurationSeconds);
if (result is null) return Conflict("review cycle is no longer active");
var awards = new List<CreditAward>();
if (result.Attempt.IsCorrect)
{
var delayed = result.Item is not null
&& result.Attempt.CreatedUtc - result.Item.CreatedUtc >= TimeSpan.FromHours(24);
var award = await credits.AwardAsync(userId, new CreditAwardRequest(
$"review:{result.Attempt.Id}", CreditEconomy.ReviewAmount(delayed),
delayed ? CreditReasonCodes.DelayedRecovery : CreditReasonCodes.ScheduledReview,
delayed ? "Delayed recovery of a missed question" : "Correct scheduled review",
"question_review", result.Attempt.Id));
if (award.Award is not null) awards.Add(award.Award);
}
awards.AddRange(await masteryAwards.AwardPromotionsAsync(userId));
return Ok(new ReviewQueueAttemptResponse
{
QuestionExternalId = question.ExternalId,
IsCorrect = result.Attempt.IsCorrect,
QueueState = result.Item?.State ?? ReviewQueueStates.Pending,
PendingCount = checked((int)await queue.CountPendingAsync(userId))
PendingCount = checked((int)await queue.CountPendingAsync(userId)),
Credits = await credits.GetStatusAsync(userId),
CreditAwards = awards
});
}