예제 #1
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)]
            HttpRequest req,
            ILogger log,
            [BindConferenceConfig]
            ConferenceConfig conference,
            [BindSubmissionsConfig]
            SubmissionsConfig submissions,
            [BindVotingConfig]
            VotingConfig voting,
            [BindTitoSyncConfig]
            TitoSyncConfig tito,
            [BindAppInsightsSyncConfig]
            AppInsightsSyncConfig appInsights)
        {
            // Get submissions
            var(submissionsRepo, submittersRepo) = await submissions.GetRepositoryAsync();

            var receivedSubmissions = await submissionsRepo.GetAllAsync(conference.ConferenceInstance);

            var presenters = await submittersRepo.GetAllAsync(conference.ConferenceInstance);

            // Get votes
            var votingRepo = await voting.GetRepositoryAsync();

            var votes = await votingRepo.GetAllAsync(conference.ConferenceInstance);

            // Get Tito ids
            var ebRepo = await tito.GetRepositoryAsync();

            var titoTickets = await ebRepo.GetAllAsync(conference.ConferenceInstance);

            var titoIds = titoTickets.Select(o => o.TicketId).ToArray();

            // Get AppInsights sessions
            var aiRepo = await appInsights.GetRepositoryAsync();

            var userSessions = await aiRepo.GetAllAsync(conference.ConferenceInstance);

            // Analyse votes
            var analysedVotes = votes.Select(v => new AnalysedVote(v, votes, titoIds, userSessions)).ToArray();

            // Get summary
            var sessions = receivedSubmissions.Select(x => x.GetSession())
                           .Select(s => new SessionWithVotes
            {
                Id         = s.Id.ToString(),
                Title      = s.Title,
                Abstract   = s.Abstract,
                Format     = s.Format,
                Level      = s.Level,
                Tags       = s.Tags,
                Presenters = GetPresentersFromSession(presenters, s, ps => ps.Select(p =>
                                                                                     new Presenter
                {
                    Id              = p.Id.ToString(),
                    Name            = p.Name,
                    Tagline         = p.Tagline,
                    Bio             = p.Bio,
                    ProfilePhotoUrl = p.ProfilePhotoUrl,
                    TwitterHandle   = p.TwitterHandle,
                    WebsiteUrl      = p.WebsiteUrl
                }).ToArray()),
                CreatedDate          = s.CreatedDate,
                ModifiedDate         = s.ModifiedDate,
                IsUnderrepresented   = GetPresentersFromSession(presenters, s, IsUnderrepresented),
                Pronoun              = CollapsePresenterField(presenters, s, p => p.DataFields["Your pronoun"]),
                JobRole              = CollapsePresenterField(presenters, s, p => p.DataFields["How would you identify your job role"]),
                SpeakingExperience   = CollapsePresenterField(presenters, s, p => p.DataFields["How much speaking experience do you have?"]),
                VoteSummary          = new VoteSummary(analysedVotes.Where(v => v.Vote.GetSessionIds().Contains(s.Id.ToString())).ToArray()),
                FirstPreferenceCount = analysedVotes.Count(v => v.Vote.GetSessionIds()[0] == s.Id.ToString()),
                Top3PreferenceCount  = analysedVotes.Count(v => new [] { v.Vote.GetSessionIds()[0], v.Vote.GetSessionIds()[1], v.Vote.GetSessionIds()[2] }.Contains(s.Id.ToString()))
            })
                           .OrderBy(s => s.Title)
                           .ToArray();

            var tagSummaries = sessions.SelectMany(s => s.Tags).Distinct().OrderBy(t => t)
                               .Select(tag => new TagSummary
            {
                Tag         = tag,
                VoteSummary = new VoteSummary(sessions.Where(s => s.Tags.Contains(tag)).SelectMany(s => analysedVotes.Where(v => v.Vote.SessionIds.Contains(s.Id))).ToArray())
            }).ToArray();

            var response = new GetVotesResponse
            {
                VoteSummary  = new VoteSummary(analysedVotes),
                Sessions     = sessions.OrderByDescending(s => s.VoteSummary.RawTotal).ToArray(),
                TagSummaries = tagSummaries,
                Votes        = analysedVotes,
                UserSessions = userSessions.Select(x => new UserSession {
                    UserId = x.UserId, VoteId = x.VoteId, StartTime = x.StartTime
                }).ToArray()
            };
            var settings = new JsonSerializerSettings {
                ContractResolver = new DefaultContractResolver()
            };

            return(new JsonResult(response, settings));
        }
