Example #1
0
        public async Task <ActionResult> UpdateEvent(CelebrationEvent celebrationEvent)
        {
            this.ViewBag.EmptyView = false;
            if (this.ModelState.IsValid)
            {
                CelebrationEvent fetchedEvent = await this.eventHelper.GetEventByEventIdAsync(celebrationEvent.Id, celebrationEvent.OwnerAadObjectId);

                await this.eventHelper.SaveEventAsync(celebrationEvent);

                // If event date or timezone is changed then delete record from Occurrences and EventMessages collections.
                if (fetchedEvent.Date != celebrationEvent.Date || fetchedEvent.TimeZoneId != celebrationEvent.TimeZoneId)
                {
                    await this.eventHelper.DeleteRecurringEventAsync(celebrationEvent.Id);

                    await this.eventHelper.DeleteEventMessagesAsync(celebrationEvent.Id);

                    // Add record in Occurrences collection if recurring event is within 72 hours.
                    DateTime upcomingEventDate = Common.GetUpcomingEventDate(celebrationEvent.Date, DateTime.UtcNow.Date);

                    if ((upcomingEventDate - DateTime.Now).TotalDays <= 72)
                    {
                        await this.AddRecurringEventAsync(celebrationEvent, upcomingEventDate);
                    }
                }
            }

            return(this.View("Events", await this.GetEventsByOwnerObjectIdAsync(celebrationEvent.OwnerAadObjectId)));
        }
Example #2
0
        public async Task <ActionResult> SaveEvent(CelebrationEvent celebrationEvent)
        {
            this.ViewBag.EmptyView = false;
            if (this.ModelState.IsValid)
            {
                await this.eventHelper.SaveEventAsync(celebrationEvent);
            }

            return(this.View("Events", await this.GetEventsByOwnerObjectIdAsync(celebrationEvent.OwnerAadObjectId)));
        }
 /// <summary>
 /// Create and return Celebration Event card
 /// </summary>
 /// <param name="celebrationEvent">Celebration event</param>
 /// <param name="ownerDisplayName">Owner display name</param>
 /// <returns>HeroCard</returns>
 public static HeroCard GetEventCard(CelebrationEvent celebrationEvent, string ownerDisplayName)
 {
     return(new HeroCard()
     {
         Title = string.Format(Strings.EventCardTitle, ownerDisplayName, celebrationEvent.Title),
         Text = celebrationEvent.Message,
         Images = new List <CardImage>()
         {
             new CardImage(url: Common.GetImageUrlFromPath(celebrationEvent.ImageUrl))
         },
     });
 }
        /// <inheritdoc/>
        public async Task UpdateEventAsync(CelebrationEvent celebrationEvent)
        {
            if (celebrationEvent.Id == null)
            {
                throw new ArgumentException("Event must have an ID", nameof(celebrationEvent));
            }

            await this.EnsureInitializedAsync();

            var documentUri = UriFactory.CreateDocumentUri(this.database.Id, this.eventsCollection.Id, celebrationEvent.Id);

            await this.documentClient.ReplaceDocumentAsync(documentUri, celebrationEvent);
        }
        /// <inheritdoc/>
        public async Task <CelebrationEvent> AddEventAsync(CelebrationEvent celebrationEvent)
        {
            if (celebrationEvent.Id != null)
            {
                throw new ArgumentException("A new event must not have an assigned ID", nameof(celebrationEvent));
            }

            await this.EnsureInitializedAsync();

            var response = await this.documentClient.CreateDocumentAsync(this.eventsCollection.SelfLink, celebrationEvent);

            return((CelebrationEvent)(dynamic)response.Resource);
        }
        /// <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);
            }
        }
 /// <summary>
 /// Prepare EventMessageActivity object.
 /// </summary>
 /// <param name="celebrationEvent">CelebrationEvent instance</param>
 /// <param name="user">User instance</param>
 /// <param name="conversationId">ConversationId</param>
 /// <returns>EventMessageActivity instance.</returns>
 private EventMessageActivity GetEventMessageActivity(CelebrationEvent celebrationEvent, User user, string conversationId)
 {
     return(new EventMessageActivity
     {
         OwnerName = user.UserName,
         OwnerAadObjectId = celebrationEvent.OwnerAadObjectId,
         Id = celebrationEvent.Id,
         ServiceUrl = user.ServiceUrl,
         Title = celebrationEvent.Title,
         Message = celebrationEvent.Message,
         ImageUrl = celebrationEvent.ImageURL,
         ConversationId = conversationId,
     });
 }
