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))); }
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, }); }
/// <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); }
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)); }
/// <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); }
/// <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); }
/// <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); } }