/// <summary> /// Sends notification to user on removal from project. /// </summary> /// <param name="userIds">List of users to be notified.</param> /// <param name="projectTitle">Project title.</param> /// <param name="projectOwner">Project owner.</param> /// <returns>A Task representing notification to user on removal.</returns> public async Task SendProjectRemovalNotificationAsync( List <string> userIds, string projectTitle, string projectOwner) { userIds = userIds ?? throw new ArgumentNullException(nameof(userIds)); foreach (var userId in userIds) { var adaptiveCard = MessageFactory.Attachment(UserNotificationCard.SendProjectRemovalCard( projectTitle.Trim(), projectOwner, this.botOptions.Value.ManifestId, this.localizer)); var userDetails = await this.userDetailProvider.GetUserDetailsAsync(userId); if (userDetails != null) { await this.SendNotificationAsync( userDetails.UserConversationId, adaptiveCard, userDetails.ServiceUrl); } } }
/// <summary> /// Sends notification to team members when project is deleted. /// </summary> /// <param name="projectEntity">ProjectEntity model containing project metadata.</param> /// <returns>A Task representing notification sent to all members in project.</returns> public async Task SendProjectDeletionNotificationAsync( ProjectEntity projectEntity) { projectEntity = projectEntity ?? throw new ArgumentNullException(nameof(projectEntity)); var userIds = projectEntity.ProjectParticipantsUserIds.Split(new char[] { ';' }, System.StringSplitOptions.RemoveEmptyEntries); foreach (var userId in userIds) { var adaptiveCard = MessageFactory.Attachment(UserNotificationCard.SendProjectDeletionCard( projectEntity.Title, projectEntity.CreatedByName, this.botOptions.Value.ManifestId, this.localizer)); var userDetails = await this.userDetailProvider.GetUserDetailsAsync(userId); if (userDetails != null) { await this.SendNotificationAsync( userDetails.UserConversationId, adaptiveCard, userDetails.ServiceUrl); } } }
/// <summary> /// Sends notification to team members when project is closed. /// </summary> /// <param name="closeProjectModel">CloseProjectModel model containing project closure metadata.</param> /// <param name="projectTitle">Title of the project.</param> /// <param name="projectOwnerName">Owner of the project.</param> /// <returns>A Task representing notification sent to all members in project.</returns> public async Task SendProjectClosureNotificationAsync( CloseProjectModel closeProjectModel, string projectTitle, string projectOwnerName) { closeProjectModel = closeProjectModel ?? throw new ArgumentNullException(nameof(closeProjectModel)); foreach (var participant in closeProjectModel.ProjectParticipantDetails) { List <string> acquiredSkills = participant.AcquiredSkills.Split(new char[] { ';' }, System.StringSplitOptions.RemoveEmptyEntries).ToList(); var adaptiveCard = MessageFactory.Attachment(UserNotificationCard.SendProjectClosureCard( projectTitle, projectOwnerName, this.botOptions.Value.ManifestId, participant.Feedback, acquiredSkills, this.localizer)); var userDetails = await this.userDetailProvider.GetUserDetailsAsync(participant.UserId); if (userDetails != null) { await this.SendNotificationAsync( userDetails.UserConversationId, adaptiveCard, userDetails.ServiceUrl); } } }
/// <summary> /// Sends notification to project owner when user joins project. /// </summary> /// <param name="projectEntity">ProjectEntity Model containing project metadata.</param> /// <param name="userName">Name of user joining the project.</param> /// <param name="userPrincipalName">UserPrincipalName of user joining the project.</param> /// <returns>A Task representing notification sent to project owner.</returns> public async Task SendProjectJoinedNotificationAsync( ProjectEntity projectEntity, string userName, string userPrincipalName) { projectEntity = projectEntity ?? throw new ArgumentNullException(nameof(projectEntity)); var adaptiveCard = MessageFactory.Attachment(UserNotificationCard.SendProjectJoinedCard( projectEntity.ProjectId, projectEntity.Title, userName, userPrincipalName, projectEntity.CreatedByUserId, this.localizer)); var userDetails = await this.userDetailProvider.GetUserDetailsAsync(projectEntity.CreatedByUserId); if (userDetails != null) { await this.SendNotificationAsync( userDetails.UserConversationId, adaptiveCard, userDetails.ServiceUrl); } }
// Handle adaptive card submit in 1:1 chat // Submits the question or feedback to the SME team private async Task OnAdaptiveCardSubmitInPersonalChatAsync(IMessageActivity message, ITurnContext <IMessageActivity> turnContext, CancellationToken cancellationToken) { Attachment smeTeamCard = null; // Notification to SME team Attachment userCard = null; // Acknowledgement to the user TicketEntity newTicket = null; // New ticket this.telemetryClient.TrackTrace($"Otro envio: {message.Text}"); switch (message.Text) { case AskAnExpert: { this.telemetryClient.TrackTrace("Sending user ask an expert card (from answer)"); var responseCardPayload = ((JObject)message.Value).ToObject <ResponseCardPayload>(); await turnContext.SendActivityAsync(MessageFactory.Attachment(AskAnExpertCard.GetCard(responseCardPayload))); break; } case ShareFeedback: { this.telemetryClient.TrackTrace("Sending user share feedback card (from answer)"); var responseCardPayload = ((JObject)message.Value).ToObject <ResponseCardPayload>(); await turnContext.SendActivityAsync(MessageFactory.Attachment(ShareFeedbackCard.GetCard(responseCardPayload))); break; } case WelcomeMsg: this.telemetryClient.TrackTrace("The user as required the Welcome screen"); var welcomeText = await this.configurationProvider.GetSavedEntityDetailAsync(ConfigurationEntityTypes.WelcomeMessageText); var userWelcomeCardAttachment = WelcomeCard.GetCard(welcomeText); await turnContext.SendActivityAsync(MessageFactory.Attachment(userWelcomeCardAttachment)); break; case AskAnExpertCard.AskAnExpertSubmitText: { this.telemetryClient.TrackTrace($"Received question for expert"); var askAnExpertPayload = ((JObject)message.Value).ToObject <AskAnExpertCardPayload>(); // Validate required fields if (string.IsNullOrWhiteSpace(askAnExpertPayload.Title)) { var updateCardActivity = new Activity(ActivityTypes.Message) { Id = turnContext.Activity.ReplyToId, Conversation = turnContext.Activity.Conversation, Attachments = new List <Attachment> { AskAnExpertCard.GetCard(askAnExpertPayload) }, }; await turnContext.UpdateActivityAsync(updateCardActivity, cancellationToken); return; } var userDetails = await this.GetUserDetailsInPersonalChatAsync(turnContext, cancellationToken); newTicket = await this.CreateTicketAsync(message, askAnExpertPayload, userDetails); smeTeamCard = new SmeTicketCard(newTicket).ToAttachment(message.LocalTimestamp); userCard = new UserNotificationCard(newTicket).ToAttachment(Resource.NotificationCardContent, message.LocalTimestamp); break; } case ShareFeedbackCard.ShareFeedbackSubmitText: { this.telemetryClient.TrackTrace($"Received app feedback"); var shareFeedbackPayload = ((JObject)message.Value).ToObject <ShareFeedbackCardPayload>(); // Validate required fields if (!Enum.TryParse(shareFeedbackPayload.Rating, out FeedbackRating rating)) { var updateCardActivity = new Activity(ActivityTypes.Message) { Id = turnContext.Activity.ReplyToId, Conversation = turnContext.Activity.Conversation, Attachments = new List <Attachment> { ShareFeedbackCard.GetCard(shareFeedbackPayload) }, }; await turnContext.UpdateActivityAsync(updateCardActivity, cancellationToken); return; } var userDetails = await this.GetUserDetailsInPersonalChatAsync(turnContext, cancellationToken); smeTeamCard = SmeFeedbackCard.GetCard(shareFeedbackPayload, userDetails); await turnContext.SendActivityAsync(MessageFactory.Text(Resource.ThankYouTextContent)); break; } default: this.telemetryClient.TrackTrace($"Unexpected text in submit payload: {message.Text}", SeverityLevel.Warning); break; } // Send message to SME team if (smeTeamCard != null) { var channelId = await this.configurationProvider.GetSavedEntityDetailAsync(ConfigurationEntityTypes.TeamId); var resourceResponse = await this.SendCardToTeamAsync(turnContext, smeTeamCard, channelId, cancellationToken); // If a ticket was created, update the ticket with the conversation info if (newTicket != null) { newTicket.SmeCardActivityId = resourceResponse.ActivityId; newTicket.SmeThreadConversationId = resourceResponse.Id; await this.ticketsProvider.SaveOrUpdateTicketAsync(newTicket); } } // Send acknowledgment to the user if (userCard != null) { await turnContext.SendActivityAsync(MessageFactory.Attachment(userCard), cancellationToken); } }
/// <summary> /// Handle adaptive card submit in 1:1 chat. /// Submits the question or feedback to the SME team. /// </summary> /// <param name="message">A message in a conversation.</param> /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param> /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param> /// <returns>A task that represents the work queued to execute.</returns> public async Task SendAdaptiveCardInPersonalChatAsync( IMessageActivity message, ITurnContext <IMessageActivity> turnContext, CancellationToken cancellationToken) { Attachment smeTeamCard = null; // Notification to SME team Attachment userCard = null; // Acknowledgement to the user TicketEntity newTicket = null; // New ticket string text = (message.Text ?? string.Empty).Trim(); switch (text) { // Sends user ask an expert card from the answer card. case Constants.AskAnExpert: this.logger.LogInformation("Sending user ask an expert card (from answer)"); var askAnExpertPayload = ((JObject)message.Value).ToObject <ResponseCardPayload>(); await this.SendActivityInChatAsync(turnContext, MessageFactory.Attachment(AskAnExpertCard.GetCard(askAnExpertPayload)), cancellationToken); break; // Sends user the feedback card from the answer card. case Constants.ShareFeedback: this.logger.LogInformation("Sending user share feedback card (from answer)"); var shareFeedbackPayload = ((JObject)message.Value).ToObject <ResponseCardPayload>(); await this.SendActivityInChatAsync(turnContext, MessageFactory.Attachment(ShareFeedbackCard.GetCard(shareFeedbackPayload)), cancellationToken); break; // User submits the ask an expert card. case Constants.AskAnExpertSubmitText: this.logger.LogInformation("Received question for expert"); newTicket = await AdaptiveCardHelper.AskAnExpertSubmitText(message, turnContext, cancellationToken, this.ticketsProvider).ConfigureAwait(false); if (newTicket != null) { smeTeamCard = new SmeTicketCard(newTicket).ToAttachment(); userCard = new UserNotificationCard(newTicket).ToAttachment(Strings.NotificationCardContent); } break; // User submits the share feedback card. case Constants.ShareFeedbackSubmitText: this.logger.LogInformation("Received app feedback"); smeTeamCard = await AdaptiveCardHelper.ShareFeedbackSubmitText(message, turnContext, cancellationToken).ConfigureAwait(false); if (smeTeamCard != null) { await this.SendActivityInChatAsync(turnContext, MessageFactory.Text(Strings.ThankYouTextContent), cancellationToken); } break; default: var payload = ((JObject)message.Value).ToObject <ResponseCardPayload>(); if (payload.IsPrompt) { this.logger.LogInformation("Sending input to QnAMaker for prompt"); await this.qnaPairServiceFacade.GetReplyToQnAAsync(turnContext, message).ConfigureAwait(false); } else { this.logger.LogWarning($"Unexpected text in submit payload: {message.Text}"); } break; } string expertTeamId = await this.configurationProvider.GetSavedEntityDetailAsync(ConfigurationEntityTypes.TeamId).ConfigureAwait(false); // Send message to SME team. if (smeTeamCard != null) { await this.SendTicketCardToSMETeamAsync(turnContext, smeTeamCard, expertTeamId, cancellationToken, newTicket); } // Send acknowledgment to the user if (userCard != null) { await this.SendActivityInChatAsync(turnContext, MessageFactory.Attachment(userCard), cancellationToken); } }
/// <summary> /// Handle adaptive card submit in 1:1 chat. /// Submits the question or feedback to the SME team. /// </summary> /// <param name="message">A message in a conversation.</param> /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param> /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param> /// <returns>A task that represents the work queued to execute.</returns> private async Task OnAdaptiveCardSubmitInPersonalChatAsync( IMessageActivity message, ITurnContext <IMessageActivity> turnContext, CancellationToken cancellationToken) { Attachment smeTeamCard = null; // Notification to SME team Attachment userCard = null; // Acknowledgement to the user TicketEntity newTicket = null; // New ticket switch (message?.Text) { case Constants.AskAnExpert: this.logger.LogInformation("Sending user ask an expert card (from answer)"); var askAnExpertPayload = ((JObject)message.Value).ToObject <ResponseCardPayload>(); await turnContext.SendActivityAsync(MessageFactory.Attachment(AskAnExpertCard.GetCard(askAnExpertPayload))).ConfigureAwait(false); break; case Constants.ShareFeedback: this.logger.LogInformation("Sending user share feedback card (from answer)"); var shareFeedbackPayload = ((JObject)message.Value).ToObject <ResponseCardPayload>(); await turnContext.SendActivityAsync(MessageFactory.Attachment(ShareFeedbackCard.GetCard(shareFeedbackPayload))).ConfigureAwait(false); break; case AskAnExpertCard.AskAnExpertSubmitText: this.logger.LogInformation("Received question for expert"); newTicket = await AdaptiveCardHelper.AskAnExpertSubmitText(message, turnContext, cancellationToken, this.ticketsProvider).ConfigureAwait(false); if (newTicket != null) { smeTeamCard = new SmeTicketCard(newTicket).ToAttachment(message?.LocalTimestamp); userCard = new UserNotificationCard(newTicket).ToAttachment(Strings.NotificationCardContent, message?.LocalTimestamp); } break; case ShareFeedbackCard.ShareFeedbackSubmitText: this.logger.LogInformation("Received app feedback"); smeTeamCard = await AdaptiveCardHelper.ShareFeedbackSubmitText(message, turnContext, cancellationToken).ConfigureAwait(false); if (smeTeamCard != null) { await turnContext.SendActivityAsync(MessageFactory.Text(Strings.ThankYouTextContent)).ConfigureAwait(false); } break; default: var payload = ((JObject)message.Value).ToObject <ResponseCardPayload>(); if (payload.IsPrompt) { this.logger.LogInformation("Sending input to QnAMaker for prompt"); await this.GetQuestionAnswerReplyAsync(turnContext, message).ConfigureAwait(false); } else { this.logger.LogWarning($"Unexpected text in submit payload: {message.Text}"); } break; } string expertTeamId = await this.configurationProvider.GetSavedEntityDetailAsync(ConfigurationEntityTypes.TeamId).ConfigureAwait(false); // Send message to SME team. if (smeTeamCard != null) { var resourceResponse = await this.SendCardToTeamAsync(turnContext, smeTeamCard, expertTeamId, cancellationToken).ConfigureAwait(false); // If a ticket was created, update the ticket with the conversation info. if (newTicket != null) { newTicket.SmeCardActivityId = resourceResponse.ActivityId; newTicket.SmeThreadConversationId = resourceResponse.Id; await this.ticketsProvider.UpsertTicketAsync(newTicket).ConfigureAwait(false); } } // Send acknowledgment to the user if (userCard != null) { await turnContext.SendActivityAsync(MessageFactory.Attachment(userCard), cancellationToken).ConfigureAwait(false); } }