private string ResolveRandom(string key, RegistrationContext ctx) { byte[] buffer; string result = ""; string[] seg = key.Split(':'); int count = 8; switch (seg[0]) { case "id": result = ctx.Gamespace.Id; break; case "grader_key": result = ctx.Request.GraderKey; break; case "grader_url": result = ctx.Request.GraderUrl; break; case "uid": result = Guid.NewGuid().ToString("n"); break; case "hex": if (seg.Length < 2 || !int.TryParse(seg[1], out count)) { count = 8; } count = Math.Min(count, 256) / 2; buffer = new byte[count]; _random.NextBytes(buffer); result = BitConverter.ToString(buffer).Replace("-", "").ToLower(); break; case "b64": if (seg.Length < 2 || !int.TryParse(seg[1], out count)) { count = 16; } count = Math.Min(count, 256); buffer = new byte[count]; _random.NextBytes(buffer); result = Convert.ToBase64String(buffer); break; case "list": if (seg.Length < 3 || !int.TryParse(seg[1], out count)) { count = 1; } var options = seg.Last() .Split(' ', StringSplitOptions.RemoveEmptyEntries) .ToList(); while (count > 0 && options.Count > 0) { string val = options[_random.Next(options.Count)]; result += val + " "; options.Remove(val); count -= 1; } result = result.Trim(); break; case "int": default: int min = 0; int max = int.MaxValue; if (seg.Length > 1) { string[] range = seg[1].Split('-'); if (range.Length > 1) { int.TryParse(range[0], out min); int.TryParse(range[1], out max); } else { int.TryParse(range[0], out max); } } result = _random.Next(min, max).ToString(); break; } return(result); }
private async Task Create(RegistrationContext ctx, User actor) { var ts = DateTimeOffset.UtcNow; int duration = actor.GamespaceMaxMinutes > 0 ? actor.GamespaceMaxMinutes : ctx.Workspace.DurationMinutes > 0 ? ctx.Workspace.DurationMinutes : _options.DefaultGamespaceMinutes ; if (string.IsNullOrEmpty(ctx.Request.GraderKey)) { ctx.Request.GraderKey = Guid.NewGuid().ToString("n"); } ctx.Gamespace = new Data.Gamespace { Id = Guid.NewGuid().ToString("n"), Name = ctx.Workspace.Name, Workspace = ctx.Workspace, ManagerId = actor.Id, ManagerName = actor.Name, AllowReset = ctx.Request.AllowReset, CleanupGraceMinutes = actor.GamespaceCleanupGraceMinutes, WhenCreated = ts, ExpirationTime = ctx.Request.ResolveExpiration(ts, duration), PlayerCount = ctx.Request.PlayerCount > 0 ? ctx.Request.PlayerCount : ctx.Request.Players.Count(), GraderKey = ctx.Request.GraderKey.ToSha256() }; var gamespace = ctx.Gamespace; foreach (var player in ctx.Request.Players) { gamespace.Players.Add( new Data.Player { SubjectId = player.SubjectId, SubjectName = player.SubjectName } ); } if (gamespace.Players.Any()) { gamespace.Players.First().Permission = Permission.Manager; } // clone challenge var spec = JsonSerializer.Deserialize <ChallengeSpec>(ctx.Workspace.Challenge ?? "{}", jsonOptions); //resolve transforms ResolveTransforms(spec, ctx); // TODO: if customize-script, run and update transforms // select variant, adjusting from 1-based to 0-based index gamespace.Variant = ctx.Request.Variant > 0 ? Math.Min(ctx.Request.Variant, spec.Variants.Count) - 1 : _random.Next(spec.Variants.Count) ; spec.Challenge = spec.Variants .Skip(gamespace.Variant).Take(1) .FirstOrDefault(); // initialize selected challenge spec.Challenge.SetQuestionWeights(); spec.MaxPoints = ctx.Request.Points; spec.MaxAttempts = ctx.Request.MaxAttempts; spec.Variants = null; gamespace.Challenge = JsonSerializer.Serialize(spec, jsonOptions); // apply transforms foreach (var kvp in spec.Transforms) { gamespace.Challenge = gamespace.Challenge.Replace($"##{kvp.Key}##", kvp.Value); } await _store.Create(gamespace); }