Ejemplo n.º 1
0
        /// <summary>
        /// Send event card
        /// </summary>
        /// <param name="eventMessages">List of EventMessage</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        private async Task SendEventCard(List <EventMessage> eventMessages)
        {
            var tasks = Task.Run(() =>
            {
                Parallel.ForEach(eventMessages, new ParallelOptions {
                    MaxDegreeOfParallelism = MaxParallelism
                }, async(eventMessage) =>
                {
                    var activity  = eventMessage.Activity;
                    HeroCard card = null;
                    switch (eventMessage.MessageType)
                    {
                    case MessageType.Event:
                        card = CelebrationCard.GetEventCard(activity);
                        break;

                    case MessageType.Preview:
                        card = CelebrationCard.GetPreviewCard(activity);
                        break;
                    }

                    var task = this.connectorServiceHelper.SendPersonalMessageAsync(string.Empty, new List <Attachment> {
                        card.ToAttachment()
                    }, activity.ConversationId);

                    RetryWithExponentialBackoff retryBackOff = new RetryWithExponentialBackoff();
                    await retryBackOff.RunAsync(task, eventMessage, this.SuccessCallback, this.FailureCallback);
                });
            });

            await tasks;
        }
Ejemplo n.º 2
0
        // Handles event skip action
        private async Task HandleSkipEventAsync(IDialogContext context, IMessageActivity message)
        {
            var payload = ((JObject)message?.Value)?.ToObject <PreviewCardPayload>();

            if (payload == null)
            {
                this.logProvider.LogInfo("Received message with no payload");
                return;
            }

            // Get the event
            var celebrationEvent = await this.eventDataProvider.GetEventByIdAsync(payload.EventId, payload.OwnerAadObjectId);

            if (celebrationEvent == null)
            {
                this.logProvider.LogInfo($"Could not find event {payload.EventId} for user {payload.OwnerAadObjectId}");
                await context.PostAsync(Strings.EventDoesNotExistMessage);

                return;
            }

            // Get the occurrence
            var occurrence = await this.eventDataProvider.GetEventOccurrenceByIdAsync(payload.OccurrenceId, payload.EventId);

            if (occurrence == null)
            {
                this.logProvider.LogInfo($"Could not find occurrence {payload.OccurrenceId} of event {payload.EventId} for user {payload.OwnerAadObjectId} (likely out of date card)");
                await context.PostAsync(Strings.SkippedStaleEventMessage);

                return;
            }

            // Check that the occurrence is still in the future
            if (occurrence.DateTime < DateTimeOffset.UtcNow)
            {
                await context.PostAsync(Strings.EventPassedMessage);

                return;
            }

            // Mark the occurrence as skipped
            occurrence.Status = EventStatus.Skipped;
            await this.eventDataProvider.UpdateEventOccurrenceAsync(occurrence);

            // Update the card
            var updatedMessage = context.MakeMessage();

            updatedMessage.Attachments.Add(CelebrationCard.GetPreviewCard(celebrationEvent, payload.OccurrenceId, payload.OwnerName, false).ToAttachment());
            await this.connectorClient.Conversations.UpdateActivityAsync(message.Conversation.Id, message.ReplyToId, (Activity)updatedMessage);

            await context.PostAsync(string.Format(Strings.EventSkippedMessage, celebrationEvent.Title));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Handles event skip action.
        /// </summary>
        /// <param name="context">IDialogContext object.</param>
        /// <param name="activity">IAwaitable message activity.</param>
        /// <returns>Task.</returns>
        public async Task HandleEventSkipActions(IDialogContext context, IAwaitable <IMessageActivity> activity)
        {
            var message = (Activity)await activity;

            if (message.Value != null)
            {
                var replyMessage       = string.Empty;
                var previewCardPayload = ((JObject)message.Value).ToObject <PreviewCardPayload>();

                // Get event by eventId to check if it exist or not.
                CelebrationEvent celebrationEvent = await this.eventHelper.GetEventByEventIdAsync(previewCardPayload.EventId, previewCardPayload.OwnerAadObjectId);

                if (celebrationEvent != null)
                {
                    if (previewCardPayload.UpcomingEventDate > DateTime.UtcNow.Date)
                    {
                        await this.eventHelper.UpdateRecurringEventAsync(previewCardPayload.EventId, EventStatus.Skipped);

                        EventMessageActivity eventMessageActivity = new EventMessageActivity
                        {
                            Id        = celebrationEvent.Id,
                            OwnerName = previewCardPayload.OwnerName,
                            ImageUrl  = celebrationEvent.ImageURL,
                            Message   = celebrationEvent.Message,
                            Title     = celebrationEvent.Title,
                        };

                        // Update the card
                        IMessageActivity updatedMessage = context.MakeMessage();
                        updatedMessage.Attachments.Add(CelebrationCard.GetPreviewCard(eventMessageActivity, false).ToAttachment());
                        updatedMessage.ReplyToId = message.ReplyToId;
                        await this.connectorClient.Conversations.UpdateActivityAsync(message.Conversation.Id, message.ReplyToId, (Activity)updatedMessage);

                        replyMessage = string.Format(Strings.EventSkippedMessage, message.From.Name);
                    }
                    else
                    {
                        // event occurrence has already passed for current year.
                        replyMessage = string.Format(Strings.EventPassedMessage);
                    }
                }
                else
                {
                    replyMessage = string.Format(Strings.EventNotExistMessage, previewCardPayload.Title);
                }

                await context.PostAsync(replyMessage);

                context.Done <object>(null);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Process request to send preview card
        /// </summary>
        /// <param name="currentDateTime">Current dateTime</param>
        /// <returns>A <see cref="Task"/>Representing the asynchronous operation</returns>
        public async Task <HttpResponseMessage> Post(string currentDateTime = "")
        {
            this.logProvider.LogInfo($"Processing events to send the reminder to owner. CurrentDateTime:{currentDateTime}");

            DateTimeOffset currentDateTimeOffset;

            if (!DateTimeOffset.TryParse(currentDateTime, null, DateTimeStyles.AdjustToUniversal, out currentDateTimeOffset))
            {
                currentDateTimeOffset = DateTimeOffset.UtcNow;
            }

            var events = await(await this.eventHelper.GetCelebrationEventsAsync(GetEventQuery(currentDateTimeOffset.Date))).ToListAsync();

            this.logProvider.LogInfo($"found {events.Count} which are coming in next 72 hours.");
            if (events.Count > 0)
            {
                var existingRecurringEvents = await(await this.eventHelper.GetRecurringEventsAsync(events.Select(x => x.Id).ToList())).ToListAsync();

                this.logProvider.LogInfo($"Found {existingRecurringEvents.Count} for which reminder has already sent");
                int    lastAttemptStatusCode = (int)HttpStatusCode.OK;
                string responseBody          = string.Empty;

                // remove events which exist in Occurrences collection
                events.RemoveAll(x => existingRecurringEvents.Any(y => y.EventId == x.Id));

                if (events.Count > 0)
                {
                    this.users = await this.userManagementHelper.GetUsersByAadObjectIdsAsync(events.Select(x => x.OwnerAadObjectId).ToList());

                    this.connectorServiceHelper = new ConnectorServiceHelper(this.CreateConnectorClient(this.users.FirstOrDefault().ServiceUrl), this.logProvider);
                }

                // Loop each event and make entry in Occurrences collection to send preview and event card.
                foreach (var celebrationEvent in events)
                {
                    this.logProvider.LogInfo("Processing event to send reminder", new Dictionary <string, string>()
                    {
                        { "EventId", celebrationEvent.Id }, { "UserObjectId", celebrationEvent.OwnerAadObjectId }
                    });

                    // Get event owner information.
                    var user = this.users.Where(x => x.AadObjectId == celebrationEvent.OwnerAadObjectId).FirstOrDefault();

                    // update conversation id if it is null.
                    await this.ModifyUserDetailsAsync(user);

                    DateTime       upcomingEventDate          = Common.GetUpcomingEventDate(celebrationEvent.Date, currentDateTimeOffset.Date);
                    var            timespan                   = Array.ConvertAll <string, int>(ApplicationSettings.TimeToPostCelebration.Split(':'), Convert.ToInt32);
                    DateTime       upcomingEventDateTime      = upcomingEventDate.AddHours(timespan[0]).AddMinutes(timespan[1]);
                    DateTimeOffset upcomingEventDateTimeInUTC = TimeZoneInfo.ConvertTimeToUtc(upcomingEventDateTime, TimeZoneInfo.FindSystemTimeZoneById(celebrationEvent.TimeZoneId));

                    // add an entry to Occurrence collection for all the upcoming event.
                    EventOccurrence eventOccurrence = new EventOccurrence
                    {
                        EventId = celebrationEvent.Id,
                        Date    = upcomingEventDateTimeInUTC,
                    };

                    await this.eventHelper.AddRecurringEventAsync(eventOccurrence);

                    // Do not send reminder if event is today.
                    if (upcomingEventDate != currentDateTimeOffset.Date)
                    {
                        // Add new entry to EventMessages collection for reminder.
                        EventMessage eventMessage = new EventMessage
                        {
                            OccurrenceId = eventOccurrence.Id,
                            EventId      = celebrationEvent.Id,
                            Activity     = this.GetEventMessageActivity(celebrationEvent, user),
                            MessageType  = MessageType.Preview,
                            ExpireAt     = upcomingEventDate.AddHours(24),
                        };

                        await this.eventHelper.AddEventMessageAsync(eventMessage);

                        bool      isMessageSentSuccessfully = false;
                        Exception exception = null;

                        try
                        {
                            HeroCard previewCard = CelebrationCard.GetPreviewCard(eventMessage.Activity);

                            string message = string.Format(Strings.PreviewText, user.UserName);

                            this.logProvider.LogInfo("Sending reminder message to the owner of the event", new Dictionary <string, string>()
                            {
                                { "EventId", celebrationEvent.Id },
                                { "Attachment", Newtonsoft.Json.JsonConvert.SerializeObject(previewCard) },
                                { "Message", message },
                            });

                            // Send reminder of event to owner.
                            await this.connectorServiceHelper.SendPersonalMessageAsync(
                                message,
                                new List <Attachment> {
                                previewCard.ToAttachment()
                            },
                                user.ConversationId);

                            this.logProvider.LogInfo($"Reminder message sent to the owner of the event. EventId: {celebrationEvent.Id}");
                        }
                        catch (HttpException httpException)
                        {
                            lastAttemptStatusCode = httpException.GetHttpCode();
                            responseBody          = httpException.GetHtmlErrorMessage();
                            exception             = httpException;
                        }
                        catch (ErrorResponseException errorResponseException)
                        {
                            lastAttemptStatusCode = (int)errorResponseException.Response.StatusCode;
                            responseBody          = errorResponseException.Response.Content.ToString();
                            exception             = errorResponseException;
                        }
                        catch (Exception ex)
                        {
                            lastAttemptStatusCode = (int)HttpStatusCode.BadRequest;
                            responseBody          = ex.ToString();
                        }
                        finally
                        {
                            if (!isMessageSentSuccessfully)
                            {
                                this.logProvider.LogError("Failed to send reminder for upcoming event.", exception, new Dictionary <string, string>
                                {
                                    { "EventId", eventMessage.EventId },
                                    { "OccurrenceId", eventMessage.OccurrenceId },
                                    { "eventActivity", eventMessage.Activity.ToString() },
                                    { "LastAttemptStatusCode", lastAttemptStatusCode.ToString() },
                                    { "LastAttemptTime", DateTime.UtcNow.ToString() },
                                    { "ConversationId", user.ConversationId },
                                });
                            }

                            MessageSendResult messageSendResult = new MessageSendResult()
                            {
                                LastAttemptTime = DateTime.UtcNow,
                                StatusCode      = lastAttemptStatusCode,
                                ResponseBody    = responseBody,
                            };

                            await this.eventHelper.UpdateEventMessageAsync(eventMessage.Id, messageSendResult);
                        }
                    }
                    else
                    {
                        this.logProvider.LogInfo("Not sending reminder for this event as its upcoming event date is today.");
                    }
                }
            }

            return(new HttpResponseMessage(HttpStatusCode.OK));
        }
        // Send a messsage to the owner of the given event, reminding them that their event is coming up
        private async Task SendEventReminderAsync(CelebrationEvent celebrationEvent, DateTimeOffset currentDateTimeOffset)
        {
            this.logProvider.LogInfo($"Sending reminder for event {celebrationEvent.Id} (owner={celebrationEvent.OwnerAadObjectId}, date={celebrationEvent.Date.ToShortDateString()})");

            // Determine the next occurrence of the event
            var deliveryTimeZone = TimeZoneInfo.FindSystemTimeZoneById(celebrationEvent.TimeZoneId);
            var currentTimeInDeliveryTimeZone = TimeZoneInfo.ConvertTimeFromUtc(currentDateTimeOffset.UtcDateTime, deliveryTimeZone);
            var upcomingEventDateTime         = Common.GetNextOccurrenceAfterDateTime(celebrationEvent.Date.Add(this.timeToPostPreview), currentTimeInDeliveryTimeZone);
            var upcomingEventDateTimeInUTC    = TimeZoneInfo.ConvertTimeToUtc(upcomingEventDateTime, deliveryTimeZone);

            // Do not send reminder if the next occurrence is not in the window
            var timeUntilNextOccurrence = upcomingEventDateTimeInUTC - currentDateTimeOffset;

            if ((timeUntilNextOccurrence.TotalMinutes < 0) ||
                (upcomingEventDateTimeInUTC - currentDateTimeOffset) > TimeSpan.FromDays(this.daysInAdvanceToSendEventPreview))
            {
                this.logProvider.LogInfo($"Next occurrence of event {celebrationEvent.Id} is not in the next {this.daysInAdvanceToSendEventPreview} days");
                return;
            }

            // Add an entry to Occurrence collection for the event, so we know that we processed it
            var eventOccurrence = new EventOccurrence
            {
                EventId          = celebrationEvent.Id,
                OwnerAadObjectId = celebrationEvent.OwnerAadObjectId,
                DateTime         = upcomingEventDateTimeInUTC,
            };

            eventOccurrence = await this.eventDataProvider.AddEventOccurrenceAsync(eventOccurrence);

            // Do not send reminder if we are within the period specified in the configuration
            if ((upcomingEventDateTimeInUTC - currentDateTimeOffset) < this.minimumTimeToProcessEvent)
            {
                this.logProvider.LogInfo($"Not sending reminder for event {celebrationEvent.Id} which is due in less than {(int)this.minimumTimeToProcessEvent.TotalHours} hours");
                return;
            }

            // Get event owner information
            var user = await this.userManagementHelper.GetUserByAadObjectIdAsync(celebrationEvent.OwnerAadObjectId);

            await this.EnsureConversationWithUserAsync(user);

            // Send reminder of event to the owner
            var previewCard = CelebrationCard.GetPreviewCard(celebrationEvent, eventOccurrence.Id, user.DisplayName);
            var message     = string.Format(Strings.EventPreviewMessageText, user.DisplayName);
            var activity    = new Activity(ActivityTypes.Message)
            {
                Conversation = new ConversationAccount {
                    Id = user.ConversationId
                },
                Recipient = new ChannelAccount {
                    Id = user.TeamsId
                },
                Text        = message,
                Summary     = message,
                Attachments = new List <Attachment> {
                    previewCard.ToAttachment()
                },
                ServiceUrl = user.ServiceUrl,
            };

            // Add new entry to EventMessages collection for message type "preview" to track the status of message sent
            var eventMessage = new EventMessage
            {
                EventId      = celebrationEvent.Id,
                OccurrenceId = eventOccurrence.Id,
                Activity     = activity,
                TenantId     = user.TenantId,
                MessageType  = MessageType.Preview,
                ExpireAt     = upcomingEventDateTimeInUTC.AddHours(24),
            };

            eventMessage = await this.eventDataProvider.AddEventMessageAsync(eventMessage);

            // Send the message
            try
            {
                await eventMessage.SendAsync(this.connectorClientFactory);

                this.logProvider.LogInfo($"Reminder message sent to the owner of event {celebrationEvent.Id}");
            }
            catch (Exception ex)
            {
                this.logProvider.LogError($"Failed to send reminder for event {celebrationEvent.Id}", ex, new Dictionary <string, string>
                {
                    { "EventId", eventMessage.EventId },
                    { "OccurrenceId", eventMessage.OccurrenceId },
                    { "ConversationId", user.ConversationId },
                    { "OccurrenceDateTime", eventOccurrence.DateTime.ToString() },
                    { "LastAttemptTime", DateTimeOffset.UtcNow.ToString() },
                    { "LastAttemptStatusCode", eventMessage.MessageSendResult?.StatusCode.ToString() },
                    { "ResponseBody", eventMessage.MessageSendResult?.ResponseBody },
                });
                throw;
            }
            finally
            {
                // Record the result of the send
                await this.eventDataProvider.UpdateEventMessageAsync(eventMessage);
            }
        }