public static async Task Run(
            [TimerTrigger("%SessionizeReadModelSyncSchedule%")]
            TimerInfo timer,
            ILogger log,
            [BindConferenceConfig]
            ConferenceConfig conference,
            [BindKeyDatesConfig]
            KeyDatesConfig keyDates,
            [BindSessionsConfig]
            SessionsConfig sessions,
            [BindSessionizeSyncConfig]
            SessionizeSyncConfig sessionize
            )
        {
            if (keyDates.Before(x => x.StopSyncingSessionsFromDate) || keyDates.After(x => x.StopSyncingAgendaFromDate))
            {
                log.LogInformation("SessionizeAgendaSync sync not active");
                return;
            }

            using (var httpClient = new HttpClient())
            {
                var apiClient = new SessionizeApiClient(httpClient, sessionize.AgendaApiKey);
                var(sessionsRepo, presentersRepo) = await sessions.GetRepositoryAsync();

                await SyncService.Sync(apiClient, sessionsRepo, presentersRepo, log, new DateTimeProvider(), conference.ConferenceInstance);
            }
        }
Пример #2
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]
            HttpRequest req,
            ILogger log,
            [BindConferenceConfig]
            ConferenceConfig conference,
            [BindKeyDatesConfig]
            KeyDatesConfig keyDates,
            [BindSubmissionsConfig]
            SubmissionsConfig submissions
            )
        {
            if (keyDates.Before(x => x.SubmissionsAvailableFromDate) || keyDates.After(x => x.SubmissionsAvailableToDate))
            {
                log.LogWarning("Attempt to access GetSubmissions endpoint outside of allowed window of {start} -> {end}.", keyDates.SubmissionsAvailableFromDate, keyDates.SubmissionsAvailableToDate);
                return(new StatusCodeResult(404));
            }

            var(submissionsRepo, submittersRepo) = await submissions.GetRepositoryAsync();

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

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

            var submissionData = receivedSubmissions.Where(x => x.Session != null)
                                 .Select(x => x.GetSession())
                                 .Select(s => new Submission
            {
                Id         = s.Id.ToString(),
                Title      = s.Title,
                Abstract   = s.Abstract,
                Format     = s.Format,
                Level      = s.Level,
                Tags       = s.Tags,
                Presenters = conference.AnonymousSubmissions
                        ? new Submitter[0]
                        : s.PresenterIds.Select(pId => submitters.Where(p => p.Id == pId).Select(p => p.GetPresenter()).Select(p => new Submitter
                {
                    Id              = p.Id.ToString(),
                    Name            = p.Name,
                    Tagline         = p.Tagline,
                    Bio             = p.Bio,
                    ProfilePhotoUrl = p.ProfilePhotoUrl,
                    TwitterHandle   = p.TwitterHandle,
                    WebsiteUrl      = p.WebsiteUrl
                }).Single()).ToArray()
            })
                                 .OrderBy(x => Random.Next())
                                 .ToArray();

            var settings = new JsonSerializerSettings();

            settings.ContractResolver = new DefaultContractResolver();

            return(new JsonResult(submissionData, settings));
        }
Пример #3
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]
            HttpRequest req,
            ILogger log,
            [BindConferenceConfig]
            ConferenceConfig conference,
            [BindKeyDatesConfig]
            KeyDatesConfig keyDates,
            [BindSessionsConfig]
            SessionsConfig sessionsConfig)
        {
            if (keyDates.Before(x => x.SubmissionsAvailableToDate))
            {
                log.LogWarning("Attempt to access GetAgenda endpoint before they are available at {availableDate}.", keyDates.SubmissionsAvailableToDate);
                return(new StatusCodeResult(404));
            }

            var(sessionsRepo, presentersRepo) = await sessionsConfig.GetRepositoryAsync();

            var sessions = await sessionsRepo.GetAllAsync(conference.ConferenceInstance);

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

            var agenda = sessions.Select(x => x.GetSession())
                         .Select(s => new Session
            {
                Id         = s.Id.ToString(),
                Title      = s.Title,
                Abstract   = s.Abstract,
                Format     = s.Format,
                Level      = s.Level,
                Tags       = s.Tags,
                Presenters = s.PresenterIds.Select(pId => presenters.Where(p => p.Id == pId).Select(p => p.GetPresenter()).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
                }).Single()).ToArray()
            })
                         .OrderBy(x => x.Title)
                         .ToArray();

            var settings = new JsonSerializerSettings();

            settings.ContractResolver = new DefaultContractResolver();

            return(new JsonResult(agenda, settings));
        }