예제 #2
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]
            HttpRequestMessage req,
            ILogger log,
            [BindConferenceConfig]
            ConferenceConfig conference,
            [BindKeyDatesConfig]
            KeyDatesConfig keyDates,
            [BindSubmissionsConfig]
            SubmissionsConfig submissions,
            [BindVotingConfig]
            VotingConfig voting,
            [BindTitoSyncConfig]
            TitoSyncConfig tickets
            )
        {
            var vote = await req.Content.ReadAsAsync <VoteRequest>();

            var ip = req.GetIpAddress();

            // Within voting window, allowing for 5 minutes of clock drift
            if (keyDates.Before(x => x.VotingAvailableFromDate) || keyDates.After(x => x.VotingAvailableToDate, TimeSpan.FromMinutes(5)))
            {
                log.LogWarning("Attempt to access SubmitVote endpoint outside of allowed window of {start} -> {end}.", keyDates.VotingAvailableFromDate, keyDates.VotingAvailableToDate);
                return(new StatusCodeResult((int)HttpStatusCode.NotFound));
            }

            // Correct number of votes
            var numVotesSubmitted = vote.SessionIds?.Length ?? 0;

            if (numVotesSubmitted < conference.MinVotes || numVotesSubmitted > conference.MaxVotes)
            {
                log.LogWarning("Attempt to submit to SubmitVotes endpoint with incorrect number of votes ({numVotes} rather than {minVotes} - {maxVotes}).", numVotesSubmitted, conference.MinVotes, conference.MaxVotes);
                return(new StatusCodeResult((int)HttpStatusCode.BadRequest));
            }

            // Correct number of indices
            if (numVotesSubmitted != vote.Indices?.Length)
            {
                log.LogWarning("Attempt to submit to SubmitVotes endpoint without matching indices ({numIndices} vs {numVotes}).", vote.Indices?.Length, numVotesSubmitted);
                return(new StatusCodeResult((int)HttpStatusCode.BadRequest));
            }

            // Valid voting start time, allowing for 5 minutes of clock drift
            if (vote.VotingStartTime > keyDates.Now.AddMinutes(5) || vote.VotingStartTime < keyDates.VotingAvailableFromDate.AddMinutes(-5))
            {
                log.LogWarning("Attempt to submit to SubmitVotes endpoint with invalid start time (got {submittedStartTime} instead of {votingStartTime} - {now}).", vote.VotingStartTime, keyDates.VotingAvailableFromDate, keyDates.Now);
                return(new StatusCodeResult((int)HttpStatusCode.BadRequest));
            }

            if (voting.TicketNumberWhileVotingValue == TicketNumberWhileVoting.Required)
            {
                // Get tickets
                var ticketsRepo = await tickets.GetRepositoryAsync();

                var matchedTicket = await ticketsRepo.GetAsync(conference.ConferenceInstance,
                                                               vote.TicketNumber.ToUpperInvariant());

                // Only if you have a valid ticket
                if (string.IsNullOrEmpty(vote.TicketNumber) || matchedTicket == null)
                {
                    log.LogWarning(
                        "Attempt to submit to SubmitVote endpoint without a valid ticket. Ticket id sent was {ticketNumber}",
                        vote.TicketNumber);
                    return(new StatusCodeResult((int)HttpStatusCode.BadRequest));
                }
            }

            // Get submitted sessions
            var(submissionsRepo, _) = await submissions.GetRepositoryAsync();

            var allSubmissions = await submissionsRepo.GetAllAsync(conference.ConferenceInstance);

            var allSubmissionIds = allSubmissions.Where(s => s.Session != null).Select(s => s.Id.ToString()).ToArray();

            // Valid session ids
            if (vote.SessionIds.Any(id => !allSubmissionIds.Contains(id)) || vote.SessionIds.Distinct().Count() != vote.SessionIds.Count())
            {
                log.LogWarning("Attempt to submit to SubmitVotes endpoint with at least one invalid or duplicate submission id (got {sessionIds}).", JsonConvert.SerializeObject(vote.SessionIds));
                return(new StatusCodeResult((int)HttpStatusCode.BadRequest));
            }

            // Valid indices
            if (vote.Indices.Any(index => index <= 0 || index > allSubmissionIds.Count()) || vote.Indices.Distinct().Count() != vote.Indices.Count())
            {
                log.LogWarning("Attempt to submit to SubmitVotes endpoint with at least one invalid or duplicate index (got {indices} when the number of sessions is {totalNumberOfSessions}).", JsonConvert.SerializeObject(vote.Indices), allSubmissionIds.Count());
                return(new StatusCodeResult((int)HttpStatusCode.BadRequest));
            }

            // No existing vote
            var repo = await voting.GetRepositoryAsync();

            var existing = await repo.GetAsync(conference.ConferenceInstance, vote.Id.ToString());

            if (existing != null)
            {
                log.LogWarning("Attempt to submit to SubmitVotes endpoint with a duplicate vote (got {voteId}).", vote.Id);
                return(new StatusCodeResult((int)HttpStatusCode.Conflict));
            }

            // Save vote
            log.LogInformation("Successfully received vote with Id {voteId}; persisting...", vote.Id);
            var voteToPersist = new Vote(conference.ConferenceInstance, vote.Id, vote.SessionIds, vote.Indices, vote.TicketNumber?.ToUpperInvariant(), ip, vote.VoterSessionId, vote.VotingStartTime, keyDates.Now);            await repo.CreateAsync(voteToPersist);

            return(new StatusCodeResult((int)HttpStatusCode.NoContent));
        }