Example #8
0
        /// <summary>
        /// Add Recurring event.
        /// </summary>
        /// <param name="celebrationEvent">CelebrationEvent instance.</param>
        /// <param name="upcomingEventDate">upcoming event date.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        private async Task AddRecurringEventAsync(CelebrationEvent celebrationEvent, DateTime upcomingEventDate)
        {
            var            timespan = Array.ConvertAll <string, int>(ApplicationSettings.TimeToPostCelebration.Split(':'), Convert.ToInt32);
            DateTime       upcomingEventDateTime      = upcomingEventDate.AddHours(timespan[0]).AddMinutes(timespan[1]).AddSeconds(timespan[2]);
            DateTimeOffset upcomingEventDateTimeInUTC = TimeZoneInfo.ConvertTimeToUtc(upcomingEventDateTime, TimeZoneInfo.FindSystemTimeZoneById(celebrationEvent.TimeZoneId));

            EventOccurrence eventOccurrence = new EventOccurrence
            {
                EventId = celebrationEvent.Id,
                Date    = upcomingEventDateTimeInUTC,
            };

            await this.eventHelper.AddRecurringEventAsync(eventOccurrence);
        }
        public async Task <ActionResult> SaveEvent(CelebrationEvent celebrationEvent)
        {
            var context      = this.Request.GetOwinContext();
            var userObjectId = context.Authentication.User.GetUserObjectId();

            if (this.ModelState.IsValid)
            {
                celebrationEvent.OwnerAadObjectId = userObjectId;
                await this.eventDataProvider.AddEventAsync(celebrationEvent);
            }

            var viewModel = new EventsTabViewModel
            {
                Events             = await this.GetEventsByOwnerObjectIdAsync(userObjectId),
                MaxUserEventsCount = Convert.ToInt32(this.configProvider.GetSetting(ApplicationConfig.MaxUserEventsCount)),
            };

            return(this.PartialView("EventsData", viewModel));
        }
        /// <summary>
        /// Create and return preview card
        /// </summary>
        /// <param name="celebrationEvent">The event</param>
        /// <param name="occurrenceId">The event occurrence</param>
        /// <param name="ownerDisplayName">The event owner</param>
        /// <param name="isSkipAllowed">true/false</param>
        /// <returns>HeroCard</returns>
        public static HeroCard GetPreviewCard(CelebrationEvent celebrationEvent, string occurrenceId, string ownerDisplayName, bool isSkipAllowed = true)
        {
            var cardActions = new List <CardAction>()
            {
                new CardAction()
                {
                    Title = Strings.EditButtonTitle,
                    Type  = ActionTypes.OpenUrl,
                    Value = Common.GetDeeplinkToEventsTab(celebrationEvent.Id),
                },
            };

            if (isSkipAllowed)
            {
                cardActions.Insert(0, new CardAction()
                {
                    Title = Strings.SkipButtonTitle,
                    Type  = ActionTypes.MessageBack,
                    Value = new PreviewCardPayload
                    {
                        Action           = "SkipEvent",
                        EventId          = celebrationEvent.Id,
                        OccurrenceId     = occurrenceId,
                        OwnerAadObjectId = celebrationEvent.OwnerAadObjectId,
                        OwnerName        = ownerDisplayName,
                    },
                });
            }

            var previewCard = new HeroCard()
            {
                Title   = string.Format(Strings.EventPreviewCardHeader, ownerDisplayName, celebrationEvent.Title),
                Text    = celebrationEvent.Message,
                Buttons = cardActions,
                Images  = new List <CardImage>()
                {
                    new CardImage(url: Common.GetImageUrlFromPath(celebrationEvent.ImageUrl))
                },
            };

            return(previewCard);
        }
Example #11
0
        public async Task <ActionResult> UpdateEvent(CelebrationEvent celebrationEvent)
        {
            var context      = this.Request.GetOwinContext();
            var userObjectId = context.Authentication.User.GetUserObjectId();

            if (this.ModelState.IsValid)
            {
                // Ensure that the provided event is actually owned by the current user
                var fetchedEvent = await this.eventDataProvider.GetEventByIdAsync(celebrationEvent.Id, userObjectId);

                if (fetchedEvent != null)
                {
                    celebrationEvent.OwnerAadObjectId = userObjectId;
                    await this.eventDataProvider.UpdateEventAsync(celebrationEvent);

                    // If event date or timezone is changed then delete record from Occurrences and EventMessages collections
                    if (fetchedEvent.Date != celebrationEvent.Date ||
                        fetchedEvent.TimeZoneId != celebrationEvent.TimeZoneId)
                    {
                        await this.eventDataProvider.DeleteEventOccurrencesByEventIdAsync(celebrationEvent.Id);

                        await this.eventDataProvider.DeleteEventMessagesByEventIdAsync(celebrationEvent.Id);

                        // The next run of the preview function will handle scheduling the preview
                    }
                }
                else
                {
                    this.logProvider.LogInfo($"Could not find event {celebrationEvent.Id} belonging to {userObjectId}");
                }
            }

            var viewModel = new EventsTabViewModel
            {
                Events             = await this.GetEventsByOwnerObjectIdAsync(userObjectId),
                MaxUserEventsCount =
                    Convert.ToInt32(this.configProvider.GetSetting(ApplicationConfig.MaxUserEventsCount)),
            };

            return(this.PartialView("EventsData", viewModel));
        }
Example #12
0
        /// <summary>
        /// Update event.
        /// </summary>
        /// <param name="celebrationEvent">CelebrationEvent object.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public async Task UpdateEventAsync(CelebrationEvent celebrationEvent)
        {
            await this.EnsureInitializedAsync();

            await this.documentClient.ReplaceDocumentAsync(celebrationEvent.SelfLink, celebrationEvent);
        }
Example #13
0
        /// <summary>
        /// Save event.
        /// </summary>
        /// <param name="celebrationEvent">CelebrationEvent object.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public async Task SaveEventAsync(CelebrationEvent celebrationEvent)
        {
            await this.EnsureInitializedAsync();

            await this.documentClient.UpsertDocumentAsync(this.eventsCollection.SelfLink, celebrationEvent);
        }
        /// <summary>
        /// Add an entry to EventMessages collection.
        /// </summary>
        /// <param name="conversationId">conversationId</param>
        /// <param name="recurringEvent">EventOccurrence instance</param>
        /// <param name="celebrationEvent">CelebrationEvent instance.</param>
        /// <param name="user">User instance.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        private async Task <EventMessage> AddEntryToEventMessagesCollection(string conversationId, EventOccurrence recurringEvent, CelebrationEvent celebrationEvent, User user)
        {
            EventMessage eventMessage = new EventMessage
            {
                OccurrenceId = recurringEvent.Id,
                EventId      = celebrationEvent.Id,
                Activity     = this.GetEventMessageActivity(celebrationEvent, user, conversationId),
                MessageType  = MessageType.Event,
                ExpireAt     = recurringEvent.Date.AddHours(12),
            };

            // Add new entry to EventMessages collection for reminder.
            await this.eventHelper.AddEventMessageAsync(eventMessage);

            return(eventMessage);
        }
Example #15
0
        /// <summary>
        /// Handles event Share action.
        /// </summary>
        /// <param name="context">IDialogContext object.</param>
        /// <param name="activity">IAwaitable message activity.</param>
        /// <returns>Task.</returns>
        public async Task HandleEventShareAction(IDialogContext context, IAwaitable <IMessageActivity> activity)
        {
            var message      = (Activity)await activity;
            var replyMessage = string.Empty;

            if (message.Value != null)
            {
                ShareEventPayload shareEventPayload = ((JObject)message.Value).ToObject <ShareEventPayload>();

                try
                {
                    var teamMembers = await this.connectorClient.Conversations.GetConversationMembersAsync(shareEventPayload.TeamId);

                    var user = teamMembers.Where(x => x.Properties["objectId"].ToString() == shareEventPayload.UserAadObjectId).ToList().FirstOrDefault();

                    var document = await this.userManagementHelper.GetTeamsDetailsByTeamIdAsync(shareEventPayload.TeamId);

                    bool isBotUnintsalledFromTeam = document == null ? true : false;

                    if (user == null)
                    {
                        replyMessage = $"You are no longer a member of {shareEventPayload.TeamName}.";
                    }
                    else if (isBotUnintsalledFromTeam)
                    {
                        replyMessage = "Someone uninstalled me from your team, I can no longer share these events there";
                    }
                    else
                    {
                        List <CelebrationEvent> celebrationEvents = await(await this.eventHelper.GetEventsByOwnerObjectIdAsync(
                                                                              shareEventPayload.UserAadObjectId)).ToListAsync();
                        if (celebrationEvents.Count > 0)
                        {
                            foreach (var celebrationEvent in celebrationEvents)
                            {
                                celebrationEvent.Teams.Add(new Team {
                                    Id = shareEventPayload.TeamId
                                });
                                CelebrationEvent updatedEvent = (dynamic)celebrationEvent;
                                updatedEvent.Teams = celebrationEvent.Teams;
                                await this.eventHelper.UpdateEventAsync(updatedEvent);
                            }
                        }

                        replyMessage = "I’ve set those events to be shared with the team when they occur.";

                        // Update the card
                        IMessageActivity updatedMessage = context.MakeMessage();
                        updatedMessage.Attachments.Add(CelebrationCard.GetShareEventAttachementWithoutActionButton(shareEventPayload.TeamName));
                        updatedMessage.ReplyToId = message.ReplyToId;
                        await this.connectorClient.Conversations.UpdateActivityAsync(message.Conversation.Id, message.ReplyToId, (Activity)updatedMessage);
                    }
                }
                catch (Exception ex)
                {
                    this.logProvider.LogError("Failed to share the existing event with team", ex, new Dictionary <string, string>()
                    {
                        {
                            "TeamId", shareEventPayload.TeamId
                        },
                        {
                            "TeamName", shareEventPayload.TeamName
                        },
                        {
                            "UserAadObjectId", shareEventPayload.UserAadObjectId
                        },
                    });

                    replyMessage = "Some error occurred to share the event with team. Please try again.";
                }

                await context.PostAsync(replyMessage);

                context.Done <object>(null);
            }
        }
        // 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);
            }
        }