Пример #4
0
        public static async Task Run(
            [TimerTrigger("%AppInsightsSyncSchedule%")]
            TimerInfo timer,
            ILogger log,
            [BindConferenceConfig]
            ConferenceConfig conference,
            [BindAppInsightsSyncConfig]
            AppInsightsSyncConfig appInsights,
            [BindKeyDatesConfig]
            KeyDatesConfig keyDates
            )
        {
            if (keyDates.Before(x => x.StartSyncingAppInsightsFromDate) || keyDates.After(x => x.StopSyncingAppInsightsFromDate, TimeSpan.FromMinutes(10)))
            {
                log.LogInformation("AppInsightsSync sync not active");
                return;
            }

            var http = new HttpClient();

            http.DefaultRequestHeaders.Add("x-api-key", appInsights.ApplicationKey);

            var response = await http.GetAsync($"https://api.applicationinsights.io/v1/apps/{appInsights.ApplicationId}/query?timespan={WebUtility.UrlEncode(keyDates.StartSyncingAppInsightsFrom)}%2F{WebUtility.UrlEncode(keyDates.StopSyncingAppInsightsFrom)}&query={WebUtility.UrlEncode(VotingUserQuery.Query)}");

            response.EnsureSuccessStatusCode();
            var content = await response.Content.ReadAsAsync <AppInsightsQueryResponse <VotingUserQuery> >();

            var currentRecords = content.Data.Select(x => new AppInsightsVotingUser(conference.ConferenceInstance, x.UserId, x.VoteId, x.StartTime)).ToArray();

            var repo = await appInsights.GetRepositoryAsync();

            var existingRecords = await repo.GetAllAsync(conference.ConferenceInstance);

            // Taking up to 100 records to meet Azure Storage Bulk Operation limit
            var newRecords = currentRecords.Except(existingRecords, new AppInsightsVotingUserComparer()).Take(100).ToArray();

            log.LogInformation("Found {existingCount} existing app insights voting users and {currentCount} current app insights voting users. Inserting {newCount} new orders.", existingRecords.Count, currentRecords.Length, newRecords.Length);
            await repo.CreateBatchAsync(newRecords);
        }
Пример #5
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));
        }
Пример #6
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]
            HttpRequest req,
            ILogger log,
            [BindConferenceConfig]
            ConferenceConfig conference,
            [BindKeyDatesConfig]
            KeyDatesConfig keyDates,
            [BindSubmissionsConfig]
            SubmissionsConfig submissions
            )
        {
            if (keyDates.Before(x => x.SubmissionsAvailableFromDate) || keyDates.After(x => x.SubmissionsAvailableToDate))
            {
                log.LogWarning("Attempt to access GetSubmissions endpoint outside of allowed window of {start} -> {end}.", keyDates.SubmissionsAvailableFromDate, keyDates.SubmissionsAvailableToDate);
                return(new StatusCodeResult(404));
            }

            var(submissionsRepo, submittersRepo) = await submissions.GetRepositoryAsync();

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

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

            var submissionData = receivedSubmissions.Where(x => x.Session != null)
                                 .Select(x => x.GetSession())
                                 .Select(s =>
            {
                var otherTagsKeys   = s.DataFields.Keys.Where(k => SessionizeAdapter.TagsTitles.Contains(k)).ToList();
                var otherTagsValues = new List <string>();
                foreach (var key in otherTagsKeys)
                {
                    var found = s.DataFields.TryGetValue(key, out var value);
                    if (found)
                    {
                        otherTagsValues.AddRange(value.Split(',').Select(v => v.Trim()).ToList());
                    }
                }

                var tags = otherTagsValues.Union(s.Tags, StringComparer.InvariantCultureIgnoreCase).ToArray();
                return(new Submission
                {
                    Id = s.Id.ToString(),
                    Title = s.Title,
                    Abstract = s.Abstract,
                    Format = s.Format,
                    Level = s.Level,
                    Tags = tags,
                    Presenters = conference.AnonymousSubmissions
                            ? new Submitter[0]
                            : s.PresenterIds.Select(pId => submitters.Where(p => p.Id == pId)
                                                    .Select(p => p.GetPresenter()).Select(p => new Submitter
                    {
                        Id = p.Id.ToString(),
                        Name = AnonymiseName(p.Name),
                        Tagline = p.Tagline,
                        Bio = p.Bio,
                        ProfilePhotoUrl = p.ProfilePhotoUrl,
                        TwitterHandle = p.TwitterHandle,
                        WebsiteUrl = p.WebsiteUrl
                    }).Single()).ToArray()
                });
            })
                                 .OrderBy(x => Random.Next())
                                 .ToArray();

            var settings = new JsonSerializerSettings();

            settings.ContractResolver = new DefaultContractResolver();

            return(new JsonResult(submissionData, settings));
        }
Пример #7
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]
            HttpRequestMessage req,
            ILogger log,
            [BindConferenceConfig]
            ConferenceConfig conference,
            [BindKeyDatesConfig]
            KeyDatesConfig keyDates,
            [BindFeedbackConfig]
            FeedbackConfig feedbackConfig,
            [BindSessionsConfig]
            SessionsConfig sessionsConfig
            )
        {
            var feedback = await req.Content.ReadAsAsync <FeedbackRequest>();

            // Within feedback window
            if (keyDates.Before(x => x.FeedbackAvailableFromDate) || keyDates.After(x => x.FeedbackAvailableToDate))
            {
                log.LogWarning("Attempt to access SubmitFeedback endpoint outside of allowed window of {start} -> {end}.", keyDates.FeedbackAvailableFromDate, keyDates.FeedbackAvailableToDate);
                return(new StatusCodeResult((int)HttpStatusCode.NotFound));
            }

            // Valid feedback
            if (string.IsNullOrWhiteSpace(feedback.Likes) && string.IsNullOrWhiteSpace(feedback.ImprovementIdeas))
            {
                log.LogWarning("Attempt to access SubmitFeedback endpoint with invalid feedback details from {DeviceId}", feedback.DeviceId);
                return(new StatusCodeResult((int)HttpStatusCode.BadRequest));
            }

            var(conferenceFeedbackRepo, sessionFeedbackRepo) = await feedbackConfig.GetRepositoryAsync();

            if (feedback.IsConferenceFeedback)
            {
                // Save conference feedback
                log.LogInformation("Successfully received conference feedback for from DeviceId {DeviceId}; persisting...", feedback.DeviceId);
                var feedbackToPersist = new ConferenceFeedbackEntity(
                    conference.ConferenceInstance,
                    feedback.Name,
                    feedback.Rating.ToString(),
                    feedback.Likes,
                    feedback.ImprovementIdeas,
                    feedback.DeviceId.ToString());

                await conferenceFeedbackRepo.CreateAsync(feedbackToPersist);
            }
            else
            {
                // valid Session existed
                var(sessionsRepo, presentersRepo) = await sessionsConfig.GetRepositoryAsync();

                var allSessions = await sessionsRepo.GetAllAsync(conference.ConferenceInstance);

                var allPresenters = await presentersRepo.GetAllAsync(conference.ConferenceInstance);

                var sessionRow = allSessions.First(s => s != null && feedback.SessionId == s.Id.ToString());
                if (sessionRow == null && !feedback.IsConferenceFeedback)
                {
                    log.LogWarning("Attempt to submit to SubmitFeedback endpoint with invalid SessionId {SessionId} from {DeviceId}", feedback.SessionId, feedback.DeviceId);
                    return(new StatusCodeResult((int)HttpStatusCode.BadRequest));
                }

                var session        = sessionRow.GetSession();
                var presenterNames = string.Join(", ", session.PresenterIds.Select(pId => allPresenters.Single(p => p.Id == pId)).Select(x => x.Name));

                // Save feedback
                log.LogInformation("Successfully received feedback for {SessionId} from DeviceId {DeviceId}; persisting...", feedback.SessionId, feedback.DeviceId);
                var feedbackToPersist = new SessionFeedbackEntity(
                    session.Id.ToString(),
                    conference.ConferenceInstance,
                    feedback.Name,
                    feedback.Rating.ToString(),
                    feedback.Likes,
                    feedback.ImprovementIdeas,
                    $"{session.Title} - {presenterNames}",
                    feedback.DeviceId.ToString());

                await sessionFeedbackRepo.CreateAsync(feedbackToPersist);
            }
            return(new StatusCodeResult((int)HttpStatusCode.NoContent));
        }