Local user://settings.cfg meant zoom level didn't follow a student across devices/browsers. Question bank and CCS text scale now live on the user's study profile in Mongo (QuestionTextScale/CcsTextScale), synced through a new PUT /api/profile/me/text-scale endpoint and the existing preferences GET/cache already used for study preferences. Both question_player.gd and ccs_service.gd read the synced value at startup and react to AccountProfileService.profile_changed so a value pulled down after login (or changed from another session) applies without a restart. Backend validates the 0.85-1.35 range and updates only the field(s) provided via a targeted $set, so it can't clobber the other scale or the unrelated study-profile preferences.
74 lines
2.7 KiB
C#
74 lines
2.7 KiB
C#
using MongoDB.Bson;
|
|
using MongoDB.Bson.Serialization.Attributes;
|
|
|
|
namespace QuestionsApi.Models;
|
|
|
|
public sealed class UserStudyProfile
|
|
{
|
|
[BsonId]
|
|
[BsonRepresentation(BsonType.ObjectId)]
|
|
public string? Id { get; set; }
|
|
public string UserId { get; set; } = "";
|
|
public DateTime? TargetExamDate { get; set; }
|
|
public string PreparationStage { get; set; } = "pre_dedicated";
|
|
public int WeeklyGoalHours { get; set; } = 10;
|
|
public string PreferredStudyMode { get; set; } = "mixed";
|
|
public double QuestionTextScale { get; set; } = 1.0;
|
|
public double CcsTextScale { get; set; } = 1.0;
|
|
public int Revision { get; set; }
|
|
public DateTime UpdatedUtc { get; set; } = DateTime.UtcNow;
|
|
}
|
|
|
|
public sealed class UpdateUserStudyProfileRequest
|
|
{
|
|
public DateTime? TargetExamDate { get; set; }
|
|
public string PreparationStage { get; set; } = "pre_dedicated";
|
|
public int WeeklyGoalHours { get; set; } = 10;
|
|
public string PreferredStudyMode { get; set; } = "mixed";
|
|
}
|
|
|
|
public sealed class UpdateTextScaleRequest
|
|
{
|
|
public double? QuestionTextScale { get; set; }
|
|
public double? CcsTextScale { get; set; }
|
|
}
|
|
|
|
public sealed class DeletedUserTombstone
|
|
{
|
|
[BsonId]
|
|
public string UserId { get; set; } = "";
|
|
public DateTime DeletedUtc { get; set; } = DateTime.UtcNow;
|
|
}
|
|
|
|
public static class UserStudyProfileValidator
|
|
{
|
|
private static readonly HashSet<string> Stages = ["pre_dedicated", "dedicated", "final_review"];
|
|
private static readonly HashSet<int> Goals = [5, 10, 15, 20, 25];
|
|
private static readonly HashSet<string> Modes = ["mixed", "question_bank", "ccs", "exam_simulation"];
|
|
|
|
public static string? Validate(UpdateUserStudyProfileRequest request)
|
|
{
|
|
if (!Stages.Contains(request.PreparationStage)) return "Invalid preparation stage.";
|
|
if (!Goals.Contains(request.WeeklyGoalHours)) return "Weekly goal must be 5, 10, 15, 20, or 25 hours.";
|
|
if (!Modes.Contains(request.PreferredStudyMode)) return "Invalid preferred study mode.";
|
|
if (request.TargetExamDate?.Kind == DateTimeKind.Local)
|
|
request.TargetExamDate = request.TargetExamDate.Value.ToUniversalTime();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static class UpdateTextScaleRequestValidator
|
|
{
|
|
private const double Min = 0.85;
|
|
private const double Max = 1.35;
|
|
|
|
public static string? Validate(UpdateTextScaleRequest request)
|
|
{
|
|
if (request.QuestionTextScale is { } questionScale && (questionScale < Min || questionScale > Max))
|
|
return "Question text scale must be between 0.85 and 1.35.";
|
|
if (request.CcsTextScale is { } ccsScale && (ccsScale < Min || ccsScale > Max))
|
|
return "CCS text scale must be between 0.85 and 1.35.";
|
|
return null;
|
|
}
|
|
}
|