Ejemplo n.º 1
0
        public async Task <Challenge> Preview(NewChallenge model)
        {
            var entity = await Store.Load(model);

            if (entity is Data.Challenge)
            {
                return(Mapper.Map <Challenge>(entity));
            }

            var spec = await Store.DbContext.ChallengeSpecs.FindAsync(model.SpecId);

            //check preview cache, else mojo
            var cachestate = _localcache.Get <string>(spec.ExternalId);

            if (cachestate == null)
            {
                var state = await Mojo.PreviewGamespaceAsync(spec.ExternalId);

                Transform(state);

                cachestate = JsonSerializer.Serialize(state);

                if (cachestate != null)
                {
                    _localcache.Set(spec.ExternalId, cachestate, new TimeSpan(0, 60, 0));
                }
            }

            var challenge = Mapper.Map <Data.Challenge>(spec);

            challenge.State = cachestate;

            return(Mapper.Map <Challenge>(challenge));
        }
Ejemplo n.º 2
0
        private async Task _validate(NewChallenge model)
        {
            if ((await PlayerExists(model.PlayerId)).Equals(false))
            {
                throw new ResourceNotFound();
            }

            if ((await SpecExists(model.SpecId)).Equals(false))
            {
                throw new ResourceNotFound();
            }

            var player = await _store.DbContext.Players.FindAsync(model.PlayerId);

            if (player.IsLive.Equals(false))
            {
                throw new SessionNotActive();
            }

            var spec = await _store.DbContext.ChallengeSpecs.FindAsync(model.SpecId);

            if (spec.GameId != player.GameId)
            {
                throw new ActionForbidden();
            }

            // Note: not checking "already exists" since this is used idempotently

            await Task.CompletedTask;
        }
Ejemplo n.º 3
0
        public async Task <Challenge> Create([FromBody] NewChallenge model)
        {
            AuthorizeAny(
                () => Actor.IsDirector,
                () => IsSelf(model.PlayerId).Result
                );

            await Validate(model);

            if (Actor.IsTester.Equals(false))
            {
                model.Variant = 0;
            }

            string graderUrl = string.Format(
                "{0}://{1}{2}",
                Request.Scheme,
                Request.Host,
                Url.Action("Grade")
                );

            var result = await ChallengeService.GetOrAdd(model, Actor.Id, graderUrl);

            await Hub.Clients.Group(result.TeamId).ChallengeEvent(
                new HubEvent <Challenge>(result, EventAction.Updated)
                );

            return(result);
        }
Ejemplo n.º 4
0
        public async Task <Challenge> Preview([FromBody] NewChallenge model)
        {
            AuthorizeAny(
                () => IsSelf(model.PlayerId).Result
                );

            await Validate(model);

            return(await ChallengeService.Preview(model));
        }
Ejemplo n.º 5
0
        public async Task <Challenge> Load(NewChallenge model)
        {
            var player = await DbContext.Players.FindAsync(model.PlayerId);

            return(await DbSet
                   .Include(c => c.Player)
                   .FirstOrDefaultAsync(c =>
                                        c.SpecId == model.SpecId &&
                                        (
                                            c.PlayerId == model.PlayerId ||
                                            c.TeamId == player.TeamId
                                        )
                                        )
                   );
        }
Ejemplo n.º 6
0
        public async Task <Challenge> GetOrAdd(NewChallenge model, string actorId, string graderUrl)
        {
            var entity = await Store.Load(model);

            if (entity is not null)
            {
                return(Mapper.Map <Challenge>(entity));
            }

            var player = await Store.DbContext.Players.FindAsync(model.PlayerId);

            var game = await Store.DbContext.Games
                       .Include(g => g.Prerequisites)
                       .Where(g => g.Id == player.GameId)
                       .FirstOrDefaultAsync()
            ;

            if ((await Store.ChallengeGamespaceCount(player.TeamId)) >= game.GamespaceLimitPerSession)
            {
                throw new GamespaceLimitReached();
            }

            if ((await IsUnlocked(player, game, model.SpecId)).Equals(false))
            {
                throw new ChallengeLocked();
            }

            var lockkey = $"{player.TeamId}{model.SpecId}";
            var lockval = Guid.NewGuid();
            var locked  = _localcache.GetOrCreate(lockkey, entry => {
                entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60);
                return(lockval);
            });

            if (locked != lockval)
            {
                throw new ChallengeStartPending();
            }

            var spec = await Store.DbContext.ChallengeSpecs.FindAsync(model.SpecId);

            string graderKey = Guid.NewGuid().ToString("n");

            int playerCount = (game.AllowTeam)
                ? await Store.DbContext.Players.CountAsync(
                p => p.TeamId == player.TeamId
                )
                : 1
            ;

            entity = Mapper.Map <Data.Challenge>(model);

            Mapper.Map(spec, entity);

            entity.Player = player;

            entity.TeamId = player.TeamId;

            entity.GraderKey = graderKey.ToSha256();

            try {
                var state = await Mojo.RegisterGamespaceAsync(new GamespaceRegistration
                {
                    Players = new RegistrationPlayer[] {
                        new RegistrationPlayer {
                            SubjectId   = player.TeamId,
                            SubjectName = player.Name
                        }
                    },
                    ResourceId     = entity.ExternalId,
                    Variant        = model.Variant,
                    Points         = spec.Points,
                    MaxAttempts    = game.MaxAttempts,
                    StartGamespace = true,
                    ExpirationTime = entity.Player.SessionEnd,
                    GraderKey      = graderKey,
                    GraderUrl      = graderUrl,
                    PlayerCount    = playerCount
                });

                Transform(state);

                Mapper.Map(state, entity);

                entity.Events.Add(new Data.ChallengeEvent
                {
                    Id        = Guid.NewGuid().ToString("n"),
                    UserId    = actorId,
                    TeamId    = entity.TeamId,
                    Timestamp = DateTimeOffset.UtcNow,
                    Type      = ChallengeEventType.Started
                });

                await Store.Create(entity);

                await Store.UpdateEtd(entity.SpecId);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                _localcache.Remove(lockkey);
            }

            return(Mapper.Map <Challenge>(entity));
        }