/// <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);
            }
        }
Example #7
0
        /// <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);
            }
